Kotlinのvalについて

採用はこちら

Kotlinを学び始めると、ほぼ必ず目にするキーワードが val です。

一見すると「varと何が違うのか」「Javaのfinalと同じなのか」と疑問に感じる方も多いでしょう。

結論から言うと、valKotlinの設計思想そのものを体現した重要なキーワード です。

単なる構文ではなく、安全性・可読性・保守性を高めるための基本戦略として使われます。

本記事では、valについて 基礎 → 応用 → 設計思想 → 実務での使い方 まで、体系的に解説します。

目次

valの基本的な意味

val再代入できない変数(読み取り専用の参照) を宣言するためのキーワードです。

val x = 10
x = 20 // コンパイルエラー
  • valvalue の略
  • 最初に代入した値を、後から別の値に変更できない
  • Kotlinでは 変数宣言の第一選択肢

valvar の違い

Kotlinでは変数宣言に valvar の2種類があります。

キーワード再代入用途
val 不可不変の参照
var可変の参照
var count = 0
count += 1 // OK

val total = 100
// total += 1 // NG

Kotlin流の考え方

「まず val で書けないかを考え、どうしても必要な場合だけ var を使う」

これはKotlin公式ドキュメントや実務でも広く共有されている指針です。

val は定数ではない

非常によくある誤解ですが、valは定数ではありません

val now = System.currentTimeMillis()
  • 実行時に決まる値でも問題なし
  • 「一度しか代入できない」だけ

コンパイル時定数は const val

const val MAX_COUNT = 100

const val は以下の条件を満たす必要があります。

  • コンパイル時に値が確定する
  • 型はプリミティブ型相当または String
  • トップレベル、または object 内で宣言する
const val NAME = "Kotlin" // OK
// const val list = listOf(1, 2, 3) // NG

valでもオブジェクトの中身は変更できる

val参照の再代入を禁止するだけ です。

オブジェクト自体がミュータブルであれば、その中身は変更できます。

val list = mutableListOf(1, 2, 3)
list.add(4) // OK

これは次の操作だけが禁止されているためです。

list = mutableListOf(9, 9, 9) // NG(再代入)

完全に不変にしたい場合

val list = listOf(1, 2, 3)
// list.add(4) // コンパイルエラー

valとイミュータブル設計

Kotlinが val を強く推奨する理由は、バグを減らすためです。

fun calculate(price: Int): Int {
    val tax = price * 10 / 100
    return price + tax
}

このコードでは、

  • taxが途中で変更されない
  • 関数の処理が読みやすい
  • 意図しない副作用が起きない

という利点があります。

なぜ重要か?

  • 変更されない値は 思考コストが低い
  • 並行処理や非同期処理でも安全
  • レビュー時に「この値は変わらない」と即座に分かる

valとスマートキャストの関係

Kotlinには スマートキャスト という仕組みがあります。

val obj: Any = "Hello"

if (obj is String) {
    println(obj.length)
}

これは、

  • objval
  • ifブロック内で型が変わらないとコンパイラが保証できる

ために成立します。

補足(重要)

  • varでも、途中で変更されないと解析できる場合はスマートキャストされる
  • ただし val の方が 安定してスマートキャストが効く
  • プロパティやマルチスレッドが絡むと var は効かなくなることが多い

クラスプロパティとしての val

class User(
    val name: String,
    val age: Int
)
  • 外部からは読み取り専用
  • データクラスやDTOで多用される
val user = User("Taro", 20)
println(user.name)
// user.age = 30 // NG

計算プロパティとの相性も良い

val isAdult: Boolean
    get() = age >= 20
  • 状態を持たない
  • 常に正しい値を返す

lateinitval は併用できない

lateinit val name: String // コンパイルエラー

理由は明確で、

  • lateinit:後から代入する前提
  • val:一度しか代入できない

代替案

val name: String by lazy {
    loadName()
}

valは「後から1回だけ代入」できる(ローカル変数)

ローカル変数に限り、次のような書き方も可能です。

val x: Int
x = 10 // 初回代入はOK
// x = 20 // NG
  • 使用前に必ず代入されている必要あり
  • 「初期化を遅らせたいが再代入は不要」なケースで有効

実務でのベストプラクティス

実務指針まとめ

  • 基本はすべて val
  • 状態が変わる必要があるときだけ var
  • コレクションは
    • 参照:val
    • 中身:用途に応じて可変 / 不変を選択
  • public API・モデルクラスでは val を優先

悪い例

var userName = "Taro" // 変更しないなら不要

良い例

val userName = "Taro"

Javaとの比較で理解する

JavaKotlin
final int x = 10;val x = 10
冗長簡潔
null安全なしnull安全あり(型で管理)

まとめ

  • val再代入不可の参照
  • 定数ではない(定数は const val
  • オブジェクトの中身は変えられる
  • Kotlinでは まず val が基本
  • 安全・可読・保守性を支える中核概念

以上、Kotlinのvalについてでした。

最後までお読みいただき、ありがとうございました。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次