Seeming Discrepancy in Arrays.copyOf - java

Why this question is not a possible duplication of How Arrays.asList(int[]) can return List<int[]>?.
That question doesn't really answer my particular situation as I am trying to figure out if there is a discrepancy in my use of Arrays.copyOf.
CASE 1: Supposed deep copy of the array
// Creating a integer array, populating its values
int[] src = new int[2];
src[0] = 2;
src[1] = 3;
// Create a copy of the array
int [] dst= Arrays.copyOf(src,src.length);
Assert.assertArrayEquals(src, dst);
// Now change one element in the original
dst[0] = 4;
// Following line throws an exception, (which is expected) if the copy is a deep one
Assert.assertArrayEquals(src, dst);
CASE 2:
Here is where things seem to be weird:
What I am trying to do with the below method (lifted verbatim from a book) is to create an immutable list view of a copy of the input array arguments. That way, if the input array changes, the contents of the returned list don't change.
#SafeVarargs
public static <T> List<T> list(T... t) {
return Collections.unmodifiableList(new ArrayList<>(Arrays.asList(Arrays.copyOf(t, t.length))));
}
int[] arr2 = new int[2];
arr2[0] = 2;
arr2[1] = 3;
// Create an unmodifiable list
List<int[]> list2 = list(arr2);
list2.stream().forEach(s -> System.out.println(Arrays.toString(s)));
// Prints [2, 3] as expected
arr2[0] = 3;
list2.stream().forEach(s -> System.out.println(Arrays.toString(s)));
// Prints [3, 3] which doesn't make sense to me... I would have thought it would print [2, 3] and not be affected by my changing the value of the element.
The contradiction that I see is that in one case (Case 1), Arrays.copyOf seems to be a deep copy, whereas in the other case (Case 2), it seems like a shallow one. The changes to the original array seem to have written through to the list, even though I have copied the array in creating my unmodifiable list.
Would someone be able to help me resolve this discrepancy?

First of all, your list method performs an unnecessary step, you don't need the copyOf operation, so here goes:
#SafeVarargs
public static <T> List<T> list(T... t) {
return Collections.unmodifiableList(
new ArrayList<>(Arrays.asList(t))
);
}
The ArrayList constructor already copies the incoming list, so you're safe there.
Next, when you are calling your list() method with an int[], that array is considered to be a single element of type int[], because the type erasure of your T... is Object..., and int is primitive. There is no way you can make your method do a deep copy inside the list without either changing the parameter types or doing an instanceOf check and performing the copy manually inside the method. I'd say the wisest thing to do is probably to move the Arrays.copyOf() call outside the method:
List<int[]> list2 = list(Arrays.copyOf(arr2));

Related

Copying an Array by reference [duplicate]

