Kotlin
Kotlin完全ガイド — モダンなJVM言語の全容
はじめに
Kotlin(コトリン)は、JetBrains社が2011年に開発を開始し、2016年にバージョン1.0がリリースされたモダンなプログラミング言語である。2017年にGoogleがAndroidの公式開発言語として採用し、2019年にはAndroid開発の推奨言語(Kotlin-first)となった。
Kotlinは「実用的、簡潔、安全、そしてJavaとの100%相互運用可能」を設計哲学としている。JVM上で動作するだけでなく、JavaScript(Kotlin/JS)やネイティブコード(Kotlin/Native)にもコンパイル可能なマルチプラットフォーム言語である。
本記事では、Kotlinの基本構文、型システム、オブジェクト指向、関数型プログラミング、コルーチン、DSL構築、マルチプラットフォーム開発、そしてサーバーサイド/Android開発の実践まで、Kotlinの全容を体系的に解説する。
第1章: Kotlinの基本
1.1 Kotlinの特徴
| 特徴 | 説明 |
|---|---|
| Null安全 | 型システムレベルでNullPointerExceptionを防止 |
| 簡潔な構文 | ボイラープレートコードの大幅削減 |
| Java相互運用 | 既存Javaコードとの100%互換性 |
| 関数型プログラミング | 高階関数、ラムダ式、イミュータブルコレクション |
| コルーチン | 軽量な非同期処理フレームワーク |
| 型推論 | 明示的な型宣言の省略が可能 |
| データクラス | POJO/DTOの自動生成 |
| 拡張関数 | 既存クラスへのメソッド追加(継承不要) |
| スマートキャスト | 型チェック後の自動キャスト |
| マルチプラットフォーム | JVM, JS, Native, Wasmへのコンパイル |
1.2 開発環境のセットアップ
# SDKMANによるインストール
$ sdk install kotlin
# Gradleプロジェクトの初期化
$ mkdir my-kotlin-project && cd my-kotlin-project
$ gradle init --type kotlin-application --dsl kotlin
# コマンドラインでのコンパイルと実行
$ kotlinc hello.kt -include-runtime -d hello.jar
$ java -jar hello.jar
# Kotlin REPL
$ kotlinc
>>> println("Hello, Kotlin!")
Hello, Kotlin!
# Kotlin Script
$ kotlinc -script hello.kts
// build.gradle.kts(Gradle Kotlin DSL)
plugins {
kotlin("jvm") version "2.0.0"
application
}
group = "com.example"
version = "1.0.0"
repositories {
mavenCentral()
}
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0")
testImplementation(kotlin("test"))
}
application {
mainClass.set("com.example.MainKt")
}
kotlin {
jvmToolchain(21)
}
1.3 基本構文
// エントリーポイント
fun main() {
println("Hello, Kotlin!")
}
// 引数付き
fun main(args: Array<String>) {
println("Arguments: ${args.joinToString()}")
}
// 変数宣言
val immutable: String = "変更不可" // val = 不変(推奨)
var mutable: String = "変更可能" // var = 可変
val inferred = "型推論" // 型推論 → String
// 基本型
val int: Int = 42
val long: Long = 42L
val double: Double = 3.14
val float: Float = 3.14f
val boolean: Boolean = true
val char: Char = 'K'
val string: String = "Kotlin"
// 文字列テンプレート
val name = "World"
println("Hello, $name!") // 変数参照
println("Length: ${name.length}") // 式の埋め込み
println("Name: ${if (name.isNotEmpty()) name else "Unknown"}")
// 複数行文字列
val json = """
{
"name": "$name",
"version": ${1 + 1}
}
""".trimIndent()
1.4 制御構造
// if式(式として値を返す)
val max = if (a > b) a else b
// when式(switchの強化版)
val result = when (status) {
200 -> "OK"
400 -> "Bad Request"
404 -> "Not Found"
in 500..599 -> "Server Error"
else -> "Unknown"
}
// whenの高度な使用法
when {
x.isNegative() -> println("Negative")
x == 0 -> println("Zero")
else -> println("Positive")
}
when (val response = executeRequest()) {
is Success -> println(response.data)
is Error -> println(response.message)
}
// forループ
for (i in 1..10) println(i) // 1〜10(10を含む)
for (i in 1 until 10) println(i) // 1〜9(10を含まない)
for (i in 10 downTo 1 step 2) println(i) // 10,8,6,4,2
for ((index, value) in list.withIndex()) println("$index: $value")
// whileループ
while (condition) { /* ... */ }
do { /* ... */ } while (condition)
1.5 関数
// 基本的な関数
fun add(a: Int, b: Int): Int {
return a + b
}
// 単一式関数
fun add(a: Int, b: Int): Int = a + b
fun add(a: Int, b: Int) = a + b // 戻り値型も推論
// デフォルト引数
fun greet(name: String, greeting: String = "Hello") = "$greeting, $name!"
greet("Kotlin") // "Hello, Kotlin!"
greet("Kotlin", "Hi") // "Hi, Kotlin!"
// 名前付き引数
fun createUser(name: String, age: Int, email: String) { /* ... */ }
createUser(name = "Alice", age = 30, email = "alice@example.com")
// 可変長引数
fun sum(vararg numbers: Int): Int = numbers.sum()
sum(1, 2, 3, 4, 5)
// ローカル関数
fun processData(data: List<String>) {
fun validate(item: String): Boolean = item.isNotBlank()
data.filter(::validate).forEach(::println)
}
// 中置関数
infix fun Int.times(str: String) = str.repeat(this)
val result = 3 times "Hello " // "Hello Hello Hello "
// 演算子オーバーロード
data class Point(val x: Int, val y: Int) {
operator fun plus(other: Point) = Point(x + other.x, y + other.y)
}
val p = Point(1, 2) + Point(3, 4) // Point(4, 6)
第2章: Null安全と型システム
2.1 Null安全
Kotlinの最も重要な機能の一つ。型システムでNullable型とNon-Null型を明確に区別する。
// Non-Null型(デフォルト)— nullを代入できない
var name: String = "Kotlin"
// name = null // コンパイルエラー
// Nullable型(?付き)— nullを許容
var nullableName: String? = "Kotlin"
nullableName = null // OK
// 安全呼び出し演算子(?.)
val length: Int? = nullableName?.length // nullならnullを返す
// エルビス演算子(?:)
val length: Int = nullableName?.length ?: 0 // nullなら0
val name: String = nullableName ?: throw IllegalStateException("Name is null")
// 非null表明演算子(!!)— NullPointerExceptionの可能性
val length: Int = nullableName!!.length // nullならNPE(使用は避ける)
// 安全キャスト
val str: String? = value as? String // キャスト失敗ならnull
// let — nullチェックとスコープ関数
nullableName?.let { name ->
println("Name: $name, Length: ${name.length}")
}
// Nullable型のコレクション操作
val list: List<String?> = listOf("a", null, "b", null, "c")
val nonNullList: List<String> = list.filterNotNull() // ["a", "b", "c"]
2.2 型システム
// 型階層
// Any (すべての非Null型のスーパータイプ)
// / | \
// / | \
// Int String ... (各型)
// \ | /
// \ | /
// Nothing (すべての型のサブタイプ — 値を持たない)
// Any? はNullable型を含むすべての型のスーパータイプ
// Nothing? はnullのみを持つ
// スマートキャスト
fun processValue(value: Any) {
if (value is String) {
// このブロック内ではvalueはString型として扱える
println(value.length) // 明示的キャスト不要
}
when (value) {
is Int -> println(value + 1)
is String -> println(value.uppercase())
is List<*> -> println(value.size)
}
}
// ジェネリクス
class Box<T>(val value: T)
val intBox = Box(42) // Box<Int>
val strBox = Box("Hello") // Box<String>
// 共変・反変
class Producer<out T>(val value: T) // out = 共変(Producer<Dog> → Producer<Animal>)
class Consumer<in T> { fun consume(item: T) {} } // in = 反変
// 型射影(Use-site variance)
fun copy(from: Array<out Any>, to: Array<Any>) {
for (i in from.indices) to[i] = from[i]
}
// スター射影
fun printAll(list: List<*>) {
list.forEach { println(it) }
}
// Reified型パラメータ(inline関数でのみ使用可能)
inline fun <reified T> isType(value: Any): Boolean = value is T
println(isType<String>("hello")) // true
println(isType<Int>("hello")) // false
// 型エイリアス
typealias UserMap = Map<String, List<User>>
typealias Predicate<T> = (T) -> Boolean
typealias Handler = (Request, Response) -> Unit
第3章: オブジェクト指向プログラミング
3.1 クラスとプロパティ
// 基本クラス
class Person(val name: String, var age: Int)
// プライマリコンストラクタとinit
class Person(val name: String, var age: Int) {
val isAdult: Boolean
init {
require(age >= 0) { "Age must be non-negative" }
isAdult = age >= 18
}
}
// セカンダリコンストラクタ
class Person(val name: String, var age: Int) {
constructor(name: String) : this(name, 0)
}
// プロパティのカスタムアクセサ
class Circle(val radius: Double) {
val area: Double
get() = Math.PI * radius * radius
var diameter: Double
get() = radius * 2
set(value) {
// radiusはvalなのでsetは定義不可(この例ではdiameterのみ)
println("Setting diameter to $value")
}
}
// レイトイニシャライゼーション
class Service {
lateinit var repository: Repository
fun isInitialized(): Boolean = ::repository.isInitialized
}
// 遅延初期化(by lazy)
class Config {
val databaseUrl: String by lazy {
println("Loading config...")
loadFromFile("config.properties")["db.url"]!!
}
}
// バッキングフィールド
class Counter {
var count: Int = 0
private set // setterをprivateに
fun increment() { count++ }
}
3.2 継承とインターフェース
// open修飾子が必要(デフォルトはfinal)
open class Animal(val name: String) {
open fun sound(): String = "..."
fun describe(): String = "$name says ${sound()}"
}
class Dog(name: String) : Animal(name) {
override fun sound(): String = "Woof!"
}
class Cat(name: String) : Animal(name) {
override fun sound(): String = "Meow!"
}
// 抽象クラス
abstract class Shape {
abstract fun area(): Double
fun describe() = "Shape with area ${area()}"
}
class Rectangle(val width: Double, val height: Double) : Shape() {
override fun area() = width * height
}
// インターフェース
interface Drawable {
fun draw()
fun describe(): String = "Drawable object" // デフォルト実装
}
interface Resizable {
fun resize(factor: Double)
}
class Circle(var radius: Double) : Shape(), Drawable, Resizable {
override fun area() = Math.PI * radius * radius
override fun draw() = println("Drawing circle with radius $radius")
override fun resize(factor: Double) { radius *= factor }
}
// sealed class(制限付き継承)
sealed class Result<out T> {
data class Success<T>(val data: T) : Result<T>()
data class Error(val message: String, val cause: Exception? = null) : Result<Nothing>()
data object Loading : Result<Nothing>()
}
fun handleResult(result: Result<String>) = when (result) {
is Result.Success -> println("Data: ${result.data}")
is Result.Error -> println("Error: ${result.message}")
is Result.Loading -> println("Loading...")
// else不要(sealedですべてのケースを網羅)
}
// sealed interface(Kotlin 1.5+)
sealed interface Shape {
data class Circle(val radius: Double) : Shape
data class Rectangle(val width: Double, val height: Double) : Shape
data class Triangle(val base: Double, val height: Double) : Shape
}
3.3 データクラスとその他の特殊クラス
// data class(equals, hashCode, toString, copy, componentNを自動生成)
data class User(
val id: Long,
val name: String,
val email: String,
val role: Role = Role.USER
)
val user = User(1, "Alice", "alice@example.com")
println(user) // User(id=1, name=Alice, email=alice@example.com, role=USER)
val admin = user.copy(role = Role.ADMIN) // 一部変更してコピー
val (id, name, email) = user // 分割代入(destructuring)
// enum class
enum class Role(val level: Int) {
USER(1), ADMIN(2), SUPER_ADMIN(3);
fun hasPermission(requiredLevel: Int): Boolean = level >= requiredLevel
}
// value class(インライン化される軽量ラッパー)
@JvmInline
value class UserId(val value: Long)
@JvmInline
value class Email(val value: String) {
init { require(value.contains("@")) { "Invalid email" } }
}
fun findUser(id: UserId): User? { /* ... */ }
findUser(UserId(42)) // 型安全、ランタイムオーバーヘッドなし
// object(シングルトン)
object Database {
private val connection = createConnection()
fun query(sql: String): ResultSet = connection.createStatement().executeQuery(sql)
}
Database.query("SELECT * FROM users")
// companion object(クラスのスタティックメンバー相当)
class User private constructor(val name: String) {
companion object Factory {
fun create(name: String): User = User(name.trim())
fun fromJson(json: String): User { /* ... */ }
}
}
val user = User.create("Alice")
第4章: 関数型プログラミング
4.1 高階関数とラムダ
// 高階関数(関数を引数に取る関数)
fun <T> List<T>.customFilter(predicate: (T) -> Boolean): List<T> {
val result = mutableListOf<T>()
for (item in this) {
if (predicate(item)) result.add(item)
}
return result
}
val numbers = listOf(1, 2, 3, 4, 5)
val evens = numbers.customFilter { it % 2 == 0 } // [2, 4]
// ラムダ式
val square: (Int) -> Int = { x -> x * x }
val double: (Int) -> Int = { it * 2 } // 引数が1つならitで参照
// 関数参照
fun isEven(n: Int): Boolean = n % 2 == 0
val evens = numbers.filter(::isEven)
// メソッド参照
val lengths = listOf("a", "bb", "ccc").map(String::length)
// 関数を返す関数
fun multiplier(factor: Int): (Int) -> Int = { it * factor }
val triple = multiplier(3)
println(triple(5)) // 15
// クロージャ
fun counter(): () -> Int {
var count = 0
return { ++count }
}
val next = counter()
println(next()) // 1
println(next()) // 2
4.2 コレクション操作
val users = listOf(
User(1, "Alice", 30), User(2, "Bob", 25),
User(3, "Charlie", 35), User(4, "Diana", 28)
)
// フィルタリング
val adults = users.filter { it.age >= 30 }
val firstAdmin = users.firstOrNull { it.role == Role.ADMIN }
// マッピング
val names = users.map { it.name }
val nameWithAge = users.map { "${it.name} (${it.age})" }
val flatList = listOf(listOf(1, 2), listOf(3, 4)).flatMap { it } // [1,2,3,4]
// ソート
val sorted = users.sortedBy { it.age }
val sortedDesc = users.sortedByDescending { it.name }
// グループ化
val byAge = users.groupBy { if (it.age >= 30) "senior" else "junior" }
val byRole = users.groupBy { it.role }
// 集約
val totalAge = users.sumOf { it.age }
val avgAge = users.map { it.age }.average()
val oldest = users.maxByOrNull { it.age }
val nameList = users.joinToString(", ") { it.name }
// fold / reduce
val sum = numbers.fold(0) { acc, n -> acc + n }
val product = numbers.reduce { acc, n -> acc * n }
// チェーン操作
val result = users
.filter { it.age >= 25 }
.sortedBy { it.name }
.take(3)
.map { "${it.name}: ${it.age}" }
.joinToString("\n")
// シーケンス(遅延評価)
val result = users.asSequence()
.filter { it.age >= 25 }
.map { it.name.uppercase() }
.take(2)
.toList()
// マップ操作
val map = mapOf("a" to 1, "b" to 2, "c" to 3)
val filtered = map.filter { (_, value) -> value > 1 }
val mapped = map.mapValues { (_, value) -> value * 10 }
4.3 スコープ関数
// let — nullチェック、変換、スコープ限定
val result = nullableValue?.let { value ->
process(value)
}
// run — オブジェクトの初期化と計算
val result = service.run {
port = 8080
host = "localhost"
start()
"Service started on $host:$port"
}
// with — オブジェクトのプロパティアクセス
val info = with(user) {
"Name: $name, Age: $age, Email: $email"
}
// apply — オブジェクトの設定(オブジェクト自身を返す)
val user = User().apply {
name = "Alice"
age = 30
email = "alice@example.com"
}
// also — 副作用(デバッグ、ロギング)
val numbers = mutableListOf(1, 2, 3)
.also { println("Before: $it") }
.apply { add(4) }
.also { println("After: $it") }
// 使い分けガイド:
// let → Nullable処理、変換 it参照、ラムダの結果を返す
// run → オブジェクト初期化+計算 this参照、ラムダの結果を返す
// with → 既存オブジェクトのプロパティ一括アクセス this参照、ラムダの結果を返す
// apply → オブジェクト設定 this参照、オブジェクト自身を返す
// also → 副作用(ログ等) it参照、オブジェクト自身を返す
第5章: コルーチン — Kotlinの非同期プログラミング
5.1 コルーチンの基本
import kotlinx.coroutines.*
// 基本的なコルーチン起動
fun main() = runBlocking {
launch {
delay(1000L)
println("World!")
}
println("Hello,")
}
// 出力: Hello, (1秒後) World!
// async/await パターン
fun main() = runBlocking {
val deferred1 = async { fetchUserFromApi(1) }
val deferred2 = async { fetchUserFromApi(2) }
val user1 = deferred1.await()
val user2 = deferred2.await()
println("Users: $user1, $user2")
}
// 構造化された並行性
fun main() = runBlocking {
coroutineScope {
launch { task1() }
launch { task2() }
}
println("Both tasks completed")
}
5.2 コルーチンビルダー
// launch — Fire-and-forget(Jobを返す)
val job: Job = scope.launch {
// 非同期処理
}
job.join() // 完了を待つ
job.cancel() // キャンセル
// async — 結果を返す非同期処理(Deferredを返す)
val deferred: Deferred<User> = scope.async {
fetchUser(userId)
}
val user: User = deferred.await()
// withContext — コンテキスト切り替え
suspend fun fetchData(): Data = withContext(Dispatchers.IO) {
// IOスレッドで実行
api.getData()
}
// coroutineScope — 構造化された並行性
suspend fun loadDashboard(): Dashboard = coroutineScope {
val user = async { fetchUser() }
val orders = async { fetchOrders() }
val recommendations = async { fetchRecommendations() }
Dashboard(user.await(), orders.await(), recommendations.await())
}
5.3 ディスパッチャー
// Dispatchers.Main — メインスレッド(UI更新用)
// Dispatchers.IO — I/O操作(ネットワーク、ディスク)
// Dispatchers.Default — CPU集約的な処理
// Dispatchers.Unconfined — 制限なし(テスト用)
launch(Dispatchers.IO) {
val data = fetchFromNetwork() // IOスレッドで実行
withContext(Dispatchers.Main) {
updateUI(data) // メインスレッドで実行
}
}
// カスタムディスパッチャー
val customDispatcher = Executors.newFixedThreadPool(4).asCoroutineDispatcher()
5.4 Flow — リアクティブストリーム
import kotlinx.coroutines.flow.*
// 基本的なFlow
fun numberFlow(): Flow<Int> = flow {
for (i in 1..5) {
delay(100)
emit(i)
}
}
fun main() = runBlocking {
numberFlow()
.filter { it % 2 == 0 }
.map { it * it }
.collect { println(it) }
// 出力: 4, 16
}
// Flow演算子
val result = flow
.filter { it.isValid() }
.map { transform(it) }
.onEach { log(it) }
.catch { e -> emit(defaultValue) }
.flowOn(Dispatchers.IO)
.stateIn(scope, SharingStarted.WhileSubscribed(5000), initialValue)
// StateFlow(状態の保持)
class ViewModel {
private val _uiState = MutableStateFlow(UiState.Loading)
val uiState: StateFlow<UiState> = _uiState.asStateFlow()
fun loadData() {
viewModelScope.launch {
_uiState.value = UiState.Loading
try {
val data = repository.fetchData()
_uiState.value = UiState.Success(data)
} catch (e: Exception) {
_uiState.value = UiState.Error(e.message)
}
}
}
}
// SharedFlow(イベントのブロードキャスト)
class EventBus {
private val _events = MutableSharedFlow<Event>(replay = 0)
val events: SharedFlow<Event> = _events.asSharedFlow()
suspend fun emit(event: Event) = _events.emit(event)
}
// channelFlow — 並行的なFlow生成
fun mergedFlow(): Flow<Data> = channelFlow {
launch { source1.collect { send(it) } }
launch { source2.collect { send(it) } }
}
5.5 エラーハンドリングとキャンセル
// 例外処理
val handler = CoroutineExceptionHandler { _, exception ->
println("Caught: ${exception.message}")
}
val job = scope.launch(handler) {
throw RuntimeException("Something went wrong")
}
// supervisorScope — 子コルーチンの失敗を独立化
supervisorScope {
val job1 = launch { task1() } // 失敗してもjob2に影響しない
val job2 = launch { task2() }
}
// キャンセル
val job = launch {
repeat(1000) { i ->
ensureActive() // キャンセルチェック(またはyield())
println("Processing $i")
delay(100) // delay()はキャンセルに対応
}
}
delay(500)
job.cancelAndJoin()
// withTimeout
val result = withTimeoutOrNull(3000L) {
fetchData()
} ?: defaultValue
第6章: 拡張関数とDSL
6.1 拡張関数
// String拡張
fun String.toSlug(): String = this
.lowercase()
.replace(Regex("[^a-z0-9\\s-]"), "")
.replace(Regex("\\s+"), "-")
.trim('-')
"Hello World!".toSlug() // "hello-world"
// コレクション拡張
fun <T> List<T>.second(): T = this[1]
fun <T> List<T>.secondOrNull(): T? = this.getOrNull(1)
// 拡張プロパティ
val String.wordCount: Int
get() = this.split(Regex("\\s+")).size
"Hello World Kotlin".wordCount // 3
// Nullable型の拡張
fun String?.orEmpty(): String = this ?: ""
fun <T> T?.orDefault(default: T): T = this ?: default
6.2 DSL構築
// HTML DSL
class HTML {
private val elements = mutableListOf<String>()
fun head(init: Head.() -> Unit) { /* ... */ }
fun body(init: Body.() -> Unit) { /* ... */ }
override fun toString() = elements.joinToString("\n")
}
fun html(init: HTML.() -> Unit): HTML = HTML().apply(init)
val page = html {
head { title("My Page") }
body {
h1("Welcome")
p("This is Kotlin DSL")
ul {
li("Item 1")
li("Item 2")
}
}
}
// Ktor ルーティングDSL(実際のフレームワーク例)
fun Application.configureRouting() {
routing {
get("/") { call.respondText("Hello, World!") }
route("/api/v1") {
get("/users") { /* ... */ }
post("/users") { /* ... */ }
route("/users/{id}") {
get { /* ... */ }
put { /* ... */ }
delete { /* ... */ }
}
}
}
}
// Gradle Kotlin DSL
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0")
implementation("io.ktor:ktor-server-core:2.3.0")
testImplementation(kotlin("test"))
}
// テストDSL
class UserTest {
@Test
fun `should create user with valid data`() {
val user = user {
name = "Alice"
age = 30
email = "alice@example.com"
}
user shouldBe User("Alice", 30, "alice@example.com")
user.name shouldStartWith "A"
user.age shouldBeGreaterThan 18
}
}
第7章: サーバーサイドKotlin
7.1 Ktor(JetBrains製Webフレームワーク)
// Application.kt
fun main() {
embeddedServer(Netty, port = 8080) {
configureSerialization()
configureRouting()
configureAuthentication()
}.start(wait = true)
}
fun Application.configureSerialization() {
install(ContentNegotiation) {
json(Json { prettyPrint = true; isLenient = true })
}
}
fun Application.configureRouting() {
routing {
route("/api/users") {
get {
val users = userService.findAll()
call.respond(users)
}
get("/{id}") {
val id = call.parameters["id"]?.toLongOrNull()
?: return@get call.respond(HttpStatusCode.BadRequest, "Invalid ID")
val user = userService.findById(id)
?: return@get call.respond(HttpStatusCode.NotFound)
call.respond(user)
}
post {
val request = call.receive<CreateUserRequest>()
val user = userService.create(request)
call.respond(HttpStatusCode.Created, user)
}
}
}
}
7.2 Spring Boot with Kotlin
@SpringBootApplication
class Application
fun main(args: Array<String>) {
runApplication<Application>(*args)
}
@RestController
@RequestMapping("/api/users")
class UserController(private val userService: UserService) {
@GetMapping
suspend fun findAll(): List<User> = userService.findAll()
@GetMapping("/{id}")
suspend fun findById(@PathVariable id: Long): ResponseEntity<User> =
userService.findById(id)
?.let { ResponseEntity.ok(it) }
?: ResponseEntity.notFound().build()
@PostMapping
suspend fun create(@RequestBody @Valid request: CreateUserRequest): ResponseEntity<User> {
val user = userService.create(request)
return ResponseEntity.status(HttpStatus.CREATED).body(user)
}
}
@Service
class UserService(private val userRepository: UserRepository) {
suspend fun findAll(): List<User> = userRepository.findAll().toList()
suspend fun findById(id: Long): User? = userRepository.findById(id)
suspend fun create(request: CreateUserRequest): User =
userRepository.save(request.toEntity())
}
第8章: Kotlin Multiplatformとまとめ
8.1 Kotlin Multiplatform(KMP)
// 共通コード(commonMain)
expect fun platformName(): String
class Greeting {
fun greet(): String = "Hello from ${platformName()}!"
}
// Android実装(androidMain)
actual fun platformName(): String = "Android ${Build.VERSION.SDK_INT}"
// iOS実装(iosMain)
actual fun platformName(): String = UIDevice.currentDevice.systemName()
// JVM実装(jvmMain)
actual fun platformName(): String = "JVM ${System.getProperty("java.version")}"
// build.gradle.kts(KMPプロジェクト)
kotlin {
androidTarget()
iosX64()
iosArm64()
iosSimulatorArm64()
jvm()
sourceSets {
commonMain.dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0")
implementation("io.ktor:ktor-client-core:2.3.0")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")
}
androidMain.dependencies {
implementation("io.ktor:ktor-client-okhttp:2.3.0")
}
iosMain.dependencies {
implementation("io.ktor:ktor-client-darwin:2.3.0")
}
}
}
まとめ
Kotlinは、モダンなプログラミング言語として以下の強力な機能を提供する:
- Null安全: 型システムでNPEを防止、
?.,?:,let - 簡潔な構文: データクラス、型推論、文字列テンプレート、デフォルト引数
- OOP: sealed class、value class、companion object、委譲パターン
- 関数型: 高階関数、ラムダ、コレクション操作、シーケンス
- コルーチン: 構造化された並行性、Flow、StateFlow/SharedFlow
- DSL構築: 拡張関数、レシーバー付きラムダ、型安全なビルダー
- サーバーサイド: Ktor、Spring Boot、Exposed
- マルチプラットフォーム: KMP、Compose Multiplatform
参考文献
- Kotlin公式ドキュメント: https://kotlinlang.org/docs/
- Kotlin Playground: https://play.kotlinlang.org/
- Kotlin Koans(練習問題): https://play.kotlinlang.org/koans/
- "Kotlin in Action" - Dmitry Jemerov, Svetlana Isakova
- "Kotlin Coroutines: Deep Dive" - Marcin Moskała
- "Atomic Kotlin" - Bruce Eckel, Svetlana Isakova
- Ktor: https://ktor.io/
- Spring Boot with Kotlin: https://spring.io/guides/tutorials/spring-boot-kotlin