初めてのKotlin:基本を解説

はい、承知いたしました。「初めてのKotlin:基本を解説」というタイトルで、約5000語の詳細な記事を記述します。


初めてのKotlin:基本を解説

はじめに:Kotlinとは何か、なぜ学ぶのか

プログラミングの世界は常に進化しており、新しい言語やツールが次々と登場しています。その中でも近年特に注目を集め、多くの開発者に採用されているのが「Kotlin(コトリン)」です。特にAndroid開発においては、Googleが公式に第一級言語としてサポートして以来、デファクトスタンダードとも言える存在になりました。しかし、Kotlinの魅力はAndroid開発にとどまらず、サーバーサイド開発、Web開発(フロントエンド・バックエンド)、デスクトップアプリケーション、さらには組み込みシステムやマルチプラットフォーム開発にまで広がっています。

この記事は、「プログラミング経験はあるけれど、Kotlinは初めて」という方を対象に、Kotlinの基本的な概念から、Javaとの違い、そしてKotlinならではの強力な機能までを、詳細かつ分かりやすく解説することを目的としています。約5000語というボリュームをかけて、単なる機能紹介にとどまらず、その機能がなぜKotlinに存在するのか、どのようなメリットがあるのかといった背景も深く掘り下げていきます。

Kotlinの誕生背景と特徴

Kotlinは、チェコのソフトウェア開発会社であるJetBrainsによって開発され、2016年にバージョン1.0がリリースされました。Javaが抱えていたいくつかの課題(冗長な記述、NullPointerExceptionの発生リスクなど)を解決し、より安全で簡潔、かつ表現力の高い言語を目指して設計されました。

Kotlinの主な特徴は以下の通りです。

  1. JVM言語: Java Virtual Machine(JVM)上で動作します。これは、既存のJavaライブラリやフレームワークをそのまま利用できることを意味し、Javaからの移行や共存が非常に容易です。
  2. 静的型付け: コンパイル時に型チェックが行われます。これにより、実行時エラー(特に型の不一致)を早期に発見でき、コードの信頼性が高まります。
  3. 簡潔性と表現力: Javaと比較して、コード量が少なく、より直感的に意図を表現できます。ラムダ式、拡張関数、データクラスなど、現代的なプログラミングパラダイムをサポートする機能が豊富です。
  4. 安全性: 最大の特徴の一つが、NullPointerException(NPE)の発生を極力抑制するための強力な「Null安全性」機能です。
  5. 相互運用性: Javaとの相互運用性が非常に高く、KotlinコードからJavaコードを、JavaコードからKotlinコードを自然に呼び出せます。
  6. マルチプラットフォーム: JVM上で動作するKotlin/JVMだけでなく、JavaScriptにコンパイルされるKotlin/JS、ネイティブバイナリにコンパイルされるKotlin/Nativeなどがあり、iOSやデスクトップアプリケーションの開発も可能です。

なぜ今、Kotlinを学ぶべきか?

  • モダンな開発に追いつく: 簡潔さ、安全性、表現力といった現代のプログラマーが求める要素を高いレベルで満たしています。
  • 生産性の向上: Javaに比べてコード記述量が減り、Nullチェックなどの定型的な処理から解放されるため、開発効率が向上します。
  • 高い人気と需要: Android開発を筆頭に、多くの企業がKotlinを採用しています。Kotlinを扱える開発者の需要は高まっています。
  • 学習コストの低さ: Javaなどのオブジェクト指向言語の経験があれば、比較的スムーズに習得できます。

この長い道のりを共に歩む準備はできましたか?それでは、Kotlinの魅力的な世界への第一歩を踏み出しましょう。

開発環境の準備

Kotlinの学習を始めるにあたって、まずはコードを書いて実行できる環境を整えましょう。最も一般的な方法は、IntelliJ IDEAというIDE(統合開発環境)を使用することです。KotlinはJetBrainsによって開発されており、IntelliJ IDEAはKotlinのサポートが非常に強力だからです。

IntelliJ IDEAのインストール

  1. IntelliJ IDEAのダウンロード: JetBrainsの公式ウェブサイトからIntelliJ IDEAをダウンロードします。Community Edition(無料版)で十分です。
    https://www.jetbrains.com/ja-jp/idea/download/
  2. インストール: ダウンロードしたインストーラを実行し、指示に従ってインストールします。特に難しい設定はありません。
  3. 起動: インストールが完了したらIntelliJ IDEAを起動します。

初めてのKotlinプロジェクトを作成

IntelliJ IDEAを使って、最も基本的なKotlinアプリケーションである「Hello, World!」を表示するプロジェクトを作成してみましょう。

  1. 新しいプロジェクトを作成: IntelliJ IDEAのウェルカムスクリーンで「New Project」を選択します。
  2. プロジェクトの設定:
    • 左側のリストから「Kotlin」を選択します。
    • プロジェクト名(例: MyFirstKotlinProject)とプロジェクトの保存場所を指定します。
    • Build systemは「Gradle」または「IntelliJ」を選択できますが、ここではシンプルに「IntelliJ」を選択します。
    • JDKがインストールされていない場合は、ここでダウンロードを促されることがあります。画面の指示に従ってダウンロード・設定してください。
  3. プロジェクト作成: 設定が完了したら「Create」をクリックします。
  4. ファイルを作成: プロジェクトが作成されたら、左側のプロジェクトビューで src ディレクトリを右クリックし、「New」>「Kotlin Class/File」を選択します。
  5. ファイルの種類と名前を指定:
    • Kindは「File」を選択します。
    • Nameは main.kt と入力します(Kotlinのソースコードファイルは通常 .kt 拡張子を持ちます)。
  6. コード記述: main.kt ファイルに以下のコードを記述します。

kotlin
fun main() {
println("Hello, World!")
}

コードの実行

コードを記述したら、実行してみましょう。

  1. 実行ボタン: main.kt ファイルを開いているエディタの左側にある緑色の実行ボタン(▶)をクリックします。
  2. 「Run ‘MainKt’」を選択: ポップアップメニューが表示されるので、「Run ‘MainKt’」を選択します。
  3. 結果を確認: IntelliJ IDEAの下部に「Run」ウィンドウが表示され、プログラムの出力 Hello, World! が表示されます。

これで、Kotlinコードを書いて実行するための基本的な環境設定は完了です。

Kotlinの基本構文

ここからが本番です。Kotlinの基本的な構文要素について、Javaと比較しながら見ていきましょう。

エントリーポイント:main関数

プログラムの実行開始地点となるのが main 関数です。Javaでは public static void main(String[] args) でしたが、Kotlinではよりシンプルになります。

