Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create an immutable list in Kotlin that is also an immutable list in Java?

I have a Java/Kotlin interop problem. A Kotlin immutable list is compiled into a normal java.util.ArrayList that is mutable!

Kotlin (library):

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

Java (consumer):

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

How to make my Kotlin class fully immutable from Java perspective too?

like image 280
WindRider Avatar asked Nov 12 '16 15:11

WindRider


People also ask

How do you make a list immutable on Kotlin?

Using listOf() function The listOf() function returns an immutable list of the given elements, which does not permit the addition or removal of elements. This is similar to Arrays. asList() function in Java. To get an immutable list with all null elements excluded, you can use the listOfNotNull() function.

Can we make list immutable in Java?

In Java, use of() with Set, Map or List to create an Immutable List.

Which of the following declares an unchangeable list of strings in Kotlin?

Kotlin has two types of lists, immutable lists (cannot be modified) and mutable lists (can be modified). Read-only lists are created with listOf() whose elements can not be modified and mutable lists created with mutableListOf() method where we alter or modify the elements of the list.

Is Kotlin immutable by default?

Unlike Java, in Kotlin all the params are by default immutable. And there is no way to make them mutable.


Video Answer


1 Answers

All non-Mutable____ collections in Kotlin are compile time read-only types by default, but not immutable. See the following code snippet:

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]
}

To truly have an immutable list, consider Guava's Immutable____ collections:

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]
}

Be aware that some of Kotlin's standard runtime function may return collections that are either unmodifiable, not resizable, etc., so all bets are off when you directly cast a read-only collection to a mutable one.

For example, listOf() currently (this may change in the future!) returns a java.util.Arrays.ArrayList around the array of vararg parameters via Arrays.asList(T...). This "list" can be modified, but elements can never be added or removed, as you cannot resize an array. See Arrays.asList(T...) javadoc for more information.

If you really want a mutable collection from any given collection, consider making a copy using .toMutableList(). This will work on any collection:

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]
}
like image 156
F. George Avatar answered Oct 05 '22 05:10

F. George