Kotlin
#14
TIOBE#23
PYPL#13
GitHub#19
RedMonk#14
IEEESpectrum#17
JetBrains#13
プログラミング言語
Kotlin
概要
Kotlinは、JetBrainsが開発したJVM上で動作するプログラミング言語です。
詳細
Kotlinは2011年にJetBrainsによって開発が開始され、2016年に正式リリースされたプログラミング言語です。Java仮想マシン(JVM)上で動作し、Javaとの100%相互運用性を持ちながら、より簡潔で安全なコードを書くことができます。Null安全性、型推論、拡張関数、データクラスなどの現代的な機能を提供しています。2017年にGoogleがAndroidの公式開発言語として採用し、現在は「Kotlin First」として推奨されています。サーバーサイド開発、Web開発、ネイティブアプリ開発など、幅広い分野で活用されています。
書き方の例
Hello World
// 基本的な出力
fun main() {
println("Hello, World!")
// 変数を使った出力
val message = "こんにちは、Kotlin!"
println(message)
// 文字列テンプレートを使った出力
val name = "太郎"
val age = 25
println("私の名前は${name}で、${age}歳です。")
}
// 従来の関数形式
fun main(args: Array<String>) {
println("Hello from main function!")
}
変数と型
fun main() {
// 読み取り専用変数(val)
val name = "太郎" // 型推論
val age: Int = 25 // 明示的な型指定
// 可変変数(var)
var score = 85
score = 90 // 変更可能
// 基本型
val height: Double = 175.5
val isActive: Boolean = true
val character: Char = 'K'
// Null許容型
val nullableName: String? = null
val nonNullName: String = "田中"
// 安全呼び出し演算子
val length = nullableName?.length
println("Null許容文字列の長さ: $length")
// エルビス演算子
val displayName = nullableName ?: "名前なし"
println("表示名: $displayName")
// 非Null表明演算子(!!)
val definitelyNotNull = nonNullName!!
println("確実に非Null: $definitelyNotNull")
// 文字列テンプレート
println("名前: $name, 年齢: $age, 身長: ${height}cm")
println("アクティブ: ${if (isActive) "はい" else "いいえ"}")
}
関数
// 基本的な関数
fun add(a: Int, b: Int): Int {
return a + b
}
// 式関数
fun multiply(a: Int, b: Int) = a * b
// デフォルト引数
fun greet(name: String, prefix: String = "さん") = "こんにちは、$name$prefix"
// 名前付き引数
fun createUser(name: String, age: Int, email: String = "") {
println("ユーザー作成: $name ($age歳) - $email")
}
// 可変長引数
fun sum(vararg numbers: Int): Int {
return numbers.sum()
}
// 高階関数
fun calculate(a: Int, b: Int, operation: (Int, Int) -> Int): Int {
return operation(a, b)
}
// 拡張関数
fun String.isValidEmail(): Boolean {
return this.contains("@") && this.contains(".")
}
fun main() {
// 関数の呼び出し
println("5 + 3 = ${add(5, 3)}")
println("4 × 6 = ${multiply(4, 6)}")
// デフォルト引数
println(greet("田中"))
println(greet("山田", "様"))
// 名前付き引数
createUser(name = "佐藤", age = 30, email = "[email protected]")
createUser(age = 25, name = "高橋") // 順序を変更可能
// 可変長引数
println("合計: ${sum(1, 2, 3, 4, 5)}")
// 高階関数
val result = calculate(10, 5) { x, y -> x - y }
println("10 - 5 = $result")
// ラムダ式
val numbers = listOf(1, 2, 3, 4, 5)
val doubled = numbers.map { it * 2 }
println("倍数: $doubled")
// 拡張関数
val email = "[email protected]"
println("$email は有効なメール: ${email.isValidEmail()}")
}
クラスとオブジェクト
// 基本的なクラス
class Person(val name: String, var age: Int) {
// プロパティ
val id: String = generateId()
// メソッド
fun getInfo(): String = "$name ($age歳) - ID: $id"
// セカンダリコンストラクタ
constructor(name: String) : this(name, 0)
private fun generateId(): String = "ID_${name.hashCode()}"
}
// データクラス
data class User(
val id: Int,
val name: String,
val email: String
)
// シールドクラス
sealed class Result {
data class Success(val data: String) : Result()
data class Error(val message: String) : Result()
object Loading : Result()
}
// インターフェース
interface Drawable {
fun draw()
// デフォルト実装
fun info() = "これは描画可能なオブジェクトです"
}
// 継承
abstract class Shape : Drawable {
abstract val area: Double
override fun info() = "これは図形です: 面積 = $area"
}
class Circle(private val radius: Double) : Shape() {
override val area: Double
get() = Math.PI * radius * radius
override fun draw() {
println("半径 $radius の円を描画します")
}
}
// オブジェクト宣言(シングルトン)
object DatabaseManager {
fun connect(): String = "データベースに接続しました"
fun disconnect(): String = "データベースから切断しました"
}
fun main() {
// クラスのインスタンス化
val person1 = Person("田中太郎", 25)
val person2 = Person("山田花子")
println(person1.getInfo())
println(person2.getInfo())
// データクラス
val user = User(1, "佐藤", "[email protected]")
println("ユーザー: $user")
// データクラスのコピー
val updatedUser = user.copy(email = "[email protected]")
println("更新されたユーザー: $updatedUser")
// 分解宣言
val (id, name, email) = user
println("ID: $id, 名前: $name, メール: $email")
// シールドクラス
val results = listOf(
Result.Success("データを取得しました"),
Result.Error("ネットワークエラー"),
Result.Loading
)
results.forEach { result ->
when (result) {
is Result.Success -> println("成功: ${result.data}")
is Result.Error -> println("エラー: ${result.message}")
is Result.Loading -> println("読み込み中...")
}
}
// 継承とポリモーフィズム
val circle = Circle(5.0)
circle.draw()
println(circle.info())
// オブジェクト宣言
println(DatabaseManager.connect())
println(DatabaseManager.disconnect())
}
コレクションと関数型プログラミング
fun main() {
// リスト
val numbers = listOf(1, 2, 3, 4, 5)
val mutableNumbers = mutableListOf(1, 2, 3)
mutableNumbers.add(4)
// セット
val uniqueNumbers = setOf(1, 2, 2, 3, 3)
println("ユニークな数値: $uniqueNumbers")
// マップ
val ages = mapOf("田中" to 25, "山田" to 30, "佐藤" to 28)
val mutableAges = mutableMapOf<String, Int>()
mutableAges["高橋"] = 35
// 関数型メソッド
val evenNumbers = numbers.filter { it % 2 == 0 }
println("偶数: $evenNumbers")
val doubled = numbers.map { it * 2 }
println("倍数: $doubled")
val sum = numbers.reduce { acc, n -> acc + n }
println("合計: $sum")
val sumWithInitial = numbers.fold(10) { acc, n -> acc + n }
println("初期値付き合計: $sumWithInitial")
// グループ化
val words = listOf("apple", "banana", "apricot", "cherry", "avocado")
val groupedByFirstLetter = words.groupBy { it.first() }
println("最初の文字でグループ化: $groupedByFirstLetter")
// チェーンメソッド
val result = words
.filter { it.startsWith("a") }
.map { it.uppercase() }
.sorted()
println("処理結果: $result")
// シーケンス(遅延評価)
val largeNumbers = generateSequence(1) { it + 1 }
.filter { it % 2 == 0 }
.take(5)
.toList()
println("シーケンス結果: $largeNumbers")
}
スコープ関数
data class Person(var name: String, var age: Int)
fun main() {
// let - オブジェクトの変換とNull安全性
val person: Person? = Person("田中", 25)
person?.let {
println("${it.name} は ${it.age} 歳です")
}
val length = "Hello, Kotlin"?.let {
println("文字列: $it")
it.length // 戻り値
}
println("文字列の長さ: $length")
// run - オブジェクトの設定と結果の計算
val message = Person("山田", 30).run {
age += 1
"来年 $name は $age 歳になります"
}
println(message)
// with - オブジェクトのメソッドを連続呼び出し
val numbers = mutableListOf<Int>()
with(numbers) {
add(1)
add(2)
add(3)
println("リスト: $this")
}
// apply - オブジェクトの設定
val person2 = Person("", 0).apply {
name = "佐藤"
age = 28
}
println("設定後: $person2")
// also - 追加の処理
val person3 = Person("高橋", 35).also {
println("作成されたperson: ${it.name}")
}
// takeIf/takeUnless - 条件付き処理
val adult = person3.takeIf { it.age >= 18 }
println("成人: $adult")
val notTeenager = person3.takeUnless { it.age in 13..19 }
println("ティーンエイジャーではない: $notTeenager")
}
例外処理
// カスタム例外クラス
class ValidationException(message: String) : Exception(message)
fun validateAge(age: Int) {
if (age < 0) {
throw ValidationException("年齢は0以上である必要があります")
}
if (age > 150) {
throw ValidationException("年齢は150以下である必要があります")
}
}
fun divide(a: Int, b: Int): Double {
if (b == 0) {
throw ArithmeticException("ゼロで除算はできません")
}
return a.toDouble() / b
}
fun main() {
// try-catch文
try {
val result = divide(10, 2)
println("10 ÷ 2 = $result")
} catch (e: ArithmeticException) {
println("算術エラー: ${e.message}")
}
// 複数の例外をキャッチ
try {
validateAge(-5)
} catch (e: ValidationException) {
println("検証エラー: ${e.message}")
} catch (e: Exception) {
println("予期しないエラー: ${e.message}")
} finally {
println("cleanup処理")
}
// try式(値を返す)
val safeDivision = try {
divide(10, 0)
} catch (e: ArithmeticException) {
0.0 // デフォルト値
}
println("安全な除算結果: $safeDivision")
// runCatching(関数型アプローチ)
val result = runCatching {
divide(15, 3)
}
result
.onSuccess { println("成功: $it") }
.onFailure { println("失敗: ${it.message}") }
// getOrElse
val safeResult = runCatching { divide(10, 0) }
.getOrElse { -1.0 }
println("デフォルト値付き結果: $safeResult")
// fold
val foldResult = runCatching { validateAge(25) }
.fold(
onSuccess = { "年齢検証成功" },
onFailure = { "年齢検証失敗: ${it.message}" }
)
println(foldResult)
}
Coroutines(協調的並行処理)
import kotlinx.coroutines.*
// suspend関数
suspend fun fetchUserData(userId: Int): String {
delay(1000) // 非同期待機(1秒)
return "ユーザー$userId のデータ"
}
suspend fun fetchUserPosts(userId: Int): List<String> {
delay(800) // 非同期待機(0.8秒)
return listOf("投稿1", "投稿2", "投稿3")
}
fun main() = runBlocking {
println("=== 基本的なCoroutine ===")
// 基本的なlaunch
val job = launch {
repeat(3) {
println("Coroutine実行中: $it")
delay(500)
}
}
delay(1000)
job.cancel()
println("Jobをキャンセルしました")
println("\n=== async/await ===")
// async/awaitによる並行処理
val userData = async { fetchUserData(1) }
val userPosts = async { fetchUserPosts(1) }
println("ユーザーデータ: ${userData.await()}")
println("ユーザー投稿: ${userPosts.await()}")
println("\n=== エラーハンドリング ===")
// エラーハンドリング
try {
val errorJob = async {
delay(100)
throw Exception("何かがうまくいかなかった")
}
errorJob.await()
} catch (e: Exception) {
println("エラーをキャッチ: ${e.message}")
}
println("\n=== CoroutineScope ===")
// カスタムスコープ
val customScope = CoroutineScope(Dispatchers.Default + Job())
customScope.launch {
println("カスタムスコープで実行")
delay(100)
println("カスタムスコープ完了")
}
delay(200) // 完了を待機
customScope.cancel() // スコープをキャンセル
println("プログラム終了")
}
バージョン
バージョン | リリース日 | 主な新機能 |
---|---|---|
Kotlin 2.1 | 2024-11 | Kotlin Multiplatform improvements, New K2 compiler |
Kotlin 2.0 | 2024-05 | K2 compiler stable, Kotlin Multiplatform stable |
Kotlin 1.9 | 2023-07 | Enum entries function, Data object declarations |
Kotlin 1.8 | 2023-02 | Recursive generic types, @JvmMultifileClass improvements |
Kotlin 1.7 | 2022-06 | Kotlin Multiplatform Mobile Alpha, Builder inference |
Kotlin 1.6 | 2021-11 | Stable exhaustive when, Kover code coverage |
Kotlin 1.5 | 2021-05 | JVM IR backend stable, Value classes |
参考ページ
公式ドキュメント
- Kotlin公式サイト - 公式サイト
- Kotlin Documentation - 公式ドキュメント
- Kotlin Playground - ブラウザ上でKotlinを試せる環境
学習リソース
- Kotlin Koans - Kotlin学習用エクササイズ
- Android Kotlin Fundamentals - Android開発用Kotlin基礎
- Kotlin for Java Developers - Java開発者向けKotlin
開発ツール
- IntelliJ IDEA - Kotlin標準対応IDE
- Android Studio - Android開発環境
- Awesome Kotlin - Kotlinライブラリ・リソース集