14

When I initialize List, I am able to do this:

List<Object[]> foo = new ArrayList<>();
foo.add(new Object[]{816, "foo", 2.6});

But when I want to simplify it using Arrays.asList:

List<Object[]> bar = Arrays.asList(new Object[]{"bar", 286});

It cannot compile with error:

incompatible types: inference variable T has incompatible bounds
equality constraints: java.lang.Object[]
lower bounds: java.lang.Object

Why it cannot do the type inference right and how to fix this?

Tunaki
  • 132,869
  • 46
  • 340
  • 423
qqibrow
  • 2,942
  • 1
  • 24
  • 40
  • related https://stackoverflow.com/questions/1248763/arrays-aslist-of-an-array –  Oct 06 '16 at 07:04
  • 2
    As a general rule of thumb, never mix generics and arrays. (You are allowed to disregard this rule once you understand why it's a good rule of thumb in the first place.) – Daniel Pryden Oct 06 '16 at 07:06

7 Answers7

14

Remember that ... is just syntactic sugar for an array parameter. You can call a method with a variadic parameter foo(Object...) either using

foo("hello", 1);

or

foo(new Object[]{"hello", 1});

since the compiler constructs the second form anyway.

Because the receiver type isn't considered when the compiler infers types, it looks at Arrays.asList(new Object[]{"bar", 286}) and thinks that you mean to create a list of Object, not a singleton list of Object[].

The easiest way with your existing syntax is just to add an explicit type parameter:

List<Object[]> bar = Arrays.<Object[]>asList(new Object[]{"bar", 286});

Adding the <Object[]> tells the compiler what T should be.

Or, if you don't need the list to be mutable:

List<Object[]> bar = Collections.singletonList(new Object[]{"bar", 286});
Andy Turner
  • 137,514
  • 11
  • 162
  • 243
13

When you pass an array of reference types to Arrays.asList you get a List of that reference type.

Therefore Arrays.asList(new Object[]{"bar", 286}) returns a List<Object>, not a List<Object[]>.

Eran
  • 387,369
  • 54
  • 702
  • 768
7

If your list only has one element in it, Collections.singletonList(new Object[] {...}) is a better choice, as it avoids varargs and makes the behavior more obvious at the call site.

Daniel Pryden
  • 59,486
  • 16
  • 97
  • 135
4

The problem is that Arrays.asList is a varargs method which technically receives an array containing the arguments and due to compatibility with pre-generics code still accepts an array instead of an argument list. When passing a single array, the call is ambiguous and will be handled like a pre-varargs method invocation.

The problem disappears when you have more than one argument:

List<Object[]> bar = Arrays.asList(new Object[]{"bar", 286}, new Object[]{"baz", 123});

If you have only one argument you can aid the compiler by inserting an explicit list element type:

List<Object[]> bar = Arrays.<Object[]>asList(new Object[]{"bar", 286});

Alternatively, you can use

List<Object[]> bar = Collections.singletonList(new Object[]{"bar", 286});

to create an immutable list of size one. Note that this differs from Arrays.asList, as the latter returns a list of fixed size but still mutable via set.

Holger
  • 285,553
  • 42
  • 434
  • 765
2

Arrays#asList signature:

public static <T> List<T> asList(T... a)

The return type is List<T>. Now you should ask yourself what is T?

T is Object, so the return type will be List<Object>, and not List<Object[]>.

Maroun
  • 94,125
  • 30
  • 188
  • 241
1

Your call:

Arrays.asList(new Object[]{"bar", 286});

creates a list out of the Object[]. So the data is convertet into a new List<Object>.

So Arrays.asList(new Object[]{"bar", 286}).get(0); will return "bar".

In this call:

List<Object[]> foo = new ArrayList<>();
foo.add(new Object[]{816, "foo", 2.6});

you are creating a List<Object[]> (2Dimensional) and add one element after it: foo.add(..);. Therefore you are adding one element consisting of an Object[]. if you now call foo.get(0); you will get a Object[] consisting of: 816, "foo", 2.6

I think you wanted to do:

Object[] oa = new Object[]{""};
Object[] ob = new Object[]{""};
List<Object[]> list = Arrays.asList(oa, ob);

If you have questions, feel free to ask me :)

Noixes
  • 1,158
  • 12
  • 25
1

When you use List<Object[]> bar = Arrays.asList(new Object[]{"bar", 286}); you actually have a two dimensional Array and you cand resolve that problem by doing List<Object[]> bar = Arrays.asList(new Object[][]{new Object[]{"bar","asd",123}});