33

When I run the following code, no output is printed.

int[] array = {3, 2, 5, 4};

if (Arrays.asList(array).contains(3))
{
    System.out.println("The array contains 3");
}
Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121
Henry Zhu
  • 2,488
  • 9
  • 43
  • 87

4 Answers4

67

When you pass an array of primitives (int[] in your case) to Arrays.asList, it creates a List<int[]> with a single element - the array itself. Therefore contains(3) returns false. contains(array) would return true.

If you'll use Integer[] instead of int[], it will work.

Integer[] array = {3, 2, 5, 4};

if (Arrays.asList(array).contains(3))
{
  System.out.println("The array contains 3");
}

A further explanation :

The signature of asList is List<T> asList(T...). A primitive can't replace a generic type parameter. Therefore, when you pass to this method an int[], the entire int[] array replaces T and you get a List<int[]>. On the other hand, when you pass an Integer[] to that method, Integer replaces T and you get a List<Integer>.

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

In Java 8, you don't need to convert the array at all; just turn it into a stream via Arrays#stream, then use the anyMatch predicate to see if the value you want is contained in the array.

int[] array = {3, 2, 5, 4};

if (Arrays.stream(array).anyMatch(x -> x == 3)) {
    System.out.println("The array contains 3");
}
Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121
Makoto
  • 104,088
  • 27
  • 192
  • 230
  • Is it better than Arrays.asList? – ghchoi Apr 29 '17 at 14:13
  • @GyuHyeonChoi: I'd argue it's equivalent. Arrays and lists run in O(n) to find a single element. This just eliminates the extra overhead of creating an object with which to call a convenient method on. – Makoto Apr 29 '17 at 17:18
  • Then it must be better! Would I better use newer function stream? – ghchoi Apr 30 '17 at 09:02
1

The previous answer explains why your approach does not work.

To achieve what you like, you can also use Apache Commons Lang utilities like this:

import org.apache.commons.lang.ArrayUtils;
...
int[] array = {3, 2, 5, 4};
ArrayUtils.contains(array, 3);
Community
  • 1
  • 1
Thomas Weller
  • 55,411
  • 20
  • 125
  • 222
  • 2
    this is not a good way to make it work. You missed explaining the problem completely as well. – Willi Mentzel Jul 15 '15 at 11:06
  • @haywire: Why is it not a good way to make it work? Because Apache is bad stuff in general? – Thomas Weller Jul 17 '15 at 06:14
  • 1
    It is bad practice to use a third party library for something that the language (or its std libs) itself can already achieve. If you use ACL utilites for something that Java cannot do, it does indeed make sense. – Willi Mentzel Jul 17 '15 at 08:26
-2

Arrays.asList(T... a) takes a T[] for any object type T which will match any array of objects (i.e., things that subclass of Object). The only things that won't match is an array of primitives, since primitive types do not derive from Object. That is, an int[] is not a (subclass of) 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.

Your function could be written as:

int[] array = {3, 2, 5, 4};
if (Ints.asList(array).contains(3))
{
    System.out.println("The array contains 3");
}

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. In your toy example, there will be only one boxing operation during the search, since the element is found immediately. Similarly, algorithms like binary search which only sparsely access the array are likely to perform reasonably.

If, however, 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. That can be as simple as making a copy of the list: new ArrayList<>(Ints.asList(array)), or you in Java 8 you can use the IntStream.boxed() approach (described below) to create a List<Integer>. Both should perform about equally.

Java 8 IntStream

As described in Makato's answer, 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 determine if the element 3 exists, you can use IntStream.anyMatch(). 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.

BeeOnRope
  • 60,350
  • 16
  • 207
  • 386
  • 2
    Don't copy [your answer](http://stackoverflow.com/questions/1467913/arrays-aslist-not-working-as-it-should/38003845#38003845), flag this question as a duplicate instead. – Tom Jun 24 '16 at 00:26
  • 1
    I flagged it as a dupe of: http://stackoverflow.com/questions/10335662/convert-java-array-to-iterable/14271602. In any case, duplicate questions usually stick around so it's worth having quality answers here. I also updated my answer to align with the particular use case of the OP (search in the array) and performance considerations for that case. Furthermore, I linked to an existing relevant answer and provided more details. – BeeOnRope Jun 24 '16 at 00:32
  • *"I flagged it as a dupe of"* Mhh, interessting question. But I guess the other question (with your first answer) has the better title, which will be found a bit easier using a search engine. That you've updated your already good answer to match OPs case doesn't prevent this question from being a duplicate and it is quite disliked to answer the same question over and over again, especially if the answer is copied ([meta](http://meta.stackoverflow.com/a/258048/3824919)). – Tom Jun 24 '16 at 00:39
  • I think the "is working wrong" titles are wrong and poorly searchable. In fact asList is working right. The real question is how to view a primitive array as a List or Collection. The OPs question just reflects an incorrect belief that `Arrays.asList` could do it. – BeeOnRope Jun 24 '16 at 03:29