Difference in containsAll behavior for Integer and int arrays (Java) - java

Could someone possibly explain why the following:
Integer[] arr1 = {1,2,3,4,5};
Collection<?> numbers = Arrays.asList(new Integer[]{1,2,3});
System.out.println(Arrays.asList(arr1).containsAll(numbers));
print "true", while if we exchange Integer for int like so:
int[] arr2 = {1,2,3,4,5};
Collection<?> numbers2 = Arrays.asList(new int[]{1,2,3});
System.out.println(Arrays.asList(arr2).containsAll(numbers2));
"false" is printed?

In the second case, each list consists of a single element. The two elements are both int[] arrays. The list containing the larger array does not contain the member of the list containing the smaller array.
The Arrays.asList() method accepts a variable argument list of arguments of type T, and returns a List<T>. With an array of Integers, T can be Integer, and the return type List. But with a primitive array, T cannot be an int, because there cannot be a List<int>.

List is a collection of objects and it works great if you put objects in it. As you are trying to create a list using primitive array, JVM is kind enough not to throw an exception but it is not able to create the list as you desired. And hence you see a difference in outputs when you you create a list with Integer array, which is valid and when you create a list with int array which is syntactically correct but logically against the principle of Collections.

according to this: What is the difference between an int and an Integer in Java and C#?
Integer is an Object and int is a primitive tho they are not directly the same...
So in the Java docs the Collection.containsAll(Object o) wants a Object and not a primitive.
Maybe this explains the different
http://docs.oracle.com/javase/6/docs/api/java/util/Collection.html#contains(java.lang.Object)
Didn't know this myself before thanks a lot for your Question.

Related

How does array.sort work with multidimensional arrays?

I've been looking around on the internet trying to find out how to sort a multidimensional array by column and i found a way that works but I'm not sure exactly how it works. Can someone explain it to me?
Arrays.sort(data, (int[] num1, int[] num2) ->
Integer number1 = num1[1];
Integer number2 = num2[1];
return number2.compareTo(number1);
});
in this care the code sorts the array [][] in descending order by the second column.
A two dimensional array is an array whose elements are arrays (int[] in your case). Therefore, in order to sort such an array, you should supply a comparator that compares int[] objects. This is exactly what the lambda expression in your code snippet does. It accepts two int[] objects and determines their relative order by comparing the elements at the second position (i.e. index 1) of the two arrays.
The lambda expression is a feature added in Java 8. It allows you to supply an implementation to a functional interface (which is an interface with a single method, such as Comparator<int[]>, whose single method is int compare (int[] first, int[] second)) without most of the syntax required for anonymous class instances.

Is it bug of JDK?

