Kotlinの文字列比較について

採用はこちら

Kotlinにおける文字列比較は非常に洗練されており、Javaよりも安全で簡潔に書ける一方、仕様を正しく理解していないと誤用につながります。

この記事では、

  • Kotlin公式仕様に沿った正確な説明
  • Javaとの違い
  • 実務での推奨パターン
  • よくある誤解・アンチパターン

を踏まえ、「もう迷わない」レベルまで詳しく解説します。

目次

KotlinのStringの基本仕様

KotlinのStringは次の特徴を持ちます。

  • イミュータブル(不変)
  • JVMでは java.lang.String と完全互換
  • 値比較と参照比較が明確に分離されている
  • null安全な比較が標準で可能

特に重要なのが、演算子 == の意味がJavaと異なる点です。

===== の違い(最重要)

==:構造的等価(値・内容の比較)

val a = "Kotlin"
val b = "Kotlin"

println(a == b) // true
  • 文字列の中身(内容)が同じかを比較
  • 内部的には equals() が呼ばれる
  • null安全

実際には、次のように変換されます。

a == b
// ↓
a?.equals(b) ?: (b === null)

nullを含む場合

val a: String? = null
val b: String? = null

println(a == b) // true
val a: String? = null
println(a == "Kotlin") // false(例外なし)

NullPointerExceptionが起きないのがKotlinの大きな強みです。

===:参照等価(同一インスタンスか)

val a = "Kotlin"
val b = String("Kotlin".toCharArray())

println(a === b) // false
  • メモリ上で同じオブジェクトかを比較
  • 実務で使うことはほぼない
  • テスト・最適化・特殊なケース向け

文字列比較に === を使うのは基本的に誤りです。

Javaとの決定的な違い

Java

if (a.equals(b)) { ... }

Kotlin

if (a == b) { ... }

Kotlinでは
== が値比較」
equals() を直接呼ぶ必要はほぼない」

という設計思想になっています。

大文字・小文字を無視した比較

equals(ignoreCase = true)(基本かつ安全)

val a = "kotlin"
val b = "KOTLIN"

println(a.equals(b, ignoreCase = true)) // true
  • Kotlinが提供する正規のAPI
  • ASCII中心の比較に安全
  • nullableでも使用可能(String?に定義されている)

大小無視の比較はこれが第一選択

lowercase() / uppercase() の正しい理解(重要修正版)

よくある誤解

lowercase() はロケール依存で危険」
「トルコ語問題が起きやすい」

これは 現在のKotlinの推奨仕様とは異なります。

正しい仕様

  • 旧API
    • toLowerCase() / toUpperCase()
      デフォルトロケール依存・非推奨
  • 新API(Kotlin 1.5以降)
    • lowercase() / uppercase()
      不変ロケール(invariant locale)を使用=ロケール非依存
val a = "KOTLIN"
println(a.lowercase()) // kotlin

これは ID・キー・タグ・プロトコル値の正規化に最適です。

ロケールを考慮すべきケース

ユーザー向け表示、自然言語処理などでは ロケールを明示します。

import java.util.Locale

text.lowercase(Locale.getDefault())

使い分け指針

用途推奨
プログラム内部の比較equals(ignoreCase = true)
正規化・キー化lowercase()
表示・言語依存処理lowercase(Locale)
toLowerCase()❌ 非推奨

辞書順(順序)比較

compareTo()

val a = "apple"
val b = "banana"

println(a.compareTo(b)) // 負の値
  • 0 → 等しい
  • 負数 → 左が小さい
  • 正数 → 左が大きい

演算子で書ける(Kotlinらしい)

println(a < b)  // true
println(a > b)  // false

注意(nullable)

val a: String? = "apple"
val b: String? = "banana"

a < b // コンパイルエラー

順序比較はnull安全ではない
必要ならnullチェックやElvis演算子を使う

部分一致・前方一致・後方一致

"Hello Kotlin".contains("Kotlin")     // true
"Hello Kotlin".startsWith("Hello")    // true
"Hello Kotlin".endsWith("Kotlin")     // true

すべて ignoreCase = true を指定可能。

正規表現による比較

val regex = Regex("\\d{3}-\\d{4}")

regex.matches("123-4567")        // 完全一致
regex.containsMatchIn("ID:123")  // 部分一致

入力バリデーションやフォーマット確認に便利です。

よくあるアンチパターン

=== を使う

if (a === b) { ... } // 誤用

Javaの癖で equals() を多用

a.equals(b) // Kotlinでは冗長なことが多い

非推奨APIの使用

a.toLowerCase() // 非推奨

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

目的推奨
通常比較a == b
null含む比較a == b
大小無視a.equals(b, true)
正規化lowercase()
辞書順a < b
入力検証Regex

Web・アプリ開発での実践ポイント

  • ユーザー入力は trim() してから比較
  • APIレスポンスは仕様通りに正規化
  • 比較ルール(大小無視など)は仕様として固定
  • 表示処理と内部ロジックの比較を混同しない

まとめ

Kotlinの文字列比較は、

  • 安全
  • 簡潔
  • 意図が明確

という強力な設計になっています。

== を恐れず使い、=== を正しく避け、ロケールと正規化を意識すれば、文字列比較でバグることはほぼなくなります。

以上、Kotlinの文字列比較についてでした。

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

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