kotlin
fun main() {
// プログラムはここから始まります
println("Hello, World!")
}

  • fun: 関数を定義するためのキーワードです。
  • main: 関数名です。
  • (): パラメータリストです。ここではパラメータはありません。
  • {}: 関数本体です。
  • println(): 標準出力に文字列を表示する関数です。改行を含みます。Javaの System.out.println() に相当します。

コマンドライン引数を受け取りたい場合は、以下のように Array<String> 型の引数を指定します。

kotlin
fun main(args: Array<String>) {
if (args.isNotEmpty()) {
println("Received arguments: ${args.joinToString()}")
} else {
println("No arguments provided.")
}
}

${} は文字列テンプレートと呼ばれる機能で、文字列の中に変数の値などを埋め込むことができます。非常に便利です。

変数:valvar

変数を宣言するには、val または var キーワードを使用します。Kotlinでは変数の扱いにおいて、可変性(Mutability)を重視しています。

  • val (Value): 読み取り専用(Read-only)の変数を宣言します。一度値を代入したら、その後は値を変更できません。Javaの final 変数に近いです。
  • var (Variable): 可変(Mutable)の変数を宣言します。値を何度でも変更できます。Javaの通常の変数に近いです。

どちらを使うべきか迷ったときは、まず val を使うのがKotlinの推奨スタイルです。可能な限り変更されないデータとして扱うことで、コードの予測可能性が高まり、バグを減らすことができます。

“`kotlin
fun main() {
// val (読み取り専用)
val name = “Alice”
// name = “Bob” // コンパイルエラー! valは再代入できません

// var (可変)
var age = 30
age = 31 // OK! varは再代入できます

println("Name: $name, Age: $age")

}
“`

型推論と明示的な型指定

Kotlinは強力な型推論(Type Inference)を備えています。多くの場合、変数宣言時に初期値を指定すれば、コンパイラが自動的に変数の型を推測してくれます。

kotlin
val count = 10 // Int と推論される
val price = 19.99 // Double と推論される
val message = "Hello" // String と推論される
val isReady = true // Boolean と推論される

もちろん、明示的に型を指定することも可能です。これは、初期値がない場合や、特定の型を指定したい場合に必要になります。変数の名前の後にコロン : と型名を記述します。

“`kotlin
val quantity: Int = 100
var total: Double = 0.0
val greeting: String
greeting = “Good morning” // valでも初期値が後から代入される場合は型指定が必要

val character: Char = ‘A’
“`

明示的な型指定と型推論を適切に使い分けることで、コードの可読性と簡潔性のバランスを取ることができます。

基本データ型

Kotlinの基本データ型は、数値、文字、真偽値などです。Javaのプリミティブ型(int, double, booleanなど)とほぼ同じように使えますが、Kotlinではこれらもオブジェクトとして扱われます(実際にはコンパイル時にJavaのプリミティブ型に最適化されることが多いです)。

  • 数値型:
    • Byte: 8ビット符号付き整数
    • Short: 16ビット符号付き整数
    • Int: 32ビット符号付き整数 (最も一般的)
    • Long: 64ビット符号付き整数 (L または l をつけてリテラルを表現: 123L)
    • Float: 32ビット単精度浮動小数点数 (F または f をつけてリテラルを表現: 3.14f)
    • Double: 64ビット倍精度浮動小数点数 (最も一般的)
  • 文字型: Char (シングルクォートで囲む: 'a', '1')
  • 真偽値型: Boolean (true または false)

“`kotlin
val intValue: Int = 42
val longValue: Long = 10000000000L
val floatValue: Float = 3.14f
val doubleValue: Double = 2.71828
val charValue: Char = ‘K’
val booleanValue: Boolean = true

println(“Int: $intValue”)
println(“Long: $longValue”)
println(“Float: $floatValue”)
println(“Double: $doubleValue”)
println(“Char: $charValue”)
println(“Boolean: $booleanValue”)
“`

数値型間の変換は、明示的に変換関数を呼び出す必要があります(例: intValue.toLong(), doubleValue.toInt())。Javaのような暗黙的な数値型変換(例えば int から long への代入)は、情報が失われる可能性のある変換(例えば long から int への代入)と同様に、Kotlinでは許されていません。

kotlin
val i: Int = 10
val l: Long = i.toLong() // OK: IntをLongに変換
// val j: Int = l // コンパイルエラー! LongをIntにそのまま代入できない
val j: Int = l.toInt() // OK: LongをIntに変換(値の範囲に注意)

文字列:String

Kotlinの String はJavaと同様にimmutable(不変)です。文字列リテラルはダブルクォート " " で囲みます。

kotlin
val greeting: String = "Hello, Kotlin!"
println(greeting)

前述の文字列テンプレートは非常に便利です。変数名や式を ${} の中に記述することで、文字列に埋め込めます。変数名だけであれば波括弧 {} は省略可能です。

“`kotlin
val language = “Kotlin”
val version = 1.9

// 変数名のみ
val message = “Learning $language version $version”
println(message) // 出力: Learning Kotlin version 1.9

// 式
val sum = 10 + 20
println(“The sum of 10 and 20 is ${10 + 20}”) // 出力: The sum of 10 and 20 is 30
println(“The sum is $sum”) // 出力: The sum is 30
“`