This code throw
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 1
on last line. Is it bug or what? (JDK 7)
int ar[] = {1,2,3};
List arList = Arrays.asList(ar);
arList.set(1,8);
No, Arrays.asList expects Integer [], but you are passing int[]. This should fix it.
Integer ar[] = {1,2,3};
This is what my inspection says about using a primitive array where a var-arg type is expected.
Reports any calls to a variable-argument method which has a primitive array in in the variable-argument position (e.g System.out.printf("%s", new int[]{1, 2, 3}) ). Such a primitive-array argument may be confusing, as it will wrapped as a single-element array, rather than each individual element being boxed, as might be expected.
This means that what you have is a List with only one element in it. And this element is your int[].
And you can't access position 1 in this list since there's only one element. Thus arList.set(1,8); will throw ArrayIndexOutOfBoundsException.
To avoid this kind of error, never use raw types, instead prefer generic types. You want a List of Integers?
Try this:
int ar[] = {1,2,3};
List<Integer> arList = Arrays.asList(ar); // here
arList.set(1,8);
The compiler will show an error in the line where I wrote the comment, indicating that this will not work. When ar is a primitive array, int[] in your case, then Arrays.asList(ar) will return a List<int[]>. List<int[]> and List<Integer> are not compatible. What you have right now is a List of int[] with 1 entry (at index 0), being your array.
As mentioned before, if you change from primitive int ar[] = {1,2,3}; to object Integer ar[] = {1,2,3}; it will work, because the return type of Arrays.asList(ar) will be List<Integer>.
The reason of the specified behavior is clear, but there is nothing about this situation in the javadoc for the Arrays.asList() and no check was made for the primitive arrays as input parameters. So, I think this should be treated like a bug.
Method javadoc:
Returns a fixed-size list backed by the specified array. (Changes to the returned list "write through" to the array.) This method acts as bridge between array-based and collection-based APIs, in combination with {#link Collection#toArray}. The returned list is erializable and implements {#link RandomAccess}. This method also provides a convenient way to create a fixed-size list initialized to contain several elements

How Arrays.asList(int[]) can return List<int[]>?

While doing simple program I noticed this issue.
int[] example = new int[10];
List<Integer> exampleList = Arrays.asList(example);// Compilation error here
Compilation error is returned as cannot convert from List<int[]> to List<Integer>. But List<int> is not permitted in java so why this kind of compilation error?
I am not questioning about autoboxing here I just wondered how Arrays.asList can return List<int[]>.
asList implementation is
public static <T> List<T> asList(T... a) {
return new ArrayList<T>(a);
}
So it is treating int[] as T that is why this is happening.
There is no automatic autoboxing done of the underlying ints in Arrays.asList.
int[] is actually an object, not a primitive.
Here Arrays.asList(example) returns List<int[]>. List<int> is indeed invalid syntax.
You could use:
List<Integer> exampleList = Arrays.asList(ArrayUtils.toObject(array));
using Apache Commons ArrayUtils.
Arrays.asList(...) works perfectly to transform an array of objects into a list of those objects.
Also, Arrays.asList(...) is defined in Java 5 with a varag construct, or, in order words, it can accept an undefined number of parameters in which case it will consider all of those parameters as members of an array and then return a List instance containing those elements.
List<Object> objList = Arrays.asList(obj1, obj2, obj3);
That means you can create a list with a single element:
List<Object> objList = Arrays.asList(obj1);
Since List<int> is not permitted in Java, when you use a int[] array as parameter for Arrays.asList it will consider it as the single element of a list instead of an array of int. That's because arrays are objects by themselves in Java while an int (and any other primitive) is not.
So, when converting an array of primitives, Arrays.asList will try to return a list of primitive arrays:
List<int[]> intArrayList = Arrays.asList(new int[]{ 1, 2, 3 });
The signature <T> List<T> asList(T... os) involves a generic type T. The extent of generic types covers only reference types (including array types), but not primitive types. Therefore in an invocation Arrays.asList(ints) with int[] ints the T can only be resolved to int[].
On a higher level, the purpose of Arrays.asList is to provide a list view of your array. That means that the array stays untouched and its elements are made available through an object implementing List. However, Lists can only contain objects and your array contains primitive ints. That makes the array uneligible for being exposed through a List interface.
Anyway, if you are looking for an elegant syntax to create a list of Integers, write Arrays.asList(1,2,3).
Arrays are objects in java, not primitive types. Note that it says List<int[]> (list of int-arrays), not List<int>.

Convert ArrayList<String> to String[] array [duplicate]

This question already has answers here:
Converting 'ArrayList<String> to 'String[]' in Java
(17 answers)
Closed 8 years ago.
I'm working in the android environment and have tried the following code, but it doesn't seem to be working.
String [] stockArr = (String[]) stock_list.toArray();
If I define as follows:
String [] stockArr = {"hello", "world"};
it works. Is there something that I'm missing?
Use like this.
List<String> stockList = new ArrayList<String>();
stockList.add("stock1");
stockList.add("stock2");
String[] stockArr = new String[stockList.size()];
stockArr = stockList.toArray(stockArr);
for(String s : stockArr)
System.out.println(s);
Try this
String[] arr = list.toArray(new String[list.size()]);
What is happening is that stock_list.toArray() is creating an Object[] rather than a String[] and hence the typecast is failing1.
The correct code would be:
String [] stockArr = stockList.toArray(new String[stockList.size()]);
or even
String [] stockArr = stockList.toArray(new String[0]);
For more details, refer to the javadocs for the two overloads of List.toArray.
The latter version uses the zero-length array to determine the type of the result array. (Surprisingly, it is faster to do this than to preallocate ... at least, for recent Java releases. See https://stackoverflow.com/a/4042464/139985 for details.)
From a technical perspective, the reason for this API behavior / design is that an implementation of the List<T>.toArray() method has no information of what the <T> is at runtime. All it knows is that the raw element type is Object. By contrast, in the other case, the array parameter gives the base type of the array. (If the supplied array is big enough to hold the list elements, it is used. Otherwise a new array of the same type and a larger size is allocated and returned as the result.)
1 - In Java, an Object[] is not assignment compatible with a String[]. If it was, then you could do this:
Object[] objects = new Object[]{new Cat("fluffy")};
Dog[] dogs = (Dog[]) objects;
Dog d = dogs[0]; // Huh???
This is clearly nonsense, and that is why array types are not generally assignment compatible.
An alternative in Java 8:
String[] strings = list.stream().toArray(String[]::new);
I can see many answers showing how to solve problem, but only Stephen's answer is trying to explain why problem occurs so I will try to add something more on this subject. It is a story about possible reasons why Object[] toArray wasn't changed to T[] toArray where generics ware introduced to Java.
Why String[] stockArr = (String[]) stock_list.toArray(); wont work?
In Java, generic type exists at compile-time only. At runtime information about generic type (like in your case <String>) is removed and replaced with Object type (take a look at type erasure). That is why at runtime toArray() have no idea about what precise type to use to create new array, so it uses Object as safest type, because each class extends Object so it can safely store instance of any class.
Now the problem is that you can't cast instance of Object[] to String[].
Why? Take a look at this example (lets assume that class B extends A):
//B extends A
A a = new A();
B b = (B)a;
Although such code will compile, at runtime we will see thrown ClassCastException because instance held by reference a is not actually of type B (or its subtypes). Why is this problem (why this exception needs to be cast)? One of the reasons is that B could have new methods/fields which A doesn't, so it is possible that someone will try to use these new members via b reference even if held instance doesn't have (doesn't support) them. In other words we could end up trying to use data which doesn't exist, which could lead to many problems. So to prevent such situation JVM throws exception, and stop further potentially dangerous code.
You could ask now "So why aren't we stopped even earlier? Why code involving such casting is even compilable? Shouldn't compiler stop it?". Answer is: no because compiler can't know for sure what is the actual type of instance held by a reference, and there is a chance that it will hold instance of class B which will support interface of b reference. Take a look at this example:
A a = new B();
// ^------ Here reference "a" holds instance of type B
B b = (B)a; // so now casting is safe, now JVM is sure that `b` reference can
// safely access all members of B class
Now lets go back to your arrays. As you see in question, we can't cast instance of Object[] array to more precise type String[] like
Object[] arr = new Object[] { "ab", "cd" };
String[] arr2 = (String[]) arr;//ClassCastException will be thrown
Here problem is a little different. Now we are sure that String[] array will not have additional fields or methods because every array support only:
[] operator,
length filed,
methods inherited from Object supertype,
So it is not arrays interface which is making it impossible. Problem is that Object[] array beside Strings can store any objects (for instance Integers) so it is possible that one beautiful day we will end up with trying to invoke method like strArray[i].substring(1,3) on instance of Integer which doesn't have such method.
So to make sure that this situation will never happen, in Java array references can hold only
instances of array of same type as reference (reference String[] strArr can hold String[])
instances of array of subtype (Object[] can hold String[] because String is subtype of Object),
but can't hold
array of supertype of type of array from reference (String[] can't hold Object[])
array of type which is not related to type from reference (Integer[] can't hold String[])
In other words something like this is OK
Object[] arr = new String[] { "ab", "cd" }; //OK - because
// ^^^^^^^^ `arr` holds array of subtype of Object (String)
String[] arr2 = (String[]) arr; //OK - `arr2` reference will hold same array of same type as
// reference
You could say that one way to resolve this problem is to find at runtime most common type between all list elements and create array of that type, but this wont work in situations where all elements of list will be of one type derived from generic one. Take a look
//B extends A
List<A> elements = new ArrayList<A>();
elements.add(new B());
elements.add(new B());
now most common type is B, not A so toArray()
A[] arr = elements.toArray();
would return array of B class new B[]. Problem with this array is that while compiler would allow you to edit its content by adding new A() element to it, you would get ArrayStoreException because B[] array can hold only elements of class B or its subclass, to make sure that all elements will support interface of B, but instance of A may not have all methods/fields of B. So this solution is not perfect.
Best solution to this problem is explicitly tell what type of array toArray() should be returned by passing this type as method argument like
String[] arr = list.toArray(new String[list.size()]);
or
String[] arr = list.toArray(new String[0]); //if size of array is smaller then list it will be automatically adjusted.
The correct way to do this is:
String[] stockArr = stock_list.toArray(new String[stock_list.size()]);
I'd like to add to the other great answers here and explain how you could have used the Javadocs to answer your question.
The Javadoc for toArray() (no arguments) is here. As you can see, this method returns an Object[] and not String[] which is an array of the runtime type of your list:
public Object[] toArray()
Returns an array containing all of the
elements in this collection. If the collection makes any guarantees as
to what order its elements are returned by its iterator, this method
must return the elements in the same order. The returned array will be
"safe" in that no references to it are maintained by the collection.
(In other words, this method must allocate a new array even if the
collection is backed by an Array). The caller is thus free to modify
the returned array.
Right below that method, though, is the Javadoc for toArray(T[] a). As you can see, this method returns a T[] where T is the type of the array you pass in. At first this seems like what you're looking for, but it's unclear exactly why you're passing in an array (are you adding to it, using it for just the type, etc). The documentation makes it clear that the purpose of the passed array is essentially to define the type of array to return (which is exactly your use case):
public <T> T[] toArray(T[] a)
Returns an array containing all of the
elements in this collection; the runtime type of the returned array is
that of the specified array. If the collection fits in the specified
array, it is returned therein. Otherwise, a new array is allocated
with the runtime type of the specified array and the size of this
collection. If the collection fits in the specified array with room to
spare (i.e., the array has more elements than the collection), the
element in the array immediately following the end of the collection
is set to null. This is useful in determining the length of the
collection only if the caller knows that the collection does not
contain any null elements.)
If this collection makes any guarantees as to what order its elements
are returned by its iterator, this method must return the elements in
the same order.
This implementation checks if the array is large enough to contain the
collection; if not, it allocates a new array of the correct size and
type (using reflection). Then, it iterates over the collection,
storing each object reference in the next consecutive element of the
array, starting with element 0. If the array is larger than the
collection, a null is stored in the first location after the end of
the collection.
Of course, an understanding of generics (as described in the other answers) is required to really understand the difference between these two methods. Nevertheless, if you first go to the Javadocs, you will usually find your answer and then see for yourself what else you need to learn (if you really do).
Also note that reading the Javadocs here helps you to understand what the structure of the array you pass in should be. Though it may not really practically matter, you should not pass in an empty array like this:
String [] stockArr = stockList.toArray(new String[0]);
Because, from the doc, this implementation checks if the array is large enough to contain the collection; if not, it allocates a new array of the correct size and type (using reflection). There's no need for the extra overhead in creating a new array when you could easily pass in the size.
As is usually the case, the Javadocs provide you with a wealth of information and direction.
Hey wait a minute, what's reflection?

Should we use type cast for the object.toArray()?

String[] a = c.toArray(new String[0]);
First: Do I need type cast here? (I think we should write like (String[])c.toArray(); BUT I have seen it as just c.toArray() without using type cast. Is this valid?
Second: Also why we write new String[0]?
The type cast is usually only needed if you're using pre-generics Java. If you look at the docs for Collection.toArray(T[]) you'll see that it knows that the type of the array which is returned is the same as the type of array passed in. So, you can write:
List<String> list = new ArrayList<String>();
list.add("Foo");
String[] array = list.toArray(new String[0]);
You pass in the array to tell the collection what result type you want, which may not be the same as the type in the collection. For example, if you have a List<OutputStream> you may want to convert that to an Object[], a Stream[] or a ByteArrayOutputStream[] - obviously the latter is only going to work if every element actually is a ByteArrayOutputStream. It also means that if you already have an array of the right type and size, the contents can be copied into that instead of creating a new array.
A previous version of this answer was inaccurate, by the way - if you use the overload which doesn't take any parameters, you always get back an Object[] which can't be cast:
List<String> list = new ArrayList<String>();
list.add("Foo");
// toArray doesn't know the type of array to create
// due to type erasure
Object[] array = list.toArray();
// This cast will fail at execution time
String[] stringArray = (String[]) arrray;
EDIT: I've just noticed this is also mentioned in erdemoo's answer, but it can't hurt to have it here too :)
if you are using list.toArray(), it will return you Object array.
Casting to String array will throw exception even if elements stored in list are String type.
if you are using list.toArray(Object[] a), it will store elements in list to "a" array. If the elements inside the list are String and you give String array then it will store elements inside String array, if given array is not large enough to store elements inside the list, then it will expand given list.
Yes you need the downcast since toArray's returns type is Object[].
You need to pass (new String[0]) as a parameter since the method needs to know what kind of array it should return (array of strings, Dates, etc.) Internally all list elements are actually objects so the list does not know the type of elements it is holding and therefore it does not know which kind of array it should return, unless you provide it as a parameter.

Categories

Resources