web-dev-qa-db-ja.com

Javaの不変リストでもあるKotlinで不変リストを作成するにはどうすればよいですか?

Java/Kotlinの相互運用に問題があります。 Kotlinの不変リストは、可変の通常のJava.util.ArrayListにコンパイルされます。

Kotlin(ライブラリ):

class A {
  val items: List<Item> = ArrayList()
}

Java(消費者):

A a = new A();
a.getItems().add(new Item());   // Compiles and runs but I wish to fail or throw

KotlinクラスをJavaの観点からも完全に不変にする方法は?

10
WindRider

Kotlinのすべての非Mutable____コレクションはコンパイル時の読み取り専用タイプデフォルトですが、不変ではありません。次のコードスニペットを参照してください。

fun main(args: Array<String>) {
  // Explanation for ArrayList(listOf()) later down the post
  val list: List<Int> = ArrayList(listOf(1, 2, 3))
  println(list) // [1, 2, 3]

  // Fails at compile time
  // list.add(4)

  // Uh oh! This works at runtime!
  (list as MutableList<Int>).add(4)
  println(list) // [1, 2, 3, 4]
}

本当に不変のリストを作成するには、GuavaのImmutable____コレクションを検討してください。

import com.google.common.collect.ImmutableList

fun main(args: Array<String>) {
  val list: List<Int> = ImmutableList.of(1, 2, 3)
  println(list) // [1, 2, 3]

  // Fails at compile time
  // list.add(4)

  // Fails at runtime, as expected
  (list as MutableList<Int>).add(4)
  println(list) // [1, 2, 3, 4]
}

Kotlinの標準ランタイム関数の一部は、変更不可能、サイズ変更不可能などのコレクションを返す可能性があるため、読み取り専用コレクションを変更可能なコレクションに直接キャストすると、すべての賭けが無効になることに注意してください。

たとえば、listOf()現在(これは将来変更される可能性があります!)は、Arrays.asList(T...)を介してvarargパラメータの配列の周りにJava.util.Arrays.ArrayListを返します。この「リスト」は変更できますが、配列のサイズを変更できないため、要素を追加または削除することはできません。詳細については、 Arrays.asList(T...) javadoc を参照してください。

特定のコレクションから変更可能なコレクションが本当に必要な場合は、.toMutableList()を使用してコピーを作成することを検討してください。これはどのコレクションでも機能します。

import com.google.common.collect.ImmutableList

fun main(args: Array<String>) {
  val list: List<Int> = ImmutableList.of(1, 2, 3)

  val copy = list.toMutableList()
  copy.add(4)

  println(copy) // [1, 2, 3, 4]
  println(list) // [1, 2, 3]
}
18
F. George