また、複数行文字列(Raw String)はトリプルクォート """ """ で囲みます。複数行文字列内ではエスケープ文字(\n, \" など)を気にする必要がありません。

“`kotlin
val poem = “””
Kotlin is fun,
It makes coding easy,
Hello, world, again.
“””.trimIndent() // trimIndent()で左側の余白を削除

println(poem)
“`

コメント

コメントの書き方はJavaと同じです。

  • 単一行コメント: // これは単一行コメントです
  • 複数行コメント:
    kotlin
    /*
    これは
    複数行コメントです
    */

演算子

Kotlinの演算子は、ほとんどがJavaと同じです。

  • 算術演算子: +, -, *, /, %
  • 比較演算子: ==, !=, <, >, <=, >=
  • 代入演算子: =, +=, -=, *=, /=, %=
  • 論理演算子: && (論理AND), || (論理OR), ! (論理NOT)
  • インクリメント/デクリメント: ++, -- (前置/後置)

“`kotlin
var a = 10
var b = 5

println(“a + b = ${a + b}”) // 15
println(“a – b = ${a – b}”) // 5
println(“a * b = ${a * b}”) // 50
println(“a / b = ${a / b}”) // 2 (整数同士の割り算)
println(“a % b = ${a % b}”) // 0

println(“a == b: ${a == b}”) // false
println(“a > b: ${a > b}”) // true

a += 2 // aは12になる
println(“a after += 2: $a”) // 12

val x = true
val y = false
println(“x && y: ${x && y}”) // false
println(“x || y: ${x || y}”) // true
println(“!x: ${!x}”) // false
“`

等価性チェック

Kotlinには2種類の等価性チェックがあります。

  • == (構造的等価性): 2つのオブジェクトの内容が同じかどうかを比較します。Javaの equals() メソッドの呼び出しに相当します(プリミティブ型の場合はJavaの == と同じ)。
  • === (参照等価性): 2つのオブジェクトがメモリ上で全く同じインスタンスを参照しているかどうかを比較します。Javaの == 演算子に相当します。

“`kotlin
val str1 = “hello”
val str2 = “hello”
val str3 = “world”

println(“str1 == str2: ${str1 == str2}”) // true (内容が同じ)
println(“str1 == str3: ${str1 == str3}”) // false

println(“str1 === str2: ${str1 === str2}”) // true (通常、同じ文字列リテラルは同じインスタンスになる)

val obj1 = object { val value = 1 }
val obj2 = object { val value = 1 }
val obj3 = obj1

println(“obj1 == obj2: ${obj1 == obj2}”) // false (デフォルトではequalsは参照比較)
println(“obj1 == obj3: ${obj1 == obj3}”) // true (同じインスタンス)

println(“obj1 === obj2: ${obj1 === obj2}”) // false (異なるインスタンス)
println(“obj1 === obj3: ${obj1 === obj3}”) // true (同じインスタンス)
“`

データクラス(後述)を使用すると、== は自動的に全プロパティの構造的等価性を比較するように実装されます。

区間(Ranges)

Kotlinは .. 演算子を使って数値の区間を簡単に表現できます。これは for ループなどで非常に便利です。

“`kotlin
val range = 1..5 // 1, 2, 3, 4, 5 を含む区間

println(“Is 3 in range? ${3 in range}”) // true
println(“Is 6 in range? ${6 in range}”) // false

for (i in 1..3) { // 1, 2, 3 を含む
println(i)
}

for (i in 1 until 5) { // 1, 2, 3, 4 を含む (5は含まない)
println(i)
}

for (i in 5 downTo 1) { // 5, 4, 3, 2, 1 を含む
println(i)
}

for (i in 1..10 step 2) { // 1, 3, 5, 7, 9 を含む
println(i)
}
“`

制御フロー

プログラムの流れを制御するための構文を見ていきましょう。

条件分岐:if, when

  • if/else: Javaと似ていますが、Kotlinの ifとして値を返すことができます。

“`kotlin
val score = 75
val result = if (score >= 60) {
“Passed” // ifブロックの最後の式が値となる
} else {
“Failed” // elseブロックの最後の式が値となる
}
println(“Result: $result”) // 出力: Result: Passed

// 式として使わない場合はJavaと同じように記述できる
if (score > 90) {
println(“Excellent!”)
} else if (score > 70) {
println(“Good!”)
} else {
println(“Needs Improvement.”)
}
“`

  • when: Javaの switch 文よりも強力で柔軟な構文です。when も式として値を返すことができます。

“`kotlin
val dayOfWeek = 3
val dayName = when (dayOfWeek) {
1 -> “Monday”
2 -> “Tuesday”
3 -> “Wednesday”
4 -> “Thursday”
5 -> “Friday”
in 6..7 -> “Weekend” // 区間も指定できる
else -> “Invalid day” // 必須ではないが、式として使う場合は全ての可能性を網羅するかelseが必要
}
println(“Day: $dayName”) // 出力: Day: Wednesday

// 引数なしのwhen (より複雑な条件に使える)
val temp = 25
val weatherStatus = when {
temp < 0 -> “Freezing”
temp < 10 -> “Cold”
temp < 20 -> “Cool”
temp < 30 -> “Warm”
else -> “Hot”
}
println(“Weather: $weatherStatus”) // 出力: Weather: Warm

// 型による判定
fun describe(obj: Any): String = when (obj) {
1 -> “One”
“Hello” -> “Greeting”
is Long -> “Long number” // 型による判定
!is String -> “Not a string”
else -> “Unknown”
}

println(describe(1)) // One
println(describe(“Hello”)) // Greeting
println(describe(10000L)) // Long number
println(describe(2.5)) // Not a string
“`

whenif-else if-else チェーンよりも多くのケースでコードを簡潔かつ明確に記述できます。

ループ:for, while, do-while

  • for: コレクション、配列、区間などをイテレート(反復処理)するのに使います。

“`kotlin
// 区間をイテレート
for (i in 1..5) {
println(i) // 1, 2, 3, 4, 5
}

// コレクションをイテレート
val fruits = listOf(“Apple”, “Banana”, “Cherry”)
for (fruit in fruits) {
println(fruit)
}

// インデックス付きでイテレート
for (index in fruits.indices) { // fruitsのインデックスの区間を取得
println(“Item at $index is ${fruits[index]}”)
}

// インデックスと値を同時に取得
for ((index, value) in fruits.withIndex()) {
println(“Item at $index is $value”)
}

// Mapをイテレート
val ages = mapOf(“Alice” to 30, “Bob” to 25)
for ((name, age) in ages) {
println(“$name is $age years old”)
}
“`

  • while: 条件が真の間、ブロック内のコードを繰り返し実行します。

kotlin
var count = 0
while (count < 5) {
println("Count: $count")
count++
}

  • do-while: ブロック内のコードを一度実行し、その後条件が真の間繰り返し実行します。

kotlin
var i = 0
do {
println("i: $i")
i++
} while (i < 3)

ジャンプ式:break, continue, return

Javaと同様に、break は最も内側のループや when 式を終了させ、continue は現在のループのイテレーションをスキップして次のイテレーションに進みます。

return は関数から制御を戻しますが、Kotlinではローカル関数やラムダ式で使用する際に「ラベル」を使って制御するスコープを指定できる強力な機能があります。

“`kotlin
fun greet(name: String?) {
// nameがnullの場合、この関数から即座にreturn
if (name == null) return

println("Hello, $name!")

}

greet(“World”) // 出力: Hello, World!
greet(null) // 何も出力されない

// ラベルを使ったbreakとcontinue
loop@ for (i in 1..10) {
for (j in 1..10) {
if (i * j > 50) {
// break@loop を使うと外側のループを抜ける
// break だけだと内側のループしか抜けない
break@loop
}
println(“i=$i, j=$j, ij=${ij}”)
}
}
“`

Null安全性

Kotlinの最も重要な特徴の一つがNull安全性です。Java開発者がよく遭遇するNullPointerException(NPE)の発生を、コンパイル時エラーとして検出することで、実行時エラーのリスクを大幅に減らします。

Kotlinでは、変数の型がデフォルトで非Null許容です。つまり、Nullを代入することができません。

kotlin
var nonNullableString: String = "Hello"
// nonNullableString = null // コンパイルエラー!

Nullを許容したい場合は、型の後ろに ? をつけます。これにより、その変数はNullを保持する可能性があることを明示的に示します。

kotlin
var nullableString: String? = "Hello"
nullableString = null // OK!

Null許容型の変数を扱う際には、コンパイラがNullの可能性を考慮して、Null安全な操作を強制します。

Null安全な呼び出し (?.)

Null許容型の変数に対してメソッドやプロパティにアクセスする場合、通常の . アクセスはできません。代わりに、Null安全な呼び出し演算子 ?. を使用します。

nullableVar?.someMethod() は、nullableVar がNullでなければ someMethod() を実行し、Nullでなければ null を返します。

“`kotlin
var name: String? = “Alice”
println(name?.length) // 出力: 5 (nameがNullではないのでlengthを取得)

name = null
println(name?.length) // 出力: null (nameがNullなのでNullを返す)
“`

メソッドチェーンでも使用できます。途中の要素が一つでもNullであれば、チェーン全体の結果はNullになります。

“`kotlin
class Address(val street: String)
class Company(val address: Address?) // addressはNull許容
class Person(val company: Company?) // companyはNull許容

fun getStreet(person: Person): String? {
// personがNullでも、companyがNullでも、addressがNullでも、Nullを返す
return person.company?.address?.street
}

val alice = Person(Company(Address(“123 Main St”)))
val bob = Person(Company(null))
val charlie = Person(null)

println(getStreet(alice)) // 出力: 123 Main St
println(getStreet(bob)) // 出力: null
println(getStreet(charlie)) // 出力: null
“`

Elvis演算子 (?:)

Null許容式の値がNullだった場合に、デフォルト値を指定したい場合に便利です。

nullableExpression ?: defaultValue は、nullableExpression がNullでなければその値を、Nullであれば defaultValue を返します。

“`kotlin
val name: String? = null
val displayName = name ?: “Guest” // nameがNullなので”Guest”が代入される
println(displayName) // 出力: Guest

val actualName: String? = “Bob”
val displayActualName = actualName ?: “Guest” // actualNameがNullではないので”Bob”が代入される
println(displayActualName) // 出力: Bob
“`

Elvis演算子の右側には、どのような式でも書くことができます。例えば、例外をスローすることも可能です。

kotlin
val input: String? = null
val nonNullInput: String = input ?: throw IllegalArgumentException("Input cannot be null")
// inputがNullなので例外がスローされる

let 関数とスコープ関数

Null許容型の変数がNullでない場合に、特定の処理を実行したい場合があります。このような場合に if (variable != null) { ... } と書く代わりに、Null安全な呼び出しとスコープ関数 let を組み合わせるのがKotlinらしい書き方です。

“`kotlin
val email: String? = “[email protected]

email?.let {
// ここはemailがNullでない場合にのみ実行される
// ‘it’ は Nullではないemailの値を参照する
println(“Sending email to $it”)
}

val phone: String? = null
phone?.let {
// phoneはNullなので、このブロックは実行されない
println(“Calling $it”)
}
“`

let 関数は、対象のオブジェクトをラムダ式の引数(デフォルトでは it)として渡すスコープ関数の一つです。Null安全な呼び出し ?. と組み合わせることで、「もしこのオブジェクトがNullでなければ、このブロック内の処理を実行する」というパターンを安全かつ簡潔に記述できます。

非Nullアサーション演算子 (!!)

Null許容型の変数に対して、開発者が「これは絶対にNullではない」と確信している場合に限り、非Nullアサーション演算子 !! を使うことができます。

kotlin
val sureName: String? = "Charlie"
val nonNullableSureName: String = sureName!! // Null許容型を非Null許容型に変換
println(nonNullableSureName.length) // OK

しかし、もし !! を使った変数や式が実際にNullだった場合、NullPointerExceptionが発生します。 これはJavaのNPEと同じ結果を招きます。

kotlin
val potentiallyNullName: String? = null
// val nonNullablePotentiallyNullName: String = potentiallyNullName!!
// println(nonNullablePotentiallyNullName.length) // 実行時にNPEが発生!

!! は「Nullになり得ないことを保証する」という強い意志表示であり、乱用すべきではありません。可能な限り ?.?:?.let { ... } など、KotlinのNull安全な機能を使うべきです。!! は主にJavaとの相互運用などでNull安全性が保証できない場合や、本当に「あり得ない」状況を示すために使用します。

安全なキャスト (as?)

オブジェクトの型変換(キャスト)を行う際にも、Null安全性が考慮されます。Kotlinでは安全なキャスト演算子 as? が提供されています。

obj as? TargetType は、objTargetType にキャスト可能であればその結果を返し、キャスト不可能であれば null を返します。キャストできない場合に例外をスローするJavaのキャストやKotlinの通常のキャスト (as) とは異なります。

“`kotlin
val value: Any = “Hello”
val str: String? = value as? String // キャスト可能なので”Hello”
println(str?.length) // 5

val num: Any = 123
val str2: String? = num as? String // キャスト不可能なのでnull
println(str2?.length) // null
“`

関数

関数は、特定のタスクを実行するためのコードブロックです。Kotlinでは、クラスの外部にトップレベル関数を定義できる点が特徴です。

関数の定義

関数は fun キーワードを使って定義します。

“`kotlin
// 引数も戻り値もない関数
fun sayHello() {
println(“Hello!”)
}

// 引数がある関数
fun greet(name: String) {
println(“Hello, $name!”)
}

// 複数の引数がある関数
fun add(a: Int, b: Int): Int { // 引数の型と戻り値の型を明示
return a + b
}

// 戻り値がない関数 (Unitを返す)
fun printSum(a: Int, b: Int): Unit { // Unitは省略可能
println(“Sum: ${a + b}”)
}

// Unitは省略するのが一般的
fun printSum(a: Int, b: Int) {
println(“Sum: ${a + b}”)
}
“`

Unit はJavaの void に相当しますが、Kotlinの Unit は単一のインスタンスを持つ実際の型です。戻り値の型が Unit の場合、明示的に return Unit と書くことも、return を省略することも可能です。通常は省略します。

単一式関数

関数本体が単一の式である場合、波括弧 {}、戻り値の型宣言(コンパイラが推論できる場合)、そして return キーワードを省略し、= を使って記述できます。これはコードを非常に簡潔にします。

“`kotlin
// 通常の関数定義
fun multiply(a: Int, b: Int): Int {
return a * b
}

// 単一式関数
fun multiply(a: Int, b: Int) = a * b // 戻り値の型Intは推論される
“`

デフォルト引数と名前付き引数

Kotlinでは、関数のパラメータにデフォルト値を設定できます。これにより、同じような機能を持つ複数のオーバーロード関数を定義する必要がなくなります。

“`kotlin
fun greetUser(name: String = “Guest”, greeting: String = “Hello”) {
println(“$greeting, $name!”)
}

greetUser(“Alice”, “Good morning”) // 出力: Good morning, Alice!
greetUser(“Bob”) // 出力: Hello, Bob! (name=”Bob”, greeting=”Hello”)
greetUser(greeting = “Hi”) // 出力: Hi, Guest! (name=”Guest”, greeting=”Hi”)
greetUser() // 出力: Hello, Guest! (両方ともデフォルト値)
“`

デフォルト引数を使用する場合、関数呼び出し時に引数の名前を指定して値を渡すこともできます(名前付き引数)。これは、特に引数が多い場合や、一部の引数だけをデフォルト値から変更したい場合に、コードの可読性を高めます。

“`kotlin
fun configure(width: Int = 800, height: Int = 600, dpi: Int = 72) {
println(“Config: width=$width, height=$height, dpi=$dpi”)
}

configure(width = 1024) // 出力: Config: width=1024, height=600, dpi=72
configure(height = 768, width = 1024) // 出力: Config: width=1024, height=768, dpi=72 (順番を入れ替えられる)
“`

可変長引数(vararg)

Javaの ... と同様に、Kotlinでは vararg 修飾子を使って可変長引数を定義できます。これにより、同じ型の引数を任意の数だけ関数に渡せます。可変長引数は関数内では配列として扱われます。

“`kotlin
fun printNumbers(vararg numbers: Int) {
println(“Received ${numbers.size} numbers:”)
for (number in numbers) {
println(number)
}
}

printNumbers(1, 2, 3)
// 出力:
// Received 3 numbers:
// 1
// 2
// 3

printNumbers(10, 20, 30, 40, 50)
// 出力:
// Received 5 numbers:
// 10
// 20
// 30
// 40
// 50
“`

既に配列やリストとして持っている要素を vararg 引数として渡したい場合は、スプレッド演算子 * を使用します。

kotlin
val nums = intArrayOf(100, 200, 300)
printNumbers(*nums) // 配列の要素を展開して渡す

クラスとオブジェクト指向

Kotlinはオブジェクト指向プログラミング(OOP)を完全にサポートしています。Javaと同様にクラスを定義し、オブジェクトを作成できます。

クラスの定義とインスタンス生成

クラスは class キーワードを使って定義します。

“`kotlin
// 基本的なクラス定義
class Person {
// プロパティやメソッドをここに記述
}

// インスタンス生成
val person = Person()
“`

プロパティ

クラスのプロパティ(メンバ変数)は、クラス本体の中で val または var を使って宣言します。Javaのようにgetter/setterメソッドを明示的に書く必要はありません。Kotlinはプロパティに対してデフォルトでgetter(val/var)とsetter(varのみ)を生成します。

“`kotlin
class User {
var name: String = “Anonymous”
val age: Int = 0 // 初期値が必要

// プロパティへのアクセスはJavaのようにフィールド名を使う
fun displayInfo() {
    println("Name: $name, Age: $age")
}

}

val user = User()
user.name = “Alice” // setterが呼び出される
// user.age = 31 // コンパイルエラー! valなので再代入できない

println(user.name) // getterが呼び出される
user.displayInfo()
“`

プロパティの初期化は必須です。コンストラクタで初期化するか、宣言時に初期値を代入します。

コンストラクタ

Kotlinには、主にプライマリコンストラクタセカンダリコンストラクタの2種類のコンストラクタがあります。

  • プライマリコンストラクタ: クラスヘッダーの一部として定義されます。クラスの基本的な初期化を行うためによく使われます。

“`kotlin
// プライマリコンストラクタを定義
class Person(val name: String, var age: Int) {
// プロパティはプライマリコンストラクタで直接定義できる
// val/var をつけると、対応するプロパティが自動生成される
// 何もつけないと、そのスコープ内でしか使えないパラメータになる

// 初期化ブロック
init {
    println("Person object created with name $name and age $age")
}

fun sayHello() {
    println("Hello, my name is $name.")
}

}

val person1 = Person(“Alice”, 30) // プライマリコンストラクタ呼び出し
person1.sayHello()
println(person1.age)
person1.age = 31 // varなので変更可能
println(person1.age)
“`

init ブロックは、プライマリコンストラクタの一部として実行される初期化ロジックを記述するために使用します。複数の init ブロックがあっても構いません。定義された順に実行されます。

  • セカンダリコンストラクタ: constructor キーワードを使ってクラス本体内に定義します。プライマリコンストラクタが存在する場合、各セカンダリコンストラクタは this() を使ってプライマリコンストラクタを直接的または間接的に呼び出す必要があります。

“`kotlin
class Animal(val name: String) { // プライマリコンストラクタ

constructor(name: String, age: Int) : this(name) { // セカンダリコンストラクタ
    // プライマリコンストラクタ(name)を呼び出し
    println("Animal $name (age $age) created.")
    // さらに追加の初期化ロジック
}

init {
    println("Animal named $name is being initialized (from init block).")
}

}

val animal1 = Animal(“Dog”) // プライマリコンストラクタを呼び出す
val animal2 = Animal(“Cat”, 5) // セカンダリコンストラクタを呼び出す (initブロックも実行される)
“`

継承

Kotlinでは、クラスはデフォルトで閉じられています(finalです)。継承を許可するには、スーパークラスに open 修飾子を付ける必要があります。メソッドやプロパティも同様に、オーバーライドを許可するには open を付け、オーバーライドする側では override を付けます。

“`kotlin
open class Base { // 継承可能にする
open fun display() { // オーバーライド可能にする
println(“This is Base class”)
}

fun normalMethod() { // オーバーライド不可
    println("This is a normal method")
}

}

class Derived : Base() { // 継承。スーパークラスのコンストラクタを呼び出す
override fun display() { // オーバーライドする
println(“This is Derived class”)
}
}

val base = Base()
val derived = Derived()

base.display() // 出力: This is Base class
derived.display() // 出力: This is Derived class
derived.normalMethod() // 出力: This is a normal method
“`

インターフェース

インターフェースは interface キーワードで定義します。プロパティと抽象メソッドを持つことができます。抽象メソッドはデフォルトで open です。

“`kotlin
interface MyInterface {
val prop: Int // プロパティ
fun abstractMethod() // 抽象メソッド

fun defaultMethod() { // デフォルト実装を持つメソッド
    println("Default implementation")
}

}

class MyClass : MyInterface {
override val prop: Int = 10 // プロパティをオーバーライド(初期化)

override fun abstractMethod() { // 抽象メソッドを実装
    println("Implementation of abstractMethod")
}
// defaultMethodはオーバーライドしてもしなくても良い

}

val obj = MyClass()
println(obj.prop) // 10
obj.abstractMethod() // Implementation of abstractMethod
obj.defaultMethod() // Default implementation
“`

可視性修飾子

Kotlinの可視性修飾子は、Javaとは少し異なります。

  • public: どこからでもアクセス可能 (デフォルト)
  • private: そのメンバーを宣言しているファイルまたはクラス内からのみアクセス可能
  • protected: クラスとそのサブクラス内からアクセス可能
  • internal: 同一モジュール内からアクセス可能(モジュールとは、IntelliJ IDEAのModule、MavenまたはGradleプロジェクト、Antタスクのセットなど)

internal はJavaにはないKotlin独自の修飾子で、ライブラリ開発などで外部からのアクセスを制限しつつ、モジュール内では自由に使えるようにしたい場合に非常に便利です。

オブジェクト宣言(Singleton)

Kotlinでは、オブジェクト宣言を使うと簡単にSingletonパターンを実現できます。object キーワードを使います。

“`kotlin
object Singleton {
val name = “MySingleton”

fun doSomething() {
    println("$name is doing something")
}

}

// オブジェクト名を使って直接メンバにアクセス
println(Singleton.name)
Singleton.doSomething()

// Singletonはインスタンス化できない
// val obj = Singleton() // コンパイルエラー
“`

コンパニオンオブジェクト(Companion Object)

クラス内に companion object を宣言すると、そのメンバはクラスのインスタンスではなく、クラス自身に関連付けられます。これはJavaの static メンバに近い概念ですが、実際のところコンパニオンオブジェクトはクラス内にネストされた通常のオブジェクト宣言です。

“`kotlin
class MyClass {
companion object {
const val CONSTANT = “This is a constant” // コンパイル時定数
private var count = 0

    fun create(): MyClass {
        count++
        println("MyClass instance created, total count: $count")
        return MyClass()
    }
}

// コンパニオンオブジェクトのメンバにアクセス
fun displayCount() {
    // privateなcountにもアクセスできる
    println("Current instance count: $count")
}

}

// クラス名を使ってコンパニオンオブジェクトのメンバにアクセス
println(MyClass.CONSTANT)
MyClass.create() // MyClass.Companion.create() と同じ意味だが、より短く書ける
MyClass.create()

val obj = MyClass.create()
obj.displayCount()
“`

Kotlinの強力な機能

Kotlinには、コードをより安全、簡潔、表現豊かにするための様々な強力な機能があります。その中からいくつかを見ていきましょう。

データクラス(Data Classes)

データを保持するためだけのクラス(JavaでいうPOJO: Plain Old Java Object)を定義する際に非常に便利なのがデータクラスです。data class キーワードをクラスの前に付けます。

データクラスを宣言すると、コンパイラは以下のメンバ関数を自動的に生成してくれます。

  • equals() / hashCode(): 主コンストラクタで宣言された全てのプロパティに基づく実装
  • toString(): 主コンストラクタで宣言された全てのプロパティを含む文字列表現
  • copy(): オブジェクトをコピーしつつ、一部のプロパティだけを変更できる関数
  • componentN(): オブジェクトを分割代入(Destructuring Declaration)可能にする関数 (プロパティの数だけ component1(), component2(), … が生成される)

“`kotlin
data class User(val name: String, val age: Int) // これだけで十分!

val user1 = User(“Alice”, 30)
val user2 = User(“Alice”, 30)
val user3 = User(“Bob”, 25)

// toString() が自動生成される
println(user1) // 出力: User(name=Alice, age=30)

// equals() が自動生成される (プロパティの値で比較)
println(“user1 == user2: ${user1 == user2}”) // 出力: user1 == user2: true
println(“user1 == user3: ${user1 == user3}”) // 出力: user1 == user3: false

// hashCode() もプロパティの値に基づいて生成される

// copy() 関数
val user4 = user1.copy(age = 31) // user1をコピーしてageだけ変更
println(user4) // 出力: User(name=Alice, age=31)

// 分割代入 (Destructuring Declaration)
val (name, age) = user1
println(“Name: $name, Age: $age”) // 出力: Name: Alice, Age: 30

// 一部のプロパティだけ取得 (アンダースコアでスキップ)
val (userName, _) = user1
println(“Name: $userName”) // 出力: Name: Alice
“`

Javaで同様のことを行うには、手作業でこれらのメソッドを実装したり、IDEの自動生成機能を使ったりする必要がありますが、Kotlinでは data class を付けるだけで済むため、非常に効率的です。

データクラスの主コンストラクタには、少なくとも1つのプロパティが必要です。また、データクラスは open にすることはできません(継承不可)。

シールドクラス(Sealed Classes)

シールドクラスは、特定の限定されたクラス階層を表現するために使用されます。シールドクラスのサブクラスは、同じファイル内でしか定義できません(Kotlin 1.1からは、同じモジュール内のどこでも定義できるようになりましたが、通常は同じファイルに定義します)。

シールドクラスは when 式と組み合わせると特に強力です。when 式でシールドクラスの全てのサブクラスを網羅した場合、else ブランチを省略できます。コンパイラが網羅性をチェックしてくれるため、パターンマッチングが安全になります。

“`kotlin
sealed class Result {
data class Success(val data: String) : Result() // サブクラス
data class Error(val message: String) : Result() // サブクラス
object Loading : Result() // シングルトンオブジェクトもサブクラスにできる
}

fun handleResult(result: Result) {
when (result) {
is Result.Success -> println(“Success: ${result.data}”)
is Result.Error -> println(“Error: ${result.message}”)
Result.Loading -> println(“Loading…”) // オブジェクトの場合はインスタンスそのものを指定
// シールドクラスの全てのサブクラスを網羅しているので、elseは不要
}
}

handleResult(Result.Loading)
handleResult(Result.Success(“Data loaded successfully”))
handleResult(Result.Error(“Failed to load data”))
“`

シールドクラスは、状態遷移や有限の状態を表現するのに適しています。

拡張関数(Extension Functions)

既存のクラスに、ソースコードを変更することなく新しいメンバ関数を追加できる機能です。JavaにはないKotlinのユニークな機能です。

拡張関数を定義するには、追加したいクラス名(レシーバ型)を関数名の前にドット . で区切って記述します。関数本体内では、レシーバ型のインスタンスは this で参照できます(通常は省略)。

“`kotlin
// StringクラスにisPalindrome()という拡張関数を追加
fun String.isPalindrome(): Boolean {
// this は拡張関数のレシーバであるStringインスタンスを指す
return this == this.reversed()
}

val str1 = “madam”
val str2 = “hello”

println(“$str1 is palindrome? ${str1.isPalindrome()}”) // 出力: madam is palindrome? true
println(“$str2 is palindrome? ${str2.isPalindrome()}”) // 出力: hello is palindrome? false
“`

拡張関数は、既存のライブラリクラスに便利なメソッドを追加したい場合や、特定のドメインに関連する関数をまとめて記述したい場合に非常に有効です。ただし、内部的には静的関数としてコンパイルされるため、継承においては少し異なる振る舞いをします(拡張関数はディスパッチされません)。

拡張プロパティも定義できます。

“`kotlin
val String.lastChar: Char
get() = this[this.length – 1]

println(“Kotlin”.lastChar) // 出力: n
“`

ラムダ式と高階関数

Kotlinは関数型プログラミングの要素も取り入れています。ラムダ式は、名前を持たない関数リテラル(匿名関数)です。高階関数は、関数を引数として受け取ったり、関数を戻り値として返したりする関数です。

  • ラムダ式: 波括弧 {} で囲み、パラメータと本体を -> で区切って記述します。

“`kotlin
val sum: (Int, Int) -> Int = { a, b -> a + b } // (Int, Int) -> Int は関数の型
println(sum(5, 3)) // 8

val greet: (String) -> Unit = { name -> println(“Hello, $name”) }
greet(“Kotlin”) // Hello, Kotlin

// パラメータが一つだけの場合、’it’ という暗黙的な名前で参照できる
val printMessage: (String) -> Unit = { println(it) }
printMessage(“Single parameter”) // Single parameter

// パラメータも戻り値もない場合
val saySomething: () -> Unit = { println(“Something”) }
saySomething() // Something
“`

  • 高階関数: 関数型をパラメータとして受け取る、または関数型を戻り値として返す関数です。

“`kotlin
// 引数として関数を受け取る高階関数
fun calculate(x: Int, y: Int, operation: (Int, Int) -> Int): Int {
return operation(x, y)
}

val result = calculate(10, 5) { a, b -> a * b } // 呼び出し時にラムダ式を渡す
// ラムダ式が関数の最後の引数である場合、関数呼び出しの括弧()の外に記述できる (Trailing Lambda Syntax)
val result2 = calculate(20, 4, { a, b -> a / b }) // 通常の渡し方
println(result) // 50
println(result2) // 5

// 戻り値として関数を返す高階関数
fun getOperation(type: String): (Int, Int) -> Int {
return when (type) {
“add” -> { a, b -> a + b }
“subtract” -> { a, b -> a – b }
else -> { _, _ -> 0 } // 何もしない関数
}
}

val addOperation = getOperation(“add”)
println(addOperation(10, 20)) // 30
“`

コレクション操作において、ラムダ式と高階関数は頻繁に使用されます。

コレクション

Kotlinの標準ライブラリは、コレクション(リスト、セット、マップなど)を扱うための豊富で強力な機能を提供しています。注目すべき点として、Kotlinはデフォルトで読み取り専用(Immutable)可変(Mutable)のコレクションを区別します。

  • 読み取り専用コレクション: listOf(), setOf(), mapOf() などで作成します。一度作成したら内容を変更できません。
  • 可変コレクション: mutableListOf(), mutableSetOf(), mutableMapOf() などで作成します。要素の追加、削除、変更が可能です。

“`kotlin
// 読み取り専用リスト
val names = listOf(“Alice”, “Bob”, “Charlie”)
// names.add(“David”) // コンパイルエラー!

// 可変リスト
val mutableNames = mutableListOf(“Alice”, “Bob”, “Charlie”)
mutableNames.add(“David”) // OK
println(mutableNames) // 出力: [Alice, Bob, Charlie, David]

// 読み取り専用マップ
val ages = mapOf(“Alice” to 30, “Bob” to 25)
// ages[“Charlie”] = 35 // コンパイルエラー!

// 可変マップ
val mutableAges = mutableMapOf(“Alice” to 30, “Bob” to 25)
mutableAges[“Charlie”] = 35 // OK
mutableAges.remove(“Bob”) // OK
println(mutableAges) // 出力: {Alice=30, Charlie=35}
“`

読み取り専用コレクションを使うことで、意図しない変更を防ぎ、コードの安全性を高めることができます。

また、Kotlinのコレクションには、前述のラムダ式と高階関数を活用した便利な拡張関数が多数用意されています。

“`kotlin
val numbers = listOf(1, 2, 3, 4, 5, 6)

// filter: 条件を満たす要素のみを抽出
val evenNumbers = numbers.filter { it % 2 == 0 } // { number -> number % 2 == 0 } と同じ
println(evenNumbers) // 出力: [2, 4, 6]

// map: 各要素に関数を適用して新しいリストを作成
val squaredNumbers = numbers.map { it * it }
println(squaredNumbers) // 出力: [1, 4, 9, 16, 25, 36]

// forEach: 各要素に対して処理を実行
numbers.forEach { println(“Number: $it”) }

// find: 条件を満たす最初の要素を返す (見つからなければnull)
val firstEven = numbers.find { it % 2 == 0 }
println(firstEven) // 出力: 2

// any: 条件を満たす要素が一つでもあればtrue
val hasNegative = numbers.any { it < 0 }
println(hasNegative) // 出力: false

// all: 全ての要素が条件を満たせばtrue
val allPositive = numbers.all { it > 0 }
println(allPositive) // 出力: true

// count: 条件を満たす要素の数をカウント
val countEven = numbers.count { it % 2 == 0 }
println(countEven) // 出力: 3
“`

これらの関数を使うことで、ループを手書きするよりも簡潔かつ宣言的にコレクション処理を記述できます。

Javaとの相互運用性

KotlinとJavaはJVM上で動作するため、非常に高い相互運用性を持ちます。これは、既存のJavaプロジェクトにKotlinを部分的に導入したり、Kotlinプロジェクトで既存のJavaライブラリを利用したりする際に大きなメリットとなります。

KotlinからJavaを呼び出す

KotlinコードからJavaのクラス、メソッド、フィールドを呼び出すのは非常に自然です。

“`kotlin
// Javaのクラスを利用する例 (Javaコードを別途用意する必要がある)
// public class JavaClass { public String getName() { return “Java”; } }
// public class JavaUtils { public static void printMessage(String msg) { System.out.println(msg); } }

// JavaClass jObj = new JavaClass();
val jObj = JavaClass()
println(jObj.name) // JavaのgetterはKotlinのプロパティのようにアクセスできる

// JavaUtils.printMessage(“Hello from Kotlin”);
JavaUtils.printMessage(“Hello from Kotlin”) // Javaのstaticメソッドも直接クラス名で呼び出せる

// Javaのstaticフィールドも直接アクセス
// public class JavaConstants { public static final int MAX_VALUE = 100; }
println(JavaConstants.MAX_VALUE)
“`

Nullabilityに関しては注意が必要です。Javaの型にはNull可能性に関する情報がありません。KotlinからJavaのメソッドやプロパティにアクセスする場合、その型はプラットフォーム型 (String!, List<Integer>!) として扱われます。プラットフォーム型はNull許容型(String?)としても非Null許容型(String)としても扱えますが、非Nullとして扱っていてもし実際にはNullが実行時に渡されるとNPEが発生します。これは、Javaとの相互運用においてNull安全性が保証されない境界領域となります。

“`kotlin
// JavaClass に public String nullableMethod() { return null; } があるとする

val javaObj = JavaClass()
val result: String = javaObj.nullableMethod() // コンパイルエラーにはならない (プラットフォーム型)
// println(result.length) // 実行時にnullableMethod()がnullを返すとここでNPEが発生!

// 安全に扱うならNull許容型として受けるか、?. や ?: を使う
val safeResult: String? = javaObj.nullableMethod()
println(safeResult?.length) // Null安全
“`

JavaからKotlinを呼び出す

JavaコードからKotlinコードを呼び出すのも同様に簡単です。Kotlinのクラスは、Javaから見ると通常のJavaクラスのように見えます。

“`kotlin
// KotlinのクラスをJavaから利用する例 (Kotlinコードを別途用意)
// class KotlinClass { fun greet(name: String) = “Hello, $name from Kotlin” }

/ Javaコード /
// KotlinClass kObj = new KotlinClass();
// System.out.println(kObj.greet(“World”)); // “Hello, World from Kotlin” と出力
“`

Kotlinのトップレベル関数は、.kt ファイル名に Kt を付けたクラスの静的メソッドとして公開されます。

“`kotlin
// Kotlinのトップレベル関数
// fun topLevelFunction() { println(“This is a top-level function”) }

/ Javaコード /
// MyFileKt.topLevelFunction(); // MyFile.kt というファイル名のKotlinファイルの場合
“`

ファイル名を変更したい場合は、ファイルのアノテーションで指定できます。@file:JvmName("CustomName")

Kotlinのプロパティは、Javaから見ると対応するgetter(getName()) とsetter(setName())としてアクセスできます。is で始まるBooleanプロパティは isReady(), setReady() のようになります。val プロパティはgetterのみ生成されます。

“`kotlin
// Kotlin class with properties
// class KotlinUser(var name: String, val age: Int)

/ Javaコード /
// KotlinUser kUser = new KotlinUser(“Alice”, 30);
// System.out.println(kUser.getName()); // Getterアクセス
// kUser.setName(“Bob”); // Setterアクセス
// System.out.println(kUser.getAge()); // valなのでgetterのみ
// kUser.setAge(31); // コンパイルエラー (setterがない)
“`

KotlinのNull許容型は、Javaから見ると @Nullable アノテーション付きの型として扱われることがありますが、これはアノテーションベースのツールやIDEの警告に依存し、コンパイル時のNull安全性を保証するものではありません。JavaコードからKotlinのNull許容型の戻り値を受け取る場合やNull許容型の引数に値を渡す場合は、Java側でNullチェックを適切に行う必要があります。

Kotlinの Unit は、Javaからは void として見えます。

総じて、KotlinとJavaの相互運用性は非常にスムーズであり、両方の言語を同じプロジェクト内で共存させることも容易です。

次のステップ:Kotlinをどこで使うか

Kotlinの基本的な文法と主要な機能を見てきました。Kotlinは多様なプラットフォームで利用できます。学習した知識を活かして、ぜひ実際に開発に挑戦してみてください。

  1. Android開発: KotlinはGoogleが公式に推奨するAndroid開発言語です。Android StudioはKotlinを完全にサポートしており、既存のJavaコードと簡単に共存できます。
  2. サーバーサイド開発: Spring Boot、Ktor、MicronautなどのフレームワークがKotlinをサポートしており、Javaに比べてより簡潔で安全なサーバーサイドアプリケーションを開発できます。
  3. Web開発: Kotlin/JSを使えば、JavaScriptの代わりにKotlinでフロントエンド開発が可能です。また、Kotlin/JVMでバックエンドを構築し、Kotlin/JSでフロントエンドを構築するフルスタック開発も可能です。
  4. マルチプラットフォーム開発 (KMP – Kotlin Multiplatform): iOS、Android、Web (JVM/JS)、デスクトップ (JVM/Native) など、複数のプラットフォームで共有可能なコードを書くことができます。特にモバイル開発(iOSとAndroid)でのコード共有に注目が集まっています。
  5. デスクトップ開発: Jetpack Compose for Desktopを使えば、KotlinでモダンなデスクトップUIアプリケーションを構築できます。

まとめ

この記事では、Kotlinの基本的な要素から、Null安全性、関数、クラス、データクラス、拡張関数、ラムダ式、コレクション、Javaとの相互運用性といった主要な機能までを詳細に解説しました。

Kotlinは、Javaの経験者にとって比較的習得しやすく、よりモダンで安全、そして生産的な開発を可能にする魅力的な言語です。特にNull安全性の仕組みは、多くの実行時エラーを防ぐ上で非常に強力です。

今回学んだ内容は、Kotlinの入門として必要十分なものです。しかし、Kotlinには他にもコルーチン(並行処理)、DSL構築、型エイリアスなど、さらに多くの強力な機能が存在します。これらの機能は、より複雑なアプリケーションを開発する際に役立ちます。

Kotlinの学習は、コードを実際に書くことが最も重要です。IntelliJ IDEAやKotlin Playgroundを使って、様々なコードを試してみてください。そして、公式ドキュメントやオンラインのリソース、コミュニティなどを活用しながら、さらに深くKotlinの世界を探求していくことをお勧めします。

この解説が、あなたのKotlinジャーニーの素晴らしい出発点となることを願っています。

Happy Coding!

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール