🟣
Kotlin言語のサンプルコード
文法解説で学んだ内容を組み合わせた、実践的なサンプルプログラムを3本紹介します。難易度は徐々に上がっていきます。
サンプル①:data classとコレクション操作による成績管理
data classで生徒データを表現し、filter・map・sortedByDescending・averageなどのコレクション操作を組み合わせて、成績の集計・並び替え・合否判定を行うプログラムです。
SAMPLE PROGRAM
data class Student(val name: String, val score: Int)
fun main() {
val students = listOf(
Student("佐藤", 82),
Student("鈴木", 45),
Student("高橋", 91),
Student("田中", 58),
Student("伊藤", 73)
)
// 合格者(60点以上)だけを抽出
val passed = students.filter { it.score >= 60 }
println("合格者: ${passed.map { it.name }}")
// 平均点を計算
val average = students.map { it.score }.average()
println("平均点: %.1f".format(average))
// 得点の高い順に並び替えて上位3名を表示
val top3 = students.sortedByDescending { it.score }.take(3)
println("上位3名:")
top3.forEachIndexed { index, student ->
println(" ${index + 1}位: ${student.name}(${student.score}点)")
}
// 一部の得点を更新したコピーを作る(data classのcopy)
val updated = students[1].copy(score = 65)
println("再テスト後: $updated")
}
実行結果として、合格者一覧・平均点・順位付き上位3名・copy()を使った得点更新後のデータが表示されます。data classのおかげでtoString()が自動生成され、そのままprintlnで内容を確認できる点がポイントです。
サンプル②:探索・整列アルゴリズムの実装と計算量比較
文法解説で紹介した線形探索(O(n))・二分探索(O(log n))・クイックソート(平均O(n log n))を実際に動かし、比較回数を数えることで計算量の違いを体感するプログラムです。
SAMPLE PROGRAM
// 比較回数をカウントする線形探索(計算量 O(n))
fun linearSearchCounting(list: List, target: Int): Pair {
var comparisons = 0
for (i in list.indices) {
comparisons++
if (list[i] == target) return Pair(i, comparisons)
}
return Pair(-1, comparisons)
}
// 比較回数をカウントする二分探索(計算量 O(log n))
fun binarySearchCounting(sorted: List, target: Int): Pair {
var comparisons = 0
var low = 0
var high = sorted.size - 1
while (low <= high) {
comparisons++
val mid = (low + high) / 2
when {
sorted[mid] == target -> return Pair(mid, comparisons)
sorted[mid] < target -> low = mid + 1
else -> high = mid - 1
}
}
return Pair(-1, comparisons)
}
// クイックソート(平均計算量 O(n log n))
fun quickSort(list: List): List {
if (list.size <= 1) return list
val pivot = list[list.size / 2]
val less = list.filter { it < pivot }
val equal = list.filter { it == pivot }
val greater = list.filter { it > pivot }
return quickSort(less) + equal + quickSort(greater)
}
fun main() {
val raw = listOf(23, 4, 67, 15, 89, 2, 45, 31, 9, 78, 12, 56)
val sorted = quickSort(raw)
println("ソート後: $sorted")
val target = 78
val (indexLinear, countLinear) = linearSearchCounting(sorted, target)
val (indexBinary, countBinary) = binarySearchCounting(sorted, target)
println("線形探索: index=$indexLinear, 比較回数=$countLinear")
println("二分探索: index=$indexBinary, 比較回数=$countBinary")
// データ件数が増えるほど、二分探索の比較回数の少なさが際立つ
}
要素数が少ないうちは差が見えにくいですが、リストの要素数を増やすほど二分探索の比較回数がO(log n)に沿って緩やかにしか増えないのに対し、線形探索はO(n)で比例して増えていくことが確認できます。
サンプル③:コルーチンを使った非同期処理
複数のAPIリクエストを模した処理を、コルーチンのasync / awaitで並行実行する例です。順番に実行(直列)した場合と、並行実行した場合の所要時間を比較しています。
SAMPLE PROGRAM
import kotlinx.coroutines.*
import kotlin.system.measureTimeMillis
suspend fun fetchUserProfile(): String {
delay(800) // ネットワーク通信を想定した遅延
return "プロフィール取得完了"
}
suspend fun fetchUserOrders(): String {
delay(1000)
return "注文履歴取得完了"
}
suspend fun fetchUserRecommendations(): String {
delay(600)
return "おすすめ商品取得完了"
}
fun main() = runBlocking {
// 直列実行:各処理を順番に待つため合計時間がかかる
val sequentialTime = measureTimeMillis {
val profile = fetchUserProfile()
val orders = fetchUserOrders()
val recommendations = fetchUserRecommendations()
println("$profile / $orders / $recommendations")
}
println("直列実行の所要時間: ${sequentialTime}ms")
// 並行実行:asyncで同時に開始し、それぞれのawait()で結果を待つ
val concurrentTime = measureTimeMillis {
val profileDeferred = async { fetchUserProfile() }
val ordersDeferred = async { fetchUserOrders() }
val recommendationsDeferred = async { fetchUserRecommendations() }
println("${profileDeferred.await()} / ${ordersDeferred.await()} / ${recommendationsDeferred.await()}")
}
println("並行実行の所要時間: ${concurrentTime}ms")
// 並行実行は最も時間のかかる処理(1000ms)程度で完了し、直列実行より大幅に速い
}
直列実行では3つの処理時間の合計(約2400ms)がかかるのに対し、並行実行では最も遅い処理(約1000ms)にほぼ収束します。コルーチンはスレッドより軽量なため、多数のI/O待ちを伴う処理を効率よく捌けるのが利点です。