views:

353

answers:

5

Is there an immutable alternative to the primitive arrays in Java? Making a primitive array final doesn't actually prevent one from doing something like

final int[] array = new int[] {0, 1, 2, 3};
array[0] = 42;

I want the elements of the array to be unchangeable.

+12  A: 

Not with primitive arrays. You'll need to use a List or some other data structure:

List<Integer> items = Collections.unmodifiableList(Arrays.asList(0,1,2,3));
Jason S
+1  A: 

No, this is not possible. However, one could do something like this:

List<Integer> temp = new ArrayList<Integer>();
temp.add(Integer.valueOf(0));
temp.add(Integer.valueOf(2));
temp.add(Integer.valueOf(3));
temp.add(Integer.valueOf(4));
List<Integer> immutable = Collections.unmodifiableList(temp);

This requires using wrappers, and is a List, not an array, but is the closest you will get.

John Gaughan
No need to write all those `valueOf()`s, autoboxing will take care of that. Also `Arrays.asList(0, 2, 3, 4)` would be much more concise.
Joachim Sauer
@Joachim: Point of using `valueOf()` is to utilize the internal Integer object cache to reduce memory consumption/recycling.
Esko
@Esko: read the autoboxing spec. It does exactly the same thing, so there's no difference here.
Joachim Sauer
Sorry, it's just a habit. I've been burned by autoboxing several times due to NPEs caused by poorly designed interfaces. So I tend to avoid using it.
John Gaughan
@John You'll never get a NPE converting an `int` to an `Integer` though; just have to be careful the other way around.
ColinD
@John: you're right, it can be dangerous. But instead of avoiding it completely, it's probably better to understand the danger and avoid that.
Joachim Sauer
@Esko: The Integer cache only works with figures -127 to +127 - see also the source code (http://www.java2s.com/Open-Source/Java-Document/6.0-JDK-Core/lang/java/lang/Integer.java.htm). I'd assume autoboxing is optimized enough through the compiler or JIT anyways, and doubt your approach vs regular autoboxing would be significantly faster.
Cthulhu
+5  A: 

As others have noted, you can't have immutable arrays in Java.

If you absolutely need a method that returns an array that doesn't influence the original array, then you'd need to clone the array each time:

public int[] getFooArray() {
  return fooArray == null ? null : fooArray.clone();
}

Obviously this is rather expensive (as you'll create a full copy each time you call the getter), but if you can't change the interface (to use a List for example) and can't risk the client changing your internals, then it may be necessary.

This technique is called making a defensive copy.

Joachim Sauer
Where did he mention that he needed a getter?
Erick Robertson
@Erik: he didn't, but that's a very common use case for immutable data structures (I modified the answer to refer to methods in general, as the solution applies everywhere, even if it's more common in getters).
Joachim Sauer
+2  A: 

My recommendation is to not use an array or an unmodifiableList but to use Guava's ImmutableList, which exists for this purpose.

ImmutableList<Integer> values = ImmutableList.of(0, 1, 2, 3);
ColinD
+1  A: 

If you need (for performance reason or to save memory) native 'int' instead of 'java.lang.Integer', then you would probably need to write your own wrapper class. There are various IntArray implementations on the net, but none (I found) was immutable: Koders IntArray, Lucene IntArray. There are probably others.

Thomas Mueller