I have an array a which is constantly being updated. Let's say a = [1,2,3,4,5]. I need to make an exact duplicate copy of a and call it b. If a were to change to [6,7,8,9,10], b should still be [1,2,3,4,5]. What is the best way to do this? I tried a for loop like:
for(int i=0; i<5; i++) {
b[i]=a[i];
}
but that doesn't seem to work correctly. Please don't use advanced terms like deep copy, etc., because I do not know what that means.
You can try using System.arraycopy()
int[] src = new int[]{1,2,3,4,5};
int[] dest = new int[5];
System.arraycopy( src, 0, dest, 0, src.length );
But, probably better to use clone() in most cases:
int[] src = ...
int[] dest = src.clone();
you can use
int[] a = new int[]{1,2,3,4,5};
int[] b = a.clone();
as well.
If you want to make a copy of:
int[] a = {1,2,3,4,5};
This is the way to go:
int[] b = Arrays.copyOf(a, a.length);
Arrays.copyOf may be faster than a.clone() on small arrays. Both copy elements equally fast but clone() returns Object so the compiler has to insert an implicit cast to int[]. You can see it in the bytecode, something like this:
ALOAD 1
INVOKEVIRTUAL [I.clone ()Ljava/lang/Object;
CHECKCAST [I
ASTORE 2
Nice explanation from http://www.journaldev.com/753/how-to-copy-arrays-in-java
Java Array Copy Methods
Object.clone(): Object class provides clone() method and since array
in java is also an Object, you can use this method to achieve full
array copy. This method will not suit you if you want partial copy of
the array.
System.arraycopy(): System class arraycopy() is the best way to do
partial copy of an array. It provides you an easy way to specify the
total number of elements to copy and the source and destination array
index positions. For example System.arraycopy(source, 3, destination,
2, 5) will copy 5 elements from source to destination, beginning from
3rd index of source to 2nd index of destination.
Arrays.copyOf(): If you want to copy first few elements of an array or
full copy of array, you can use this method. Obviously it’s not
versatile like System.arraycopy() but it’s also not confusing and easy
to use.
Arrays.copyOfRange(): If you want few elements of an array to be
copied, where starting index is not 0, you can use this method to copy
partial array.
I have a feeling that all of these "better ways to copy an array" are not really going to solve your problem.
You say
I tried a for loop like [...] but that doesn't seem to be working correctly?
Looking at that loop, there's no obvious reason for it not to work ... unless:
you somehow have the a and b arrays messed up (e.g. a and b refer to the same array), or
your application is multi-threaded and different threads are reading and updating the a array simultaneously.
In either case, alternative ways of doing the copying won't solve the underlying problem.
The fix for the first scenario is obvious. For the second scenario you will have to figure out some way of synchronizing the threads. Atomic array classes don't help because they have no atomic copy constructors or clone methods, but synchronizing using a primitive mutex will do the trick.
(There are hints in your question that lead me to think that this is indeed thread related; e.g. your statement that a is constantly changing.)
You can try using Arrays.copyOf() in Java
int[] a = new int[5]{1,2,3,4,5};
int[] b = Arrays.copyOf(a, a.length);
All solution that call length from array, add your code redundant null checkersconsider example:
int[] a = {1,2,3,4,5};
int[] b = Arrays.copyOf(a, a.length);
int[] c = a.clone();
//What if array a comes as local parameter? You need to use null check:
public void someMethod(int[] a) {
if (a!=null) {
int[] b = Arrays.copyOf(a, a.length);
int[] c = a.clone();
}
}
I recommend you not inventing the wheel and use utility class where all necessary checks have already performed. Consider ArrayUtils from apache commons. You code become shorter:
public void someMethod(int[] a) {
int[] b = ArrayUtils.clone(a);
}
Apache commons you can find there
You can also use Arrays.copyOfRange.
Example:
public static void main(String[] args) {
int[] a = {1,2,3};
int[] b = Arrays.copyOfRange(a, 0, a.length);
a[0] = 5;
System.out.println(Arrays.toString(a)); // [5,2,3]
System.out.println(Arrays.toString(b)); // [1,2,3]
}
This method is similar to Arrays.copyOf, but it's more flexible. Both of them use System.arraycopy under the hood.
See:
https://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html
https://docs.oracle.com/javase/tutorial/java/nutsandbolts/arrays.html
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/util/Arrays.java?av=f
If you must work with raw arrays and not ArrayList then Arrays has what you need. If you look at the source code, these are the absolutely best ways to get a copy of an array. They do have a good bit of defensive programming because the System.arraycopy() method throws lots of unchecked exceptions if you feed it illogical parameters.
You can use either Arrays.copyOf() which will copy from the first to Nth element to the new shorter array.
public static <T> T[] copyOf(T[] original, int newLength)
Copies the specified array, truncating or padding with nulls (if
necessary) so the copy has the specified length. For all indices that
are valid in both the original array and the copy, the two arrays will
contain identical values. For any indices that are valid in the copy
but not the original, the copy will contain null. Such indices will
exist if and only if the specified length is greater than that of the
original array. The resulting array is of exactly the same class as
the original array.
2770
2771 public static <T,U> T[] More ...copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
2772 T[] copy = ((Object)newType == (Object)Object[].class)
2773 ? (T[]) new Object[newLength]
2774 : (T[]) Array.newInstance(newType.getComponentType(), newLength);
2775 System.arraycopy(original, 0, copy, 0,
2776 Math.min(original.length, newLength));
2777 return copy;
2778 }
or Arrays.copyOfRange() will also do the trick:
public static <T> T[] copyOfRange(T[] original, int from, int to)
Copies the specified range of the specified array into a new array.
The initial index of the range (from) must lie between zero and
original.length, inclusive. The value at original[from] is placed into
the initial element of the copy (unless from == original.length or
from == to). Values from subsequent elements in the original array are
placed into subsequent elements in the copy. The final index of the
range (to), which must be greater than or equal to from, may be
greater than original.length, in which case null is placed in all
elements of the copy whose index is greater than or equal to
original.length - from. The length of the returned array will be to -
from. The resulting array is of exactly the same class as the original
array.
3035 public static <T,U> T[] More ...copyOfRange(U[] original, int from, int to, Class<? extends T[]> newType) {
3036 int newLength = to - from;
3037 if (newLength < 0)
3038 throw new IllegalArgumentException(from + " > " + to);
3039 T[] copy = ((Object)newType == (Object)Object[].class)
3040 ? (T[]) new Object[newLength]
3041 : (T[]) Array.newInstance(newType.getComponentType(), newLength);
3042 System.arraycopy(original, from, copy, 0,
3043 Math.min(original.length - from, newLength));
3044 return copy;
3045 }
As you can see, both of these are just wrapper functions over System.arraycopy with defensive logic that what you are trying to do is valid.
System.arraycopy is the absolute fastest way to copy arrays.
For a null-safe copy of an array, you can also use an optional with the Object.clone() method provided in this answer.
int[] arrayToCopy = {1, 2, 3};
int[] copiedArray = Optional.ofNullable(arrayToCopy).map(int[]::clone).orElse(null);
I had a similar problem with 2D arrays and ended here.
I was copying the main array and changing the inner arrays' values and was surprised when the values changed in both copies. Basically both copies were independent but contained references to the same inner arrays and I had to make an array of copies of the inner arrays to get what I wanted.
This is sometimes called a deep copy. The same term "deep copy" can also have a completely different and arguably more complex meaning, which can be confusing, especially to someone not figuring out why their copied arrays don't behave as they should. It probably isn't the OP's problem, but I hope it can still be helpful.

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

Say I want to create a List which contains Integer[] arrays. But
Integer[] foo = {1,2,3};
List<Integer[]> bar = Arrays.asList(foo);
The second line wouldn't compile, because Arrays.asList(foo) will return a List with three Integer elements(namely 1, 2, 3), not a List with a single Integer[] element.
Since the documentation states the parameter of asList method as varargs of type T, I don't understand why the compiler doesn't interpret the second line as single argument of type Integer[] given. How do I get a List of single Array element?
List<Integer[]> bar = new ArrayList<Integer[]>(Arrays.asList(foo));
This is what I actually wanted to do, but it also doesn't compile, for the same reason I believe.
A very similar question was just asked the other day, but I suppose this is different enough for it not to be a duplicate. You need to explicitly specify the generic type for it to compile, like so:
Integer[] foo = {1, 2, 3};
List<Integer[]> list = Arrays.<Integer[]>asList(foo);
Unless you actually need the ability to set the element to a different array, you can use:
List<Integer[]> list = Collections.singletonList(foo);
This is more efficient, because it is specialized to just holding one element: no array has to be created, contains is simply checking equality, size is always 1 etc.
No. Arrays.asList takes a projection of your current array and flattens the first dimension into a List. Since you only have one dimension, all of those elements get collected into the list.
You could do it if you had an Integer[][].
Note: asList accepts a vararg of T (so T...), which is effectively T[]. If you substitute that with Integer[][], you get Integer[], since one dimension of your Integer[][] will satisfy T...'s type requirement.
Varargs in java is just a syntactic sugar in Java. So, there is no difference between.
Arrays.asList(1,2,3) and Arrays.asList(new Integer[]{1,2,3}).
So what you can do like below to solve your problem.
Integer[][] foo = {{1,2,3}};
List<Integer[]> bar = Arrays.asList(foo);
Arrays.asList() generates list of contents of array passed as argument. If you need to create list of arrays, you need to pass to this method array of arrays (e.g. Integer[][]).
When you pass to method Integer[] as argument instead of Integer[][] , it makes a list of contents of that array (in that case these are Integers not arrays of Integers).
Wrapping your array in another array will achieve what you want:
Integer[] foo = {1,2,3};
List<Integer[]> bar = Arrays.asList(new Integer[][]{foo});
// OR
Integer[][] foo = {{1,2,3}};
List<Integer[]> bar = Arrays.asList(foo);
You could also just manually set the first element: (I'd probably say this is more readable, but opinions may vary)
Integer[] foo = {1,2,3};
List<Integer[]> bar = new ArrayList<>();
bar.set(0, foo);

Concatenating elements and Collections into a new Collection

I have a Collection of elements and a single element. I want my getter function looks a little like this
public List<Element> getElements(boolean includeOtherElement){
if (includeOtherElement){
return elements + otherElement; //Obviously this doesn't work, but I'm looking for something that would work like this
}
return elements;
}
Is there a way I could acheive this behavior in a single line, such as with the Stream API or something similar?
EDIT:
I have since realized that I should not be modifying state in a getter method.
If you don't want to add otherElement to the elements list but still want to return a list, you will have to provide a new list.
Simple way:
public List<Element> getElements(boolean includeOtherElement){
if (includeOtherElement){
List<Element> extendedList = new ArrayList<>(elements);
extendedList.add(otherElement);
return extendedList;
}
return elements;
}
This would create a shallow copy of your list.
If you really want to, you could provide your own list implementation, which delegates the first indices to the elements list and the last index to the otherElement;
Usually you do not want your getter function to be changing variables. I would recommend doing something like temp = elements to return a temp variable, with the extra element added via temp.add(otherElement). This way you will not change your current variable while still eliciting the same behavior.
I'm not sure if this answer will work exactly for you but I think it is a good example of something that is possible with the API. The reason that it may or may not be usable in a particular case is that it depends on the location of the extra element(s) being constant in the list.
Suppose it was the case that you didn't want to create a copy of the list, because you actually wanted whoever calls the getter to be able to modify the list. Or, suppose that you just didn't want to make a defensive copy of the list, perhaps because the list is very, very large. In these cases you don't want to add or remove the extra element from the list, you want to return a view of the list which either includes or excludes the extra element.
This is actually possible with existing API, using the List.subList(int, int) method. subList doesn't create a copy, like e.g. String.substring(...) does. Rather, the returned sublist is mutable (if the original list was), and changes to the sublist show through to the original list.
(Though I should note that the semantics of the sublist become undefined if the backing list is structurally modified, i.e. you shouldn't add/remove to and from the original list while keeping a reference to the sublist. If you change the original list through a reference other than the sublist, you have to create a new sublist.)
So what you could do is keep a complete list with all of the elements, then return a sublist of the range which excludes the element(s) you don't want to return.
This could also be used in conjunction with Collections.unmodifiableList(List) if the code which calls the getter is not supposed to be able to mutate the list.
Here's an example which shows this in action:
import java.util.*;
class Example {
public static void main (String[] args) {
Example e = new Example();
List<Object> sub = e.getList(false);
// sublist is [1, 2, 3]
System.out.printf("sublist is %s%n", sub);
sub.add(0, -1);
sub.add(1, 0);
sub.add(5);
// sublist is [-1, 0, 1, 2, 3, 5]
System.out.printf("sublist is %s%n", sub);
List<Object> all = e.getList(true);
// full list is [element0, -1, 0, 1, 2, 3, 5]
System.out.printf("full list is %s%n", all);
// As a side-note, this sequence of calls is
// e.g. what you aren't supposed to do:
// all.add(something); // <- structural modification
// sub.add(another); // <- this is undefined
// You have to make a new sublist first:
// sub = e.getList(false);
// sub.add(another); // <- this is fine now
}
List<Object> objects = new ArrayList<Object>();
Example() {
objects.add("element0");
objects.add(1);
objects.add(2);
objects.add(3);
}
List<Object> getList(boolean includeElement0) {
if (includeElement0) {
return objects;
} else {
return objects.subList(1, objects.size());
}
}
}
Here is the example on Ideone: http://ideone.com/PloZCh.
Also, while not returning a List, this can be done by returning a Stream:
Stream<E> stream = list.stream();
if (includeOtherElement) {
return Stream.concat(stream, Stream.of(otherElement));
} else {
return stream;
}
I suppose this may be the canonical way to do such a thing in Java 8.

Array is given same memory address for every instance of class [duplicate]

I have an array a which is constantly being updated. Let's say a = [1,2,3,4,5]. I need to make an exact duplicate copy of a and call it b. If a were to change to [6,7,8,9,10], b should still be [1,2,3,4,5]. What is the best way to do this? I tried a for loop like:
for(int i=0; i<5; i++) {
b[i]=a[i];
}
but that doesn't seem to work correctly. Please don't use advanced terms like deep copy, etc., because I do not know what that means.
You can try using System.arraycopy()
int[] src = new int[]{1,2,3,4,5};
int[] dest = new int[5];
System.arraycopy( src, 0, dest, 0, src.length );
But, probably better to use clone() in most cases:
int[] src = ...
int[] dest = src.clone();
you can use
int[] a = new int[]{1,2,3,4,5};
int[] b = a.clone();
as well.
If you want to make a copy of:
int[] a = {1,2,3,4,5};
This is the way to go:
int[] b = Arrays.copyOf(a, a.length);
Arrays.copyOf may be faster than a.clone() on small arrays. Both copy elements equally fast but clone() returns Object so the compiler has to insert an implicit cast to int[]. You can see it in the bytecode, something like this:
ALOAD 1
INVOKEVIRTUAL [I.clone ()Ljava/lang/Object;
CHECKCAST [I
ASTORE 2
Nice explanation from http://www.journaldev.com/753/how-to-copy-arrays-in-java
Java Array Copy Methods
Object.clone(): Object class provides clone() method and since array
in java is also an Object, you can use this method to achieve full
array copy. This method will not suit you if you want partial copy of
the array.
System.arraycopy(): System class arraycopy() is the best way to do
partial copy of an array. It provides you an easy way to specify the
total number of elements to copy and the source and destination array
index positions. For example System.arraycopy(source, 3, destination,
2, 5) will copy 5 elements from source to destination, beginning from
3rd index of source to 2nd index of destination.
Arrays.copyOf(): If you want to copy first few elements of an array or
full copy of array, you can use this method. Obviously it’s not
versatile like System.arraycopy() but it’s also not confusing and easy
to use.
Arrays.copyOfRange(): If you want few elements of an array to be
copied, where starting index is not 0, you can use this method to copy
partial array.
I have a feeling that all of these "better ways to copy an array" are not really going to solve your problem.
You say
I tried a for loop like [...] but that doesn't seem to be working correctly?
Looking at that loop, there's no obvious reason for it not to work ... unless:
you somehow have the a and b arrays messed up (e.g. a and b refer to the same array), or
your application is multi-threaded and different threads are reading and updating the a array simultaneously.
In either case, alternative ways of doing the copying won't solve the underlying problem.
The fix for the first scenario is obvious. For the second scenario you will have to figure out some way of synchronizing the threads. Atomic array classes don't help because they have no atomic copy constructors or clone methods, but synchronizing using a primitive mutex will do the trick.
(There are hints in your question that lead me to think that this is indeed thread related; e.g. your statement that a is constantly changing.)
You can try using Arrays.copyOf() in Java
int[] a = new int[5]{1,2,3,4,5};
int[] b = Arrays.copyOf(a, a.length);
All solution that call length from array, add your code redundant null checkersconsider example:
int[] a = {1,2,3,4,5};
int[] b = Arrays.copyOf(a, a.length);
int[] c = a.clone();
//What if array a comes as local parameter? You need to use null check:
public void someMethod(int[] a) {
if (a!=null) {
int[] b = Arrays.copyOf(a, a.length);
int[] c = a.clone();
}
}
I recommend you not inventing the wheel and use utility class where all necessary checks have already performed. Consider ArrayUtils from apache commons. You code become shorter:
public void someMethod(int[] a) {
int[] b = ArrayUtils.clone(a);
}
Apache commons you can find there
You can also use Arrays.copyOfRange.
Example:
public static void main(String[] args) {
int[] a = {1,2,3};
int[] b = Arrays.copyOfRange(a, 0, a.length);
a[0] = 5;
System.out.println(Arrays.toString(a)); // [5,2,3]
System.out.println(Arrays.toString(b)); // [1,2,3]
}
This method is similar to Arrays.copyOf, but it's more flexible. Both of them use System.arraycopy under the hood.
See:
https://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html
https://docs.oracle.com/javase/tutorial/java/nutsandbolts/arrays.html
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/util/Arrays.java?av=f
If you must work with raw arrays and not ArrayList then Arrays has what you need. If you look at the source code, these are the absolutely best ways to get a copy of an array. They do have a good bit of defensive programming because the System.arraycopy() method throws lots of unchecked exceptions if you feed it illogical parameters.
You can use either Arrays.copyOf() which will copy from the first to Nth element to the new shorter array.
public static <T> T[] copyOf(T[] original, int newLength)
Copies the specified array, truncating or padding with nulls (if
necessary) so the copy has the specified length. For all indices that
are valid in both the original array and the copy, the two arrays will
contain identical values. For any indices that are valid in the copy
but not the original, the copy will contain null. Such indices will
exist if and only if the specified length is greater than that of the
original array. The resulting array is of exactly the same class as
the original array.
2770
2771 public static <T,U> T[] More ...copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
2772 T[] copy = ((Object)newType == (Object)Object[].class)
2773 ? (T[]) new Object[newLength]
2774 : (T[]) Array.newInstance(newType.getComponentType(), newLength);
2775 System.arraycopy(original, 0, copy, 0,
2776 Math.min(original.length, newLength));
2777 return copy;
2778 }
or Arrays.copyOfRange() will also do the trick:
public static <T> T[] copyOfRange(T[] original, int from, int to)
Copies the specified range of the specified array into a new array.
The initial index of the range (from) must lie between zero and
original.length, inclusive. The value at original[from] is placed into
the initial element of the copy (unless from == original.length or
from == to). Values from subsequent elements in the original array are
placed into subsequent elements in the copy. The final index of the
range (to), which must be greater than or equal to from, may be
greater than original.length, in which case null is placed in all
elements of the copy whose index is greater than or equal to
original.length - from. The length of the returned array will be to -
from. The resulting array is of exactly the same class as the original
array.
3035 public static <T,U> T[] More ...copyOfRange(U[] original, int from, int to, Class<? extends T[]> newType) {
3036 int newLength = to - from;
3037 if (newLength < 0)
3038 throw new IllegalArgumentException(from + " > " + to);
3039 T[] copy = ((Object)newType == (Object)Object[].class)
3040 ? (T[]) new Object[newLength]
3041 : (T[]) Array.newInstance(newType.getComponentType(), newLength);
3042 System.arraycopy(original, from, copy, 0,
3043 Math.min(original.length - from, newLength));
3044 return copy;
3045 }
As you can see, both of these are just wrapper functions over System.arraycopy with defensive logic that what you are trying to do is valid.
System.arraycopy is the absolute fastest way to copy arrays.
For a null-safe copy of an array, you can also use an optional with the Object.clone() method provided in this answer.
int[] arrayToCopy = {1, 2, 3};
int[] copiedArray = Optional.ofNullable(arrayToCopy).map(int[]::clone).orElse(null);
I had a similar problem with 2D arrays and ended here.
I was copying the main array and changing the inner arrays' values and was surprised when the values changed in both copies. Basically both copies were independent but contained references to the same inner arrays and I had to make an array of copies of the inner arrays to get what I wanted.
This is sometimes called a deep copy. The same term "deep copy" can also have a completely different and arguably more complex meaning, which can be confusing, especially to someone not figuring out why their copied arrays don't behave as they should. It probably isn't the OP's problem, but I hope it can still be helpful.

How to convert an int[] array to a List?

I expected this code to display true:
int[] array = {1, 2};
System.out.println(Arrays.asList(array).contains(1));
The method Arrays.asList(T ...) is, when generics are erased and varargs are transformed, actually equal to a method of type Arrays.ofList(Object[]) (which is the, binary equivalent, JDK 1.4 version of the same Method).
An array of primitives is an Object (see also this question), but not an Object[], so the compiler thinks you are using the varargs version and generates an Object array around your int array. You could illustrate what's happening by adding an extra step:
int[] array = {1, 2};
List<int[]> listOfArrays = Arrays.asList(array);
System.out.println(listOfArrays.contains(1));
This compiles and is equivalent to your code. It also obviously returns false.
The compiler translates varargs calls into calls with a single array, so calling a varargs method that expects parameters T ... with parameters T t1, T t2, T t3 is equivalent to calling it with new T[]{t1, t2, t3} but the special case here is that varargs with primitives will be autoboxed before the array is created if the method needs an object array. So the compiler thinks the int array is passed in as a single Object and creates a single element array of type Object[], which it passes to asList().
So here's the above code once again, the way the compiler implements it internally:
int[] array = {1, 2};
// no generics because of type erasure
List listOfArrays = Arrays.asList(new Object[]{array});
System.out.println(listOfArrays.contains(1));
Here are some good and bad ways to call Arrays.asList() with int values:
// These versions use autoboxing (which is potentially evil),
// but they are simple and readable
// ints are boxed to Integers, then wrapped in an Object[]
List<Integer> good1 = Arrays.asList(1,2,3);
// here we create an Integer[] array, and fill it with boxed ints
List<Integer> good2 = Arrays.asList(new Integer[]{1,2,3});
// These versions don't use autoboxing,
// but they are very verbose and not at all readable:
// this is awful, don't use Integer constructors
List<Integer> ugly1 = Arrays.asList(
new Integer(1),new Integer(2),new Integer(3)
);
// this is slightly better (it uses the cached pool of Integers),
// but it's still much too verbose
List<Integer> ugly2 = Arrays.asList(
Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3)
);
// And these versions produce compile errors:
// compile error, type is List<int[]>
List<Integer> bad1 = Arrays.asList(new int[]{1,2,3});
// compile error, type is List<Object>
List<Integer> bad2 = Arrays.asList(new Object[]{1,2,3});
Reference:
Java Tutorial > Classes and Objects > Passing Information to a Method or a Constructor > Varargs
Arrays.asList(T ...)
But to actually solve your problem in a simple way:
There are some library solutions in Apache Commons / Lang (see Bozho's answer) and in Google Guava:
Ints.contains(int[], int) checks whether an array of ints contains a given int
Ints.asList(int ...) creates a List of Integers from an int array
The Arrays.asList(array) will result in a singleton list of an int[].
It works as you expect if you change int[] to Integer[]. Don't know if that helps you though.
Arrays.asList(ArrayUtils.toObjectArray(array))
(ArrayUtils is from commons-lang)
But if you want to just call contains there is no need of that. Simply use Arrays.binarySearch(..) (sort the array first)
This
System.out.println(Arrays.asList(array).contains(array));
returns true.
It seems like your understanding of Arrays.asList(T... a) is wrong. You wouldn't be the first person to make an assumption as to how it works.
Try it with
System.out.println(Arrays.asList(1, 2).contains(1));
Autoboxing just doesn't work the way you want it to in this case. The following code may be a bit verbose, but does the job of converting an int array to a list:
List<Integer> list = new ArrayList<Integer>(array.length);
for (int value : array) {
list.add(value);
}
The following code displays true:
Integer[] array = {1, 2};
System.out.println(Arrays.asList(array).contains(1));
(Your version fails, since Int's not beeing objects, but Int[] is an object. Therefor you will call asList(T... a) with one element beeing a Collection, since it is not possible to have an Collection a.)
When you call
Arrays.asList(array)
on your array of primitives, you get a List instance containing one object: an array of int values! You have to first convert the array of primitives into an array of objects, as #Bozho suggests in his answer.
If you only want to check whether the array contains certain element just iterate over array and search for element. This will take o(n/2). All other solutions are less effective. Any method that copies array to list must iterate over array and therefore this operation only requires n atomic assignments.
I dont think there is a method call you could use. Try it like this
List<Integer> list = new ArrayList<Integer>();
for (int index = 0; index < array.length; index++)
{
list.add(array[index]);
}

Categories

Resources