4

I'm trying to make code that follows the functional programming paradigm, which follows immutability very religiously, but the only way I know how to make my array even close to being immutable is by using

List<Integer> items = Collections.unmodifiableList(Arrays.asList(0,1,2,3));

I am unsure whether this makes the array immutable or just unmodifiable. If the command above does not make the array immutable what would?

Krzysztof Atłasik
  • 21,985
  • 6
  • 54
  • 76
Thezi
  • 157
  • 1
  • 5
  • 1
    [There’s basically no true immutability in Java.](https://stackoverflow.com/questions/57981224/can-i-have-stringbuilder-in-an-immutable-class) – jaco0646 Sep 24 '19 at 18:35
  • 2
    what do you call "an array"? you don't have one here... – Andrew Tobilko Sep 24 '19 at 18:37
  • @AndrewTobilko there is an array created when invoking the varargs method `Arrays.asList`. – Holger Sep 25 '19 at 08:45
  • @Holger I understand it, but the OP never initialised one on their own. I presumed that by "arrays" they actually meant "`List`s" – Andrew Tobilko Sep 25 '19 at 08:48
  • @AndrewTobilko since Java has no true immutable arrays, the only way to get them, is via a wrapper object. Which might conveniently implement `List`. The inlined syntax, whether you use `Arrays.asList(0,1,2,3)` or `Arrays.asList(new Integer[] {0,1,2,3})` ensures that no other reference to the array exists. Since that’s the right approach, I wouldn’t presume that the OP didn’t understand this. That’s not recognizable from the question. – Holger Sep 25 '19 at 08:54

2 Answers2

3
  1. You can't mutate the underlying array (or the list returned by Arrays.asList) except by reflection. However, arrays aren't really relevant here; don't confuse arrays and lists!

  2. Since Java 9, List.of(0, 1, 2, 3) achieves the same.

  3. To do operations which produce new collections, you'll have to go through streams. You may also want to consider third-party libraries, e.g. Guava (this link is to their immutable collections page). Or even better PCollections, which provides only immutable collections and more functional implementations of them than Guava does.

Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487
  • Basic things like `concat`, `filter` or `map`? You can get them in Java standard library through streams, but not with an immutable collection as output as OP wants. – Alexey Romanov Sep 25 '19 at 14:29
  • One more thing. It might be better to be explicit about the scenario for the first point, e.g. “If you don’t keep a reference, like with your `Arrays.asList(0,1,2,3)`, you can't mutate the underlying array”. – Holger Sep 26 '19 at 07:36
3

The problem with using Collections.unmodifiableList is that you're not really creating a read-only view on mutable collection, not real immutable collection. It might seem like it's not a big deal, but in reality, the mutable collection acting as immutable won't be very efficient and performant. For example, appending the new element to the list would require copying the whole list.

I would suggest you check out Vavr. It has its own implementation of functional, immutable linked list, which allows you to do appends on constant time (which doesn't require copying whole list, because common elements are shared). For example:

var l1 = List.of(1, 2, 3); //List(1, 2, 3)
var l2 = l1.append(4);     //List(1, 2, 3, 4)

In this example both list would share 1,2,3.

You can also convert from and to Java List easily:

java.util.List<String> javaList = Arrays.asList("Java", "Haskell", "Scala");
List<String> vavrList = List.ofAll(javaList);

List<String> vavrStringList = List.of("JAVA", "Javascript", "Scala");
java.util.List<String> javaStringList = vavrStringList.toJavaList();
Krzysztof Atłasik
  • 21,985
  • 6
  • 54
  • 76
  • 1
    One “not really” too much? Besides, having a fast append operation via linking sounds good, as long as you don’t care for the performance of all other subsequent operations… – Holger Sep 25 '19 at 08:42
  • My point is that Java's list is not optimized for immutable operations and making it read-only doesn't change that. You can have though immutable collections which are *almost* as performant as mutable ones and I gave an example of `Vavr` list. – Krzysztof Atłasik Sep 25 '19 at 15:12
  • The first point of my comment was that your first sentence says “it’s not really A, not real B” while it’s very likely intended to say “it’s A, not a real B”. • The other point is that cheap append operations come at a price for all other operations. That’s entirely independent from its immutable nature, e.g. `LinkedList` pays the same price. On the other hand, `String` always has been immutable, but in the past, it had cheap `substring` operations, but nowadays it hasn’t, to avoid paying the price for all other operations. It’s a common trade off, irrespective of mutable vs immutable. – Holger Sep 26 '19 at 07:08