← Kotlin言語のページに戻る
🟣

Kotlin言語のサンプルコード

文法解説で学んだ内容を組み合わせた、実践的なサンプルプログラムを3本紹介します。難易度は徐々に上がっていきます。

サンプル①:data classとコレクション操作による成績管理

data classで生徒データを表現し、filtermapsortedByDescendingaverageなどのコレクション操作を組み合わせて、成績の集計・並び替え・合否判定を行うプログラムです。

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待ちを伴う処理を効率よく捌けるのが利点です。

理解度チェッククイズに挑戦する →