- Kotlin
Kotlin入門|Javaとの違いと基本文法をコピペで学ぶ【2.4対応】
Kotlinとは、JetBrains社が開発した、Javaと同じJVM上で動き、Javaより短く安全に書けるプログラミング言語です。 Javaのライブラリをそのまま呼び出せるため、Javaの知識を活かしながら移行でき、Androidアプリやサーバーサイド開発で広く使われています。
この記事では、2026年10月時点の最新版 Kotlin 2.4.20 のコンパイラで全コードを実行し、出力をそのまま載せています。 Javaの書き方と並べた対比表で違いを押さえ、null安全・data class・拡張関数・スコープ関数などをコピペで試せます。さらに、実際のコンパイルエラー文と直し方、== と === の違いなど、入門時につまずきやすい点もまとめました。
KotlinとJavaの違い早見表
Javaを知っている人が最初に覚えるとよい違いを、1つの表にまとめました。
| やりたいこと | Java | Kotlin | ポイント |
|---|---|---|---|
| 変数(再代入不可) | final String name = "佐藤"; |
val name = "佐藤" |
型は推論される |
| 変数(再代入可) | int stock = 10; |
var stock = 10 |
基本は val、必要なときだけ var |
| null を入れられる型 | すべての参照型 | String? のように ? を付けた型だけ |
付けない型に null は入らない |
| null なら null のまま呼ぶ | s != null ? s.length() : null |
s?.length |
安全呼び出し |
| null なら既定値 | s != null ? s : "未登録" |
s ?: "未登録" |
エルビス演算子 |
| 文字列の埋め込み | "在庫" + n + "個" |
"在庫${n}個" / "$name さん" |
文字列テンプレート |
| 分岐 | switch |
when |
式として値を返す。条件も書ける |
| 範囲 | for (int i = 1; i <= 5; i++) |
for (i in 1..5) |
1..<5、5 downTo 1、step 2 |
| 関数 | int square(int x) { return x * x; } |
fun square(x: Int) = x * x |
式本体で1行に |
| 引数の既定値 | オーバーロードを複数書く | fun order(item: String, qty: Int = 1) |
名前付き引数も使える |
| データ用クラス | record Item(String name, int price) |
data class Item(val name: String, val price: Int) |
copy と分解宣言つき |
| 既存クラスにメソッド追加 | ユーティリティクラスの static メソッド | 拡張関数 fun Int.toYen() |
呼び出しは 12345.toYen() |
| シングルトン | static フィールド+private コンストラクタ | object IdGenerator |
1語で書ける |
| static メソッド | static |
companion object |
クラスに1つ置ける |
| 型の判定とキャスト | if (o instanceof Integer i) |
if (o is Int) → 自動でキャスト |
スマートキャスト |
| 文字列の中身比較 | a.equals(b) |
a == b |
=== が参照の比較 |
| 検査例外 | throws 宣言と catch が必要 |
なし(すべて非検査) | try は式として使える |
| 行末 | ; が必要 |
不要 | |
| リスト操作 | list.stream().filter(...).toList() |
list.filter { ... } |
Stream なしで直接呼べる |
| 非同期処理 | スレッド・CompletableFuture | コルーチン(kotlinx.coroutines) |
ライブラリとして追加 |
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Kotlin入門|Javaとの違いと基本文法をコピペで学ぶ【2.4対応】」
Kotlinの最新版と動かし方
最新バージョン(2026年10月時点)
公式の「Kotlin releases」ページで確認した直近のリリースです。
| バージョン | リリース日 | 種類 |
|---|---|---|
| 2.4.20 | 2026年9月7日 | ツーリングリリース(最新) |
| 2.4.10 | 2026年7月14日 | バグ修正リリース |
| 2.4.0 | 2026年6月3日 | 言語リリース |
| 2.3.0 | 2025年12月16日 | 言語リリース |
Kotlin 2.0 以降は、言語リリース(2.x.0)がおよそ6か月ごと、ツーリングリリース(2.x.20)がその3か月後という周期で出ています。入門で学ぶ基本文法は、どの 2.x でも同じように動きます。
コンパイラを入れて Hello World
IDE(IntelliJ IDEA や Android Studio)なら新規作成するだけで動きます。コマンドラインで試す場合は、GitHub の Kotlin リリースページから kotlin-compiler-2.4.20.zip をダウンロードして展開します。Java(JDK)が必要です。この記事では JDK 21 を使いました。
# 展開したフォルダの bin にある kotlinc を使う
unzip kotlin-compiler-2.4.20.zip
./kotlinc/bin/kotlinc -version
info: kotlinc-jvm 2.4.20 (JRE 21.0.10+7-Ubuntu-124.04)
Hello.kt を作ります。
fun main() {
println("Hello, Kotlin ${KotlinVersion.CURRENT}")
}
# Kotlin の標準ライブラリを含めた jar を作って実行する
./kotlinc/bin/kotlinc Hello.kt -include-runtime -d Hello.jar
java -jar Hello.jar
Hello, Kotlin 2.4.20
Java と違い、クラスを書かずに fun main() だけで動きます。 以降のコードも同じ手順(kotlinc ファイル.kt -include-runtime -d ファイル.jar → java -jar ファイル.jar)で実行しています。
ディストリビューションのパッケージ(apt など)の kotlinc は版が古いことがあるため、最新版で学ぶなら公式の配布物か IDE を使うのがおすすめです。
基本文法:変数・when・範囲・関数
まずは毎日使う基本文法を1ファイルで動かします。
fun main() {
// val(再代入できない)と var(再代入できる)
val name = "佐藤" // 型推論で String
var stock = 10 // 型推論で Int
stock -= 3
val price: Int = 1200 // 型を明示することもできる
println("$name さんの在庫は $stock 個、合計 ${stock * price} 円")
// when(Java の switch より柔軟。式として値を返す)
for (n in listOf(0, 3, 15, -1)) {
val label = when {
n < 0 -> "不正"
n == 0 -> "在庫切れ"
n in 1..5 -> "残りわずか"
else -> "在庫あり"
}
println("when: $n → $label")
}
val kind: Any = 3.5
println("when(型): " + when (kind) {
is Int -> "Int です"
is Double -> "Double です(${kind + 1})" // スマートキャスト
else -> "その他"
})
// 範囲
println("1..5 = ${(1..5).toList()}")
println("1..<5 = ${(1..<5).toList()}")
println("5 downTo 1 step 2 = ${(5 downTo 1 step 2).toList()}")
println("'a'..'e' = ${('a'..'e').joinToString("")}")
// 関数:デフォルト引数と名前付き引数
println(order("ノート"))
println(order("ペン", qty = 3))
println(order(qty = 2, item = "付箋", gift = true))
// 式本体の関数
println("square(7) = ${square(7)}")
// if も式
val max = if (stock > 5) "多い" else "少ない"
println("if式: $max")
// 生文字列(複数行)
val sql = """
SELECT id, name
FROM member
WHERE id = $stock
""".trimIndent()
println(sql)
}
fun order(item: String, qty: Int = 1, gift: Boolean = false): String =
"注文: $item × $qty" + if (gift) "(ギフト包装)" else ""
fun square(x: Int) = x * x
実行結果(Kotlin 2.4.20):
佐藤 さんの在庫は 7 個、合計 8400 円
when: 0 → 在庫切れ
when: 3 → 残りわずか
when: 15 → 在庫あり
when: -1 → 不正
when(型): Double です(4.5)
1..5 = [1, 2, 3, 4, 5]
1..<5 = [1, 2, 3, 4]
5 downTo 1 step 2 = [5, 3, 1]
'a'..'e' = abcde
注文: ノート × 1
注文: ペン × 3
注文: 付箋 × 2(ギフト包装)
square(7) = 49
if式: 多い
SELECT id, name
FROM member
WHERE id = 7
| 文法 | 押さえるポイント |
|---|---|
val / var |
迷ったら val。 再代入が必要なときだけ var にすると、値が途中で変わる心配が減る |
| 文字列テンプレート | 変数は $name、式は ${stock * price} |
when |
引数なしの when { 条件 -> 値 } で if-else の連続を置き換えられる。is で型の判定もでき、判定後は自動でその型として使える |
| 範囲 | 1..5 は5を含む、1..<5 は5を含まない |
| デフォルト引数・名前付き引数 | オーバーロードを何個も書かずに済む。 名前付きなら順番も自由 |
if / when は式 |
結果を変数に直接入れられるので、Java の三項演算子は不要 |
生文字列 """ |
複数行の文字列。trimIndent() で先頭の共通インデントを除去 |
null安全:? ・ ?. ・ ?: ・ !! の使い分け
Kotlin の最大の特徴が null 安全 です。型に ? が付いていない変数には null を入れられないので、NullPointerException(NPE)の多くをコンパイル時に防げます。
fun findEmail(id: Int): String? = if (id == 1) "sato@example.com" else null
fun main() {
val a: String? = findEmail(1)
val b: String? = findEmail(2)
// ?. 安全呼び出し:null なら null のまま
println("a?.length = ${a?.length}")
println("b?.length = ${b?.length}")
// ?: エルビス演算子:null なら右側を使う
println("b ?: 既定値 = ${b ?: "未登録"}")
val len = b?.length ?: 0
println("b?.length ?: 0 = $len")
// if で null チェックするとスマートキャストで String として扱える
if (a != null) println("スマートキャスト: ${a.uppercase()}")
// let と組み合わせる
a?.let { println("let: メール送信 → $it") }
b?.let { println("ここは呼ばれない") }
// 安全キャスト as?
val x: Any = "123"
println("as? Int = ${x as? Int}")
// !! は null なら NullPointerException
try {
println(b!!.length)
} catch (e: NullPointerException) {
println("!! で例外: $e")
}
// null を除いてリストにする
val ids = listOf(1, 2, 1)
println("mapNotNull = ${ids.mapNotNull { findEmail(it) }}")
// == と ===
val s1 = String(charArrayOf('a', 'b'))
val s2 = "ab"
println("s1 == s2 : ${s1 == s2}") // 中身の比較(equals)
println("s1 === s2 : ${s1 === s2}") // 同じオブジェクトか
val n1: String? = null
println("null == \"ab\" : ${n1 == "ab"}") // null でも NPE にならない
}
実行結果:
a?.length = 16
b?.length = null
b ?: 既定値 = 未登録
b?.length ?: 0 = 0
スマートキャスト: SATO@EXAMPLE.COM
let: メール送信 → sato@example.com
as? Int = null
!! で例外: java.lang.NullPointerException
mapNotNull = [sato@example.com, sato@example.com]
s1 == s2 : true
s1 === s2 : false
null == "ab" : false
| 記号 | 名前 | 意味 | 使う場面 |
|---|---|---|---|
String? |
null 許容型 | null を入れてよい型 | 見つからない可能性がある戻り値など |
a?.length |
安全呼び出し | a が null なら結果も null | null の可能性がある値のメソッドを呼ぶ |
a ?: "既定" |
エルビス演算子 | null なら右側 | 既定値を決める、?: return で早期リターン |
a?.let { } |
安全呼び出し+let | null でないときだけ処理 | null でなければ送信・保存する |
x as? Int |
安全キャスト | キャストできなければ null | 型が不確かな値の変換 |
a!! |
非 null 表明 | null なら NPE | 確実に null でないと言えるときだけ |
!! は「ここは絶対に null ではない」と宣言する演算子で、外れると NPE になります。 まずは ?. と ?: で書き、!! は最後の手段にするのが Kotlin らしい書き方です。
== と === の違い
| 演算子 | 比較するもの | Java での書き方 |
|---|---|---|
== |
中身(equals)。null 同士も安全に比較 | Objects.equals(a, b) |
=== |
同じオブジェクトか(参照) | a == b |
Java の == は Kotlin の === に当たるので、Java から来た人は逆に感じやすい点です。文字列やデータの比較には普段どおり == を使えば中身で比べられます。
クラス:data class・拡張関数・object・sealed
// data class:equals / hashCode / toString / copy / 分解宣言 が自動生成
data class Item(val name: String, val price: Int, val qty: Int = 1)
// 拡張関数:既存クラスにメソッドを足したように書ける
fun Int.toYen(): String = "%,d円".format(this)
val Item.total: Int get() = price * qty // 拡張プロパティ
// object:シングルトン
object IdGenerator {
private var next = 1
fun nextId() = next++
}
// companion object:Java の static の代わり
class Member private constructor(val id: Int, val name: String) {
companion object {
fun create(name: String) = Member(IdGenerator.nextId(), name)
}
override fun toString() = "Member(id=$id, name=$name)"
}
// sealed class / sealed interface:when で全パターンを網羅チェックできる
sealed interface Result
data class Success(val value: Int) : Result
data class Failure(val message: String) : Result
data object Loading : Result
fun describe(r: Result): String = when (r) {
is Success -> "成功: ${r.value}"
is Failure -> "失敗: ${r.message}"
Loading -> "読み込み中"
}
fun main() {
val a = Item("ノート", 300, 2)
val b = a.copy(qty = 5)
println(a)
println("copy → $b")
println("a == Item(\"ノート\", 300, 2) : ${a == Item("ノート", 300, 2)}")
val (name, price) = a
println("分解宣言: name=$name price=$price")
println("拡張: ${12345.toYen()} / 合計=${b.total.toYen()}")
println(Member.create("佐藤"))
println(Member.create("鈴木"))
listOf(Success(10), Failure("在庫不足"), Loading).forEach { println(describe(it)) }
}
実行結果:
Item(name=ノート, price=300, qty=2)
copy → Item(name=ノート, price=300, qty=5)
a == Item("ノート", 300, 2) : true
分解宣言: name=ノート price=300
拡張: 12,345円 / 合計=1,500円
Member(id=1, name=佐藤)
Member(id=2, name=鈴木)
成功: 10
失敗: 在庫不足
読み込み中
| 機能 | Java で近いもの | Kotlin で得られること |
|---|---|---|
data class |
record(Java 16以降)、Lombok の @Data | copy(qty = 5) で一部だけ変えた複製、val (name, price) = a の分解宣言 |
| 拡張関数・拡張プロパティ | static なユーティリティメソッド | 12345.toYen() のように元のクラスのメソッドのように呼べる(元のクラスは変更しない) |
object |
シングルトンパターン | 1語でスレッドセーフなシングルトン |
companion object |
static メソッド・static フィールド | ファクトリメソッドを置く場所として使いやすい |
sealed interface |
sealed interface(Java 17以降) | when で全パターンを書けば else が不要。 種類を増やすと書き漏れがコンパイルエラーで分かる |
data object |
― | toString が Loading のように読みやすくなるシングルトン |
ラムダとコレクション操作
Kotlin のコレクションは、Stream を経由せずに直接 filter や map を呼べます。 ラムダの引数が1つなら it で参照できます。
data class Item(val name: String, val price: Int, val qty: Int = 1)
val Item.total: Int get() = price * qty
fun main() {
val items = listOf(
Item("ノート", 300, 2), Item("ペン", 120, 10), Item("付箋", 200, 3), Item("ファイル", 450, 1))
println("filter : ${items.filter { it.price >= 200 }.map { it.name }}")
println("sumOf : ${items.sumOf { it.total }}")
println("sorted : ${items.sortedByDescending { it.total }.map { "${it.name}=${it.total}" }}")
println("groupBy : ${items.groupBy { if (it.price >= 300) "高" else "低" }.mapValues { e -> e.value.map { it.name } }}")
println("associate: ${items.associate { it.name to it.qty }}")
println("any/all : ${items.any { it.qty > 5 }} / ${items.all { it.price > 100 }}")
println("first : ${items.first { it.price < 150 }}")
println("firstOrNull: ${items.firstOrNull { it.price > 1000 }}")
// 可変と不変のコレクション
val fixed = listOf(1, 2, 3) // 追加メソッドなし
val box = mutableListOf(1, 2, 3)
box += 4
println("listOf=$fixed mutableListOf=$box")
val stock = mapOf("ノート" to 5, "ペン" to 0)
println("map[ノート]=${stock["ノート"]} map[消しゴム]=${stock["消しゴム"]} getOrDefault=${stock.getOrDefault("消しゴム", 0)}")
}
実行結果:
filter : [ノート, 付箋, ファイル]
sumOf : 2850
sorted : [ペン=1200, ノート=600, 付箋=600, ファイル=450]
groupBy : {高=[ノート, ファイル], 低=[ペン, 付箋]}
associate: {ノート=2, ペン=10, 付箋=3, ファイル=1}
any/all : true / true
first : Item(name=ペン, price=120, qty=10)
firstOrNull: null
listOf=[1, 2, 3] mutableListOf=[1, 2, 3, 4]
map[ノート]=5 map[消しゴム]=null getOrDefault=0
| やりたいこと | Kotlin | Java(Stream) |
|---|---|---|
| 条件で絞る | filter { it.price >= 200 } |
.stream().filter(i -> i.price() >= 200).toList() |
| 変換する | map { it.name } |
.stream().map(Item::name).toList() |
| 合計 | sumOf { it.total } |
.mapToInt(...).sum() |
| 並べ替え | sortedByDescending { it.total } |
.sorted(Comparator.comparing(...).reversed()) |
| グループ化 | groupBy { ... } |
Collectors.groupingBy(...) |
| Map にする | associate { it.name to it.qty } |
Collectors.toMap(...) |
| 最初の1件(なければ null) | firstOrNull { ... } |
.filter(...).findFirst() → Optional |
| 不変リスト | listOf(...) |
List.of(...) |
| 可変リスト | mutableListOf(...) |
new ArrayList<>(...) |
listOf は読み取り専用、mutableListOf は追加・削除ができると型で区別されます。to は Pair を作る書き方で、mapOf("ノート" to 5) のように Map の初期化でよく使います。Map の stock["消しゴム"] は、キーがなければ null を返します。
スコープ関数 let・apply・also・run・with
スコープ関数は、オブジェクトに対する処理を1つのブロックにまとめるための関数です。5つあり、違いは「ブロック内でオブジェクトを it と this のどちらで呼ぶか」と「戻り値がオブジェクト自身か、ブロックの結果か」の2点だけです。
data class Item(val name: String, val price: Int, val qty: Int = 1)
fun main() {
val a = Item("ノート", 300, 2)
val items = listOf(a, Item("ペン", 120, 10), Item("付箋", 200, 3), Item("ファイル", 450, 1))
val sb = StringBuilder().apply { append("在庫"); append("一覧") } // 戻り値はレシーバ
println("apply → $sb")
val len = "kotlin".let { it.length * 2 } // 戻り値はラムダの結果
println("let → $len")
val list = mutableListOf("A").also { println("also → 追加前 $it") }.apply { add("B") }
println("also+apply → $list")
val summary = with(items) { "件数=$size 先頭=${first().name}" } // レシーバを this に
println("with → $summary")
val r = a.run { "$name を $qty 個" } // this で参照し結果を返す
println("run → $r")
}
実行結果:
apply → 在庫一覧
let → 12
also → 追加前 [A]
also+apply → [A, B]
with → 件数=4 先頭=ノート
run → ノート を 2 個
| 関数 | ブロック内での参照 | 戻り値 | よく使う場面 |
|---|---|---|---|
let |
it |
ブロックの結果 | null でないときだけ処理(x?.let { })、値の変換 |
apply |
this |
オブジェクト自身 | 生成直後の設定(ビルダー的な初期化) |
also |
it |
オブジェクト自身 | ログ出力・検証など「ついでの処理」 |
run |
this |
ブロックの結果 | オブジェクトを使って計算した結果がほしい |
with(obj) |
this |
ブロックの結果 | 1つのオブジェクトのメソッドを続けて呼ぶ |
迷ったら、null チェックは let、初期化は apply、ログは also の3つから覚えると十分です。入れ子にすると it や this が何を指すか分かりにくくなるので、1段までにしておくと読みやすくなります。
よくあるコンパイルエラーと直し方
Kotlin は多くのミスをコンパイル時に知らせてくれます。次のコードを kotlinc 2.4.20 でコンパイルしたときの、実際のエラー文です(エラー位置を示す ^ の行は省略しています)。
sealed interface Result
data class Success(val value: Int) : Result
data class Failure(val message: String) : Result
fun findEmail(id: Int): String? = null
fun describe(r: Result): String = when (r) {
is Success -> "成功"
}
fun main() {
val count = 1
count = 2
val email = findEmail(1)
println(email.length)
val n: Int = "10"
var s: String = null
}
Err.kt:7:35: error: 'when' expression must be exhaustive. Add the 'is Failure' branch or an 'else' branch.
Err.kt:13:5: error: 'val' cannot be reassigned.
Err.kt:15:18: error: only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type 'String?'.
Err.kt:16:16: error: initializer type mismatch: expected 'Int', actual 'String'.
Err.kt:17:21: error: null cannot be a value of a non-null type 'String'.
| エラー文 | 原因 | 直し方 |
|---|---|---|
'when' expression must be exhaustive |
sealed の when で書いていない種類がある | is Failure -> ... を追加(else より全種類を書く方が追加漏れに気づける) |
'val' cannot be reassigned |
val に再代入した | 本当に変える必要があれば var に。多くは新しい val を作る方が読みやすい |
only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver |
String? のまま .length を呼んだ |
email?.length、email?.length ?: 0、または if (email != null) で囲む |
initializer type mismatch: expected 'Int', actual 'String' |
型が合わない | "10".toInt()、失敗しうるなら "10".toIntOrNull() |
null cannot be a value of a non-null type 'String' |
? なしの型に null |
var s: String? = null、または後から必ず入れるなら lateinit var |
実行時につまずきやすい3つ
fun main() {
// Java のメソッドの戻り値は「プラットフォーム型」(String!)。null チェックがコンパイル時に効かない
val home: String? = System.getenv("NO_SUCH_VAR") // String? で受けると安全
println("String? で受ける: ${home?.length ?: "未設定"}")
try {
val raw = System.getenv("NO_SUCH_VAR") // 型を書かないと String! のまま
println(raw.length)
} catch (e: NullPointerException) {
println("型を書かずに受けた場合: ${e::class.simpleName}")
}
// 文字列 → 数値
println("\"42\".toInt() = ${"42".toInt()}")
println("\"abc\".toIntOrNull() = ${"abc".toIntOrNull()}")
try { "abc".toInt() } catch (e: NumberFormatException) { println("toInt: ${e.message}") }
// lateinit:後から初期化する var
val s = Service()
try { s.show() } catch (e: UninitializedPropertyAccessException) { println("lateinit: ${e.message}") }
s.name = "在庫サービス"; s.show()
}
class Service {
lateinit var name: String
fun show() = println("name=$name")
}
実行結果:
String? で受ける: 未設定
型を書かずに受けた場合: NullPointerException
"42".toInt() = 42
"abc".toIntOrNull() = null
toInt: For input string: "abc"
lateinit: lateinit property name has not been initialized
name=在庫サービス
| つまずき | 起きること | 書き方のコツ |
|---|---|---|
| Java のメソッドの戻り値 | プラットフォーム型(String!)になり、null チェックがコンパイル時に効かない |
null の可能性があれば val x: String? = javaMethod() と型を書いて受ける |
toInt() |
数字でなければ NumberFormatException | 入力値には toIntOrNull() ?: 0 |
lateinit |
代入前に読むと UninitializedPropertyAccessException | 初期化のタイミングが決まっている場合(DI・テストの準備)に限って使う |
!! の多用 |
null のときに NPE | ?.・?:・let に置き換える |
Kotlin でも NPE が起きるのは、主に !!・Java との境界・lateinit の3か所です。この3つを意識しておけば、null 安全の恩恵を十分に受けられます。
コルーチンの概要(未実行)
Kotlin では非同期処理に コルーチン(中断と再開ができる軽量な処理単位)を使います。言語本体ではなく kotlinx-coroutines-core ライブラリとして追加します。この記事の検証環境ではライブラリを取得できなかったため、次のコードは公式ドキュメントの書き方に沿った例で、実行はしていません。
import kotlinx.coroutines.*
suspend fun fetchStock(): Int { delay(300); return 12 } // suspend:中断できる関数
suspend fun fetchMember(): String { delay(300); return "佐藤" }
fun main() = runBlocking {
val stock = async { fetchStock() } // 2つを並行に開始
val member = async { fetchMember() }
println("${member.await()} さんの在庫 ${stock.await()} 個") // 約300msで両方そろう
}
| 用語 | 意味 | Java で近いもの |
|---|---|---|
suspend fun |
途中で中断・再開できる関数 | ― |
runBlocking |
コルーチンが終わるまで現在のスレッドで待つ(main やテスト用) | join() |
launch |
結果を返さないコルーチンを開始 | runAsync |
async / await |
結果を返すコルーチンを開始し、後で受け取る | supplyAsync / join |
delay |
スレッドを止めずに待つ | Thread.sleep(こちらはスレッドを止める) |
Gradle(Kotlin DSL)での構成の要点
本格的に開発するときは Gradle を使います。ビルドスクリプトも Kotlin で書ける(Kotlin DSL、build.gradle.kts)のが特徴です。最小構成の要点だけ示します。Groovy DSL との対訳や依存関係の書き方の詳細は「build.gradle書き方」の記事で扱っています。
// build.gradle.kts(最小構成の例)
plugins {
kotlin("jvm") version "2.4.20"
application
}
repositories { mavenCentral() }
kotlin { jvmToolchain(21) } // 使う JDK のバージョン
application { mainClass = "MainKt" } // Main.kt の main 関数
| 項目 | 要点 |
|---|---|
| ソースの置き場所 | src/main/kotlin(テストは src/test/kotlin) |
Main.kt の main |
クラス名は MainKt になる(ファイル名+Kt) |
| 実行 | ./gradlew run |
| Java との混在 | 同じプロジェクトに src/main/java を置いて相互に呼び出せる |
よくある質問
Q. KotlinはJavaを知らなくても学べますか? A. 学べます。Kotlin だけで文法は完結しています。ただし、Kotlin は Java のライブラリを使う場面が多いので、Java の標準ライブラリ(List・Map・例外など)の名前を知っていると理解が速くなります。 Java 経験者なら、この記事の早見表の違いを押さえるだけで読み書きを始められます。
Q. KotlinとJavaは同じプロジェクトで混在できますか?
A. できます。Kotlin から Java のクラスを、Java から Kotlin のクラスを、そのまま呼び出せます。 既存の Java コードを残したまま、新しいファイルだけ Kotlin で書く移行のしかたがよく取られます。Java の戻り値を受け取るときは、null の可能性に応じて String? などの型を明示すると安全です。
Q. valとvarはどちらを使えばよいですか? A. 基本は val です。再代入できない変数が多いほど、値がどこで変わるかを追う必要がなくなり、コードが読みやすくなります。ループのカウンタや、状態を積み上げる変数など、再代入が必要な場合だけ var を使います。
Q. Kotlinの最新版はどこで確認できますか? A. 公式サイト(kotlinlang.org)の「Kotlin releases」ページに、バージョンとリリース日の一覧があります。2026年10月時点の最新は 2.4.20(2026年9月7日) です。
まとめ
- Kotlin は JVM で動き、Java のライブラリをそのまま使える言語。最新版は 2.4.20(2026年9月)
- 変数は val(再代入不可)を基本に、必要なときだけ var。型は推論される
- null 安全は
?・?.・?:の3つで書き、!!は最後の手段 ==は中身、===は参照の比較。Java の==は Kotlin の===に当たる- data class・拡張関数・sealed・object で、Java より短く安全にクラスを書ける
- スコープ関数は let(null チェック)・apply(初期化)・also(ログ)から覚える
- NPE が起きやすいのは
!!・Java との境界・lateinit の3か所
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Kotlin入門|Javaとの違いと基本文法をコピペで学ぶ【2.4対応】」
株式会社RJCでは、Kotlinの基本文法を仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。