By Savvas Dalkitsis


2009-09-23 18:48:21 8 Comments

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[]?

9 comments

@Stephen C 2018-07-22 02:01:38

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.

@YoYo 2015-06-04 06:16:37

Enter Java 8, and you can do following to collect in a boxed Array:

Integer[] boxedInts = IntStream.of(ints).boxed().toArray(Integer[]::new);

Or this to collect in a boxed List

List<Integer> boxedInts = IntStream.of(ints).boxed().collect(Collectors.toList());

However, this only works for int[], long[], and double[]. This will not work for byte[].

Note that Arrays.stream(ints) and IntStream.of(ints) are equivalent. So earlier two examples can also be rewritten as:

Integer[] boxedIntArray = Arrays.stream(ints).boxed().toArray(Integer[]::new);
List<Integer> boxedIntList = Arrays.stream(ints).boxed().collect(Collectors.toList());

This last form could be favored as it omits a primitive specific subtype of Stream. However, internally it is still a bunch of overloaded's which in this case still create a IntStream internally.

@laertis 2018-02-18 15:32:48

You need to cast the result from toArray() since it returns Object[]

@laertis 2018-02-19 11:09:17

@YoYo 2018-02-19 14:37:19

Ok. You are right. Type at that point is Stream<Integer> and not IntStream. I have fixed it however by using toArray(Integer[]::new) instead. Maybe simply typecasting here would be better?

@laertis 2018-02-20 10:53:50

This is actually a different overloaded toArray() implementation (docs.oracle.com/javase/8/docs/api/java/util/stream/…) that uses a generator function and does the job properly. It's better to avoid typecasting where you can..

@BeeOnRope 2016-06-24 00:15:15

Arrays.asList(T... a) effectively takes a T[] which will match any array of true objects (subclasses of Object) as an array. The only thing that won't match like that is an array of primitives, since primitive types do not derive from Object. So an int[] is not an Object[].

What happens then is that the varags mechanism kicks in and treats it as if you had passed a single object, and creates a single element array of that type. So you pass an int[][] (here, T is int[]) and end up with a 1-element List<int[]> which is not what you want.

You still have some pretty good options though:

Guava's Int.asList(int[]) Adapter

If your project already uses guava, it's as simple as using the adapter Guava provides: Int.asList(). There is a similar adapter for each primitive type in the associated class, e.g., Booleans for boolean, etc.

int foo[] = {1,2,3,4,5};
Iterable<Integer> fooBar = Ints.asList(foo);
for(Integer i : fooBar) {
    System.out.println(i);
}

The advantage of this approach is that it creates a thin wrapper around the existing array, so the creation of the wrapper is constant time (doesn't depend on the size of the array), and the storage required is only a small constant amount (less than 100 bytes) in addition to the underlying integer array.

The downside is that accessing each element requires a boxing operation of the underlying int, and setting requires unboxing. This may result in a large amount of transient memory allocation if you access the list heavily. If you access each object many times on average, it may be better to use an implementation that boxes the objects once and stores them as Integer. The solution below does that.

Java 8 IntStream

In Java 8, you can use the Arrays.stream(int[]) method to turn an int array into a Stream. Depending on your use case, you may be able to use the stream directly, e.g., to do something with each element with forEach(IntConsumer). In that case, this solution is very fast and doesn't incur any boxing or unboxing at all, and does not create any copy of the underlying array.

Alternately, if you really need a List<Integer>, you can use stream.boxed().collect(Collectors.toList()) as suggested here. The downside of that approach is that it fully boxes every element in the list, which might increase its memory footprint by nearly an order of magnitude, it create a new Object[] to hold all the boxed elements. If you subsequently use the list heavily and need Integer objects rather than ints, this may pay off, but it's something to be aware of.

@Jon Skeet 2009-09-23 18:53:10

There's no such thing as a List<int> in Java - generics don't support primitives.

Autoboxing only happens for a single element, not for arrays of primitives.

As for how to correct it - there are various libraries with oodles of methods for doing things like this. There's no way round this, and I don't think there's anything to make it easier within the JDK. Some will wrap a primitive array in a list of the wrapper type (so that boxing happens on access), others will iterate through the original array to create an independent copy, boxing as they go. Make sure you know which you're using.

(EDIT: I'd been assuming that the starting point of an int[] was non-negotiable. If you can start with an Integer[] then you're well away :)

Just for one example of a helper library, and to plug Guava a bit, there's com.google.common.primitive.Ints.asList.

@Geek 2014-01-15 04:49:08

Why does "Autoboxing only happens for a single element, not for arrays of primitives.". What do you think is the reason for this design decision?

@Jon Skeet 2014-01-15 06:46:44

@Geek: Well what would you suggest as an alternative? It would be odd for a double[] to be automatically converted to a Double[] by copying all the elements - such that a cast of a reference type would effectively clone the data, unlike every other operation in Java. If you're suggesting that a Double[] should be able to be backed by a double[] in a "view" sort of way, that has other issues such as how you store null references and again the difference between this and other arrays. I think it was the right decision.

@Geek 2014-01-15 06:59:00

I see your point. Great explanation.+1.

@marcinj 2014-04-16 18:59:42

with java 8 you can use stream api: List<Integer> list = Arrays.stream(new int[]{1,2,3}).boxed().collect(Collectors.toList());, a bit verbose though

@Maarten Bodewes 2014-12-07 14:32:51

One of these Guava functions that should have been added to Java a long way back. Horrible type juggling with primitive types is unfortunately not going away soon.

@karl 2015-11-25 22:50:47

Warning: lists returned by Ints.asList do not support add() or related methods

@Maciek Kreft 2010-07-27 04:24:39

It's not possible to convert int[] to Integer[], you have to copy values


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

public static List<Integer> asList(int[] a) {
    List<Integer> list = new ArrayList<Integer>();
    for (int i = 0; i < a.length && list.add(a[i]); i++);
    return list;
}

@Michael Borgwardt 2009-09-23 18:57:38

The problem is not with Arrays.asList(). The problem is that you expect autoboxing to work on an array - and it doesn't. In the first case, the compiler autoboxes the individual ints before it looks at what they're used for. In the second case, you first put them into an int array (no autoboxing necessary) and then pass that to Arrays.asList() (not autoboxing possible).

@Tom Neyland 2009-09-23 18:55:36

If you pass an int[] to Arrays.asList(), the list created will be List<int[]>, which is not vaild in java, not the correct List<Integer>.

I think you are expecting Arrays.asList() to auto-box your ints, which as you have seen, it won't.

@JRL 2009-09-23 18:52:15

How about this?

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

@Michael Myers 2009-09-23 18:53:12

Beat me, but it would be better with an explanation also.

@Savvas Dalkitsis 2009-09-23 18:53:24

unbelievable... It works with reference but not with primitive types :D thanks a lot. :)

@Savvas Dalkitsis 2009-09-23 18:54:47

Hm but is there an easy way to convert an int[] to Integer[]? The thing is i get my array via a method call and i cannot change it.

@Jonik 2010-07-27 14:51:05

@Savvas: See stackoverflow.com/questions/880581/java-convert-int-to-integ‌​er or Jon Skeet's answer here. Libraries like Apache Commons Lang or Guava will be of some help.

@Munavar Fairooz 2017-05-10 11:33:06

@MichaelMyers . Will this work Object Array?

@user7294900 2019-07-03 12:17:06

Can warning be overcome Type safety: The expression of type List needs unchecked conversion to conform to List<Integer> ?

@Abdul 2019-07-16 01:40:44

Array.asList works only with Objects? Not Primitive array?

@ChssPly76 2009-09-23 18:51:46

Because java arrays are objects and Arrays.asList() treats your int array as a single argument in the varargs list.

@Michael Myers 2009-09-23 18:54:24

That's right, but it's not the real story.

@whiskeysierra 2010-03-01 23:29:09

@mmyers In fact, that's what this question is all about. +1 for ChssPly76

Related Questions

Sponsored Content

24 Answered Questions

[SOLVED] What is a serialVersionUID and why should I use it?

26 Answered Questions

[SOLVED] Why not inherit from List<T>?

26 Answered Questions

[SOLVED] How does the Java 'for each' loop work?

15 Answered Questions

[SOLVED] Efficiency of Java "Double Brace Initialization"?

6 Answered Questions

[SOLVED] Can I create a list of array with Arrays.asList?

  • 2018-02-07 17:17:22
  • user8931048
  • 317 View
  • 2 Score
  • 6 Answer
  • Tags:   java list

3 Answered Questions

[SOLVED] What is the return type of Arrays.asList?

  • 2017-05-17 07:52:04
  • CrazySynthax
  • 2930 View
  • 1 Score
  • 3 Answer
  • Tags:   java collections

1 Answered Questions

[SOLVED] Benefits of creating a List using Arrays.asList()

2 Answered Questions

[SOLVED] Arrays.asList works

  • 2015-04-04 04:37:47
  • Saurabh Jhunjhunwala
  • 680 View
  • 4 Score
  • 2 Answer
  • Tags:   java arrays

3 Answered Questions

[SOLVED] incompatible types: inference variable T has incompatible bounds

  • 2014-12-17 09:53:45
  • PDStat
  • 51195 View
  • 19 Score
  • 3 Answer
  • Tags:   java java-8

2 Answered Questions

[SOLVED] Am I missing something, or do varargs break Arrays.asList?

Sponsored Content