Varargs methods and primitive types [duplicate] - java

This question already has answers here:
Arrays.asList() not working as it should?
(12 answers)
Closed 4 years ago.
In Effective Java J. Bloch mentioned that it was not safe to use varargs method with primitive types. Percisely, Arrays.asList(1, 2, 4) had return type List<int[]> and it sounds quite reasonble. Now I tried to reproduce this behaviour myself and couldn't:
My question is why is the type deduced to List<Integer> but not to List<int[]> as he stated? Does it mean, that in Java 8 the problem about varargs is not relevant anymore and we can safely use them anywhere we want if we don't care about performance too much.

Author most probably meant that you can't pass array of primitive type elements and expect it to be boxed like
int[] intArray = {1,2,3};
Arrays.asList(intArray);
which will return List<int[]> not List<Integer> since there is no autoboxing of arrays like int[]->Integer[] so only possible type which can be used by T... vararg is int[] since generic type T can't represent primitive type.
Other possible problem is that you are reading first edition of book (released in 2001) but autoboxing was added in Java 1.5 (Java 5.0) which was released in 2004.

Related

Why arrays can be used in the generic in JAVA? [duplicate]

This question already has answers here:
Primitive arrays as a generic parameter [duplicate]
(4 answers)
Closed 1 year ago.
int is primitive type in java. Why is int[] usable as a generic type?
I can write code like this and compile it.
List<int[]> test = new ArrayList<>();
Indeed int is a primitive however an array of integers, int[], isn't.
Java Docs define an array as,
An array is a container object that holds a fixed number of values of
a single type.
As you can see an array is an object with class hierarchy as following,
java.lang.Object
java.util.Arrays
So arrays in java are basically objects of type java.util.Arrays. The same class also provides all the good operations you can perform on Arrays.
Back to your question, you're right, Java doesn't allow passing primitives as type parameter when you're using generics.
You cannot do this,
List<int> test = new ArrayList<int>();
However you can do generics with Integer class just fine,
List<Integer> test = new ArrayList<Integer>();
The reasons for not allowing primitives are discussed here on stackoverflow.
One might think, Java does support autoboxing so why not simply autobox primitives to their equivalent classes. Well that is a design choice. Primitives are efficient and cost less memory. Designers probably rightly decided to not assume autoboxing would serve equivalent efficiency.

Why do not Java Generics support primitive types? [duplicate]

This question already has answers here:
Why don't Java Generics support primitive types?
(5 answers)
Closed 2 years ago.
The following is an example of an error that is incorrectly specified. How should I fix it and why did I get an error?
Vector <int> vi = new Vector <int> ();
Java generics don't support primitive types like int. You can use the java.lang.Integer wrapper class instead:
Vector <Integer> vi = new Vector<Integer>();
As a side note, while Vector isn't officially deprecated, it's been considered outdated since JDK 1.2, and you should probably use an ArrayList instead.

Why does Arrays.asList(...).toArray().getClass() give different results in JDK 8 and 9? [duplicate]

This question already has answers here:
array cast Java 8 vs Java 9
(2 answers)
Closed 4 years ago.
Why does the following condition return true with JDK 8, whereas it returns false with JDK 9?
String[].class == Arrays.asList("a", "b").toArray().getClass()
The List type returned by asList is Arrays$ArrayList. The toArray method in JDK 8 on that class is:
#Override
public Object[] toArray() {
return a.clone();
}
But in JDK 9+ it is:
#Override
public Object[] toArray() {
return Arrays.copyOf(a, a.length, Object[].class);
}
In both cases a String[] is passed to asList, but in the JDK 8 case it is cloned, which retains its array type (String[]), and in JDK 9+ it is copied using Arrays.copyOf with the explicit new array type of Object[].
This difference means that in JDK 8 Arrays.asList("a", "b").toArray().getClass() returns String[] and in JDK 9+ it returns Object[], so in JDK 9+ your expression will evaluate to false.
The reason for this change comes from JDK-6260652 with the motivation:
The Collection documentation claims that
collection.toArray()
is "identical in function" to
collection.toArray(new Object[0]);
However, the implementation of Arrays.asList does not follow this: If created with an array of a subtype (e.g. String[]), its toArray() will return an array of the same type (because it use clone()) instead of an Object[].
If one later tries to store non-Strings (or whatever) in that array, an ArrayStoreException is thrown.
So this change was made to fix the previous behaviour.
If this is a problem for you, the related release note offers this as a work-around:
If this problem occurs, rewrite the code to use the one-arg form toArray(T[]), and provide an instance of the desired array type. This will also eliminate the need for a cast.
String[] array = list.toArray(new String[0]);
I would say that this was a bug in JDK 8 and before that has been fixed.
List<T>.toArray() was always declared as returning Object[] (see JavaDoc) - that it did in effect return String[] in a special case was a mistake.

The difference between int[] and Integer[] and why are they treated differently? [duplicate]

This question already has answers here:
Arrays.asList() not working as it should?
(12 answers)
Closed 4 years ago.
I've got two pieces of code, in both the main focus is the method Arrays.asList(T... a).
In the first of them I input an Integer[], in the second I input an int[] , and - this is the part that confuses me, in the two cases, the resulting List<...> is different:
Integer[] arrayBoxed = new Integer[10];
List<Integer> list = Arrays.asList(arrayBoxed);
It's pretty short, and none of the values in arrayBoxed are set, but it works, and produces an List<Integer>.
int[] array = new int[10];
List<int[]> list = Arrays.asList(array);
In this case, for some reason, I get a List<int[]>, which is a pretty pathological construct.
Why is that?
The problem is, that given the similar input into Arrays.asList, I'd expect both of the functions to output the same (both code pieces are fully functional). However, one time the method returns List<Integer>, the other time List<int[]>.
Arrays.asList takes an array of reference types, not primitive types.
So, when you call Arrays.asList(int[]), the reference type taken is int[] (the array type), and that's why the result is List<int[]>.
Integer is a reference type, which explains why List<Integer> is the return type.

Why primitive datatypes are not allowed in java.util.ArrayList? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Storing primitive values in a Java collection?
ArrayList accepts only reference types as its element, not primitive datatypes.
When trying to do so it produces a compile time error.
What is the concept behind this? It seems like a limitation, is it not?
All collection classes of java store memory location of the objects they collect. The primitive values do not fit in to the same definition.
To circumvent this problem, JDK5 and onwards have autoboxing - wherein the primitives are converted to appropriate objects and back when they are added or read from the collections. Refer to the official JDK tutorial on this topic.
Checking the JDK5 source code for ArrayList helps better understanding: creating an ArrayList<E> includes casting an Object[] array to E[].
Because Java can only use class (and not primitive types) and arrays (also arrays for primitives) for generics (between < and >).
List list; That is also a reason why there are wrapper classes for primitive types:
int -> Integer
boolean -> Boolean
double -> Double
byte -> Byte etc...

Categories

Resources