Arrays.asList() not working as it should?

Viewed 41070

I have a float[] and i would like to get a list with the same elements. I could do the ugly thing of adding them one by one but i wanted to use the Arrays.asList method. There is a problem though. This works:

List<Integer> list = Arrays.asList(1,2,3,4,5);

But this does not.

int[] ints = new int[] {1,2,3,4,5};
List<Integer> list = Arrays.asList(ints);

The asList method accepts a varargs parameter which to the extends of my knowledge is a "shorthand" for an array.

Questions:

  • Why does the second piece of code returns a List<int[]> but not List<int>.

  • Is there a way to correct it?

  • Why doesn't autoboxing work here; i.e. int[] to Integer[]?

11 Answers

Why doesn't autoboxing work here; i.e. int[] to Integer[]?

While autoboxing will convert an int to an Integer, it will not convert an int[] to an Integer[].

Why not?

The simple (but unsatisfying) answer is because that is what the JLS says. (You can check it if you like.)

The real answer is fundamental to what autoboxing is doing and why it is safe.

When you autobox 1 anywhere in your code, you get the same Integer object. This is not true for all int values (due to the limited size of the Integer autoboxing cache), but if you use equals to compare Integer objects you get the "right" answer.

Basically N == N is always true and new Integer(N).equals(new Integer(N)) is always true. Furthermore, these two things remain true ... assuming that you stick with Pure Java code.

Now consider this:

int[] x = new int[]{1};
int[] y = new int[]{1};

Are these equal? No! x == y is false and x.equals(y) is false! But why? Because:

y[0] = 2;

In other words, two arrays with the same type, size and content are always distinguishable because Java arrays are mutable.

The "promise" of autoboxing is that it is OK to do because the results are indistinguishable1. But, because all arrays are fundamentally distinguishable because of the definition of equals for arrays AND array mutability. So, if autoboxing of arrays of primitive types was permitted, it would undermine the "promise".


1 - ..... provided that you don't use == to test if autoboxed values are equal.

Alternatively, you can use IntList as the type and the IntLists factory from Eclipse Collections to create the collection directly from an array of int values. This removes the need for any boxing of int to Integer.

IntList intList1 = IntLists.mutable.with(1,2,3,4,5);
int[] ints = new int[] {1,2,3,4,5};
IntList intList2 = IntLists.mutable.with(ints);
Assert.assertEquals(intList1, intList2);

Eclipse Collections has support for mutable and immutable primitive List as well as Set, Bag, Stack and Map.

Note: I am a committer for Eclipse Collections.

int is a primitive type. Arrays.asList() accept generic type T which only works on reference types (object types), not on primitives. Since int[] as a whole is an object it can be added as a single element.

Related