The following code (run in android) always gives me a ClassCastException in the 3rd line:
final String[] v1 = i18nCategory.translation.get(id);
final ArrayList<String> v2 = new ArrayList<String>(Arrays.asList(v1));
String[] v3 = (String[])v2.toArray();
It happens also when v2 is Object[0] and also when there are Strings in it.
Any Idea why?
This is because when you use
toArray()
it returns an Object[], which can't be cast to a String[] (even tho the contents are Strings) This is because the toArray method only gets a
List
and not
List<String>
as generics are a source code only thing, and not available at runtime and so it can't determine what type of array to create.
use
toArray(new String[v2.size()]);
which allocates the right kind of array (String[] and of the right size)
You are using the wrong toArray()
Remember that Java's generics are mostly syntactic sugar. An ArrayList doesn't actually know that all its elements are Strings.
To fix your problem, call toArray(T[]). In your case,
String[] v3 = v2.toArray(new String[v2.size()]);
Note that the genericized form toArray(T[]) returns T[], so the result does not need to be explicitly cast.
String[] v3 = v2.toArray(new String[0]);
also does the trick,
note that you don't even need to cast anymore once the right ArrayType is given to the method.
Using toArray from the JDK 11 Stream API, you can solve the more general problem this way:
Object[] v1 = new String[] {"a", "b", "c"}; // or array of another type
String[] v2 = Arrays.stream(v1)
.<String>map((Object v) -> v.toString()).toArray(String[]::new);
String[] str = new String[list.size()];
str = (String[]) list.toArray(str);
Use like this.
Related
I was working on Collection framework in Java , where i encountered a strange problem .
I made 2 lists of Strings 1 with the help of ArrayList while second was made using Arrays.asList(T ...).
After creation of these two list i tried to convert these lists into String arrays with the list.toArray() ,
as list.toArray() method call returns an object array , so i had to explicitly cast to String[] .
After casting some strange behaviour is happening as :
Case #1 : ( where list was created using ArrayList) , gives runtime exception as
java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
Case 2 : (where list as created using Arrays.asList(T ... ) ) runs fine .
here is the code
String [] str = null ,str1 = null ;
List<String> list = new ArrayList<String>();
list.add("a");
List<String> list1 = Arrays.asList("a");
str = (String[]) list.toArray(); // Runtime Exception
str1 = (String[]) list1.toArray(); // Runs Fine
An ArrayList is backed by an Object[]. A copy of that array is returned with toArray().
Returns an array containing all of the elements in this list in proper
sequence (from first to last element).
It make no guarantees on the type of array returned. But we know this from the exception's message. If you want it to return a String[], use the overloaded method provided for this reason.
str = list.toArray(new String[0]);
The cast becomes unnecessary.
The List implementation returned by Arrays.asList maintains a reference to the array (implicit or explicit) passed as its variable arity argument.
Returns a fixed-size list backed by the specified array.
The invocation
List<String> list1 = Arrays.asList("a");
creates a String[] and passes that as the argument to asList. This isn't specified clearly by the API documention, but backed by seems to indicate that it will return that same array. (Looking at the implementation, it returns a clone.) Since it is a String[], there is no error when casting and assigning it to a variable of that type.
In both cases, the appropriate solution is to use the overloaded List#toArray(T[]).
For fun, run the following and check the type of array that is returned.
List<String> list1 = (List) Arrays.<Object> asList("a");
System.out.println(list1.toArray().getClass());
Don't make assumptions. Always rely on the API documentation. If it isn't clear, try to find a better solution.
The different calls to toArray are returning arrays with different component types. You can see this by running the following code:
List<String> list = new ArrayList<String>();
list.add("a");
List<String> list1 = Arrays.asList("a");
System.out.println(list.toArray().getClass());
System.out.println(list1.toArray().getClass());
On any version of Java 8 or earlier, the result is
class [Ljava.lang.Object;
class [Ljava.lang.String;
Basically this output means Object[] and String[] respectively.
However, this is a bug. See JDK-6260652. Although it's not stated very clearly, Collection.toArray() must return an Object[] and not an array of some subtype of Object. There are a couple reasons for this.
First is that Collection.toArray() was introduced in JDK 1.2, long before generics were added to the language. There was no possibility of any collection implementation returning anything other than Object[], so for compatibility, all collections' toArray() implementations must return Object[].
The second reason is that a rather offhand comment in the specification for toArray(T[]) says:
Note that toArray(new Object[0]) is identical in function to toArray().
which again requires toArray() to return Object[] and not an array of some other type.
This bug has been fixed in JDK 9. Running the code snippet above on a recent JDK 9 build gives the following output:
class [Ljava.lang.Object;
class [Ljava.lang.Object;
The fact that Arrays.asList("a") uses a String[] for internal storage is an implementation detail. The bug where toArray() returned something other than Object[] is this implementation detail leaking out. (In fact, the array is created by the varargs machinery, using the method's type parameter as the array component type. Arrays.asList() just wraps the array it's given.)
As others have said, if you want to control the component type of the returned array, use the other overload toArray(T[]):
String[] array = list.toArray(new String[0]);
String[] array1 = list1.toArray(new String[0]);
List<String> list = new ArrayList<String>();
list.add("a");
str = (String[]) list.toArray();
In this case your list invoke method toArray() of ArrayList class. Which looks like below, it returns Object []:
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
And elementData declare:
transient Object[] elementData;
And constructor method:
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
And DEFAULTCAPACITY_EMPTY_ELEMENTDATA:
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
There for, elementData is totaly Object [] and can't be casted to any type, String etc...
With Arrays.asList(T...), it returns java.util.Arrays$ArrayList class. And java.util.Arrays$ArrayList also has toArray() method. That subtle toArray() method makes some confuse :). Here is its implementation:
public Object[] toArray() {
return a.clone();
}
And finally a field declare:
private final E[] a;
java.util.Arrays$ArrayList.toArray() able to return Object [] and actually E []. Hope this will help you :)
The key here is that Arrays.asList(..) does not return a java.util.ArrayList, but instead it returns a java.util.Arrays$ArrayList. So the .toArray() methods vary slightly.
If you want the first case to return a String[], you can change the call to
str = list.toArray(new String[0]);
Why would not it work?
List<String> lista = new ArrayList<>();
lista.add("Lol");
lista.add("ball");
String [] array = (String[])lista.toArray();
It throws a RunTimeException (ClassCastException), I am aware that there is another method for the purpose of returning the object contained in the List, however what is happening behind the scenes? I mean I am casting an array of Objects which actually is an array of Strings to an Array of Strings. So it should compile, but it does not.
Thanks in advance.
That version of toArray() returns Object[]. You can't cast an Object array into a String array even if all the objects in it are Strings.
You can use the lista.toArray(new String[lista.size()]); version to get the actual type correctly.
List.toArray()
returns an Object[], because of type erasure. At runtime your list does not know if it has String objects. From there you can see where that error is coming from.
You cannot type cast an Object[] into a String[]
Array of objects is not array of Strings and can't be cast to one.
Check this.
use toArray(T[] a) instead.
Ie.
List<String> lista = new ArrayList<String>();
lista.add("Lol");
lista.add("ball");
String [] array = lista.toArray(new string[1]);
This insures that toArray returns an array of type String[]
As others have noted, toArray() returns an array of type Object[], and the cast from Object[] to String[] is illegal.
List lista = new ArrayList<>(); ---> List lista = new ArrayList();
There are two toArray() versions.You can use another one!
I need to get a String[] out of a Set<String>, but I don't know how to do it. The following fails:
Map<String, ?> myMap = gpxlist.getAll();
Set<String> myset = myMap.keySet();
String[] GPXFILES1 = (String[]) myset.toArray(); // Here it fails.
How can I fix it so that it works?
Use the Set#toArray(IntFunction<T[]>) method taking an IntFunction as generator.
String[] GPXFILES1 = myset.toArray(String[]::new);
If you're not on Java 11 yet, then use the Set#toArray(T[]) method taking a typed array argument of the same size.
String[] GPXFILES1 = myset.toArray(new String[myset.size()]);
While still not on Java 11, and you can't guarantee that myset is unmodifiable at the moment of conversion to array, then better specify an empty typed array.
String[] GPXFILES1 = myset.toArray(new String[0]);
Java 11
The new default toArray method in Collection interface allows the elements of the collection to be transferred to a newly created array of the desired runtime type. It takes IntFunction<T[]> generator as argument and can be used as:
String[] array = set.toArray(String[]::new);
There is already a similar method Collection.toArray(T[]) and this addition means we no longer be able to pass null as argument because in that case reference to the method would be ambiguous. But it is still okay since both methods throw a NPE anyways.
Java 8
In Java 8 we can use streams API:
String[] array = set.stream().toArray(String[]::new);
We can also make use of the overloaded version of toArray() which takes IntFunction<A[]> generator as:
String[] array = set.stream().toArray(n -> new String[n]);
The purpose of the generator function here is to take an integer (size of desired array) and produce an array of desired size. I personally prefer the former approach using method reference than the later one using lambda expression.
Use toArray(T[] a) method:
String[] array = set.toArray(new String[0]);
Guava style:
Set<String> myset = myMap.keySet();
FluentIterable.from(mySet).toArray(String.class);
more info: https://google.github.io/guava/releases/19.0/api/docs/com/google/common/collect/FluentIterable.html
In Java 11 we can use Collection.toArray(generator) method. The following code will create a new array of String:
Set<String> set = Set.of("one", "two", "three");
String[] array = set.toArray(String[]::new)
See: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Collection.html#toArray(java.util.function.IntFunction)
Set<String> stringSet= new HashSet<>();
String[] s = (String[])stringSet.toArray();
I was facing the same situation.
I begin by declaring the structures I need:
Set<String> myKeysInSet = null;
String[] myArrayOfString = null;
In my case, I have a JSON object and I need all the keys in this JSON to be stored in an array of strings. Using the GSON library, I use JSON.keySet() to get the keys and move to my Set :
myKeysInSet = json_any.keySet();
With this, I have a Set structure with all the keys, as I needed it. So I just need to the values to my Array of Strings. See the code below:
myArrayOfString = myKeysInSet.toArray(new String[myKeysInSet.size()]);
This was my first answer in StackOverflow.
Sorry for any error :D
The following code (run in android) always gives me a ClassCastException in the 3rd line:
final String[] v1 = i18nCategory.translation.get(id);
final ArrayList<String> v2 = new ArrayList<String>(Arrays.asList(v1));
String[] v3 = (String[])v2.toArray();
It happens also when v2 is Object[0] and also when there are Strings in it.
Any Idea why?
This is because when you use
toArray()
it returns an Object[], which can't be cast to a String[] (even tho the contents are Strings) This is because the toArray method only gets a
List
and not
List<String>
as generics are a source code only thing, and not available at runtime and so it can't determine what type of array to create.
use
toArray(new String[v2.size()]);
which allocates the right kind of array (String[] and of the right size)
You are using the wrong toArray()
Remember that Java's generics are mostly syntactic sugar. An ArrayList doesn't actually know that all its elements are Strings.
To fix your problem, call toArray(T[]). In your case,
String[] v3 = v2.toArray(new String[v2.size()]);
Note that the genericized form toArray(T[]) returns T[], so the result does not need to be explicitly cast.
String[] v3 = v2.toArray(new String[0]);
also does the trick,
note that you don't even need to cast anymore once the right ArrayType is given to the method.
Using toArray from the JDK 11 Stream API, you can solve the more general problem this way:
Object[] v1 = new String[] {"a", "b", "c"}; // or array of another type
String[] v2 = Arrays.stream(v1)
.<String>map((Object v) -> v.toString()).toArray(String[]::new);
String[] str = new String[list.size()];
str = (String[]) list.toArray(str);
Use like this.
I use the following code to convert an Object array to a String array :
Object Object_Array[]=new Object[100];
// ... get values in the Object_Array
String String_Array[]=new String[Object_Array.length];
for (int i=0;i<String_Array.length;i++) String_Array[i]=Object_Array[i].toString();
But I wonder if there is another way to do this, something like :
String_Array=(String[])Object_Array;
But this would cause a runtime error: Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
What's the correct way to do it ?
Another alternative to System.arraycopy:
String[] stringArray = Arrays.copyOf(objectArray, objectArray.length, String[].class);
In Java 8:
String[] strings = Arrays.stream(objects).toArray(String[]::new);
To convert an array of other types:
String[] strings = Arrays.stream(obj).map(Object::toString).
toArray(String[]::new);
System.arraycopy is probably the most efficient way, but for aesthetics, I'd prefer:
Arrays.asList(Object_Array).toArray(new String[Object_Array.length]);
I see that some solutions have been provided but not any causes so I will explain this in detail as I believe it is as important to know what were you doing wrong that just to get "something" that works from the given replies.
First, let's see what Oracle has to say
* <p>The returned array will be "safe" in that no references to it are
* maintained by this list. (In other words, this method must
* allocate a new array even if this list is backed by an array).
* The caller is thus free to modify the returned array.
It may not look important but as you'll see it is... So what does the following line fail? All object in the list are String but it does not convert them, why?
List<String> tList = new ArrayList<String>();
tList.add("4");
tList.add("5");
String tArray[] = (String[]) tList.toArray();
Probably, many of you would think that this code is doing the same, but it does not.
Object tSObjectArray[] = new String[2];
String tStringArray[] = (String[]) tSObjectArray;
When in reality the written code is doing something like this. The javadoc is saying it! It will instatiate a new array, what it will be of Objects!!!
Object tSObjectArray[] = new Object[2];
String tStringArray[] = (String[]) tSObjectArray;
So tList.toArray is instantiating a Objects and not Strings...
Therefore, the natural solution that has not been mentioning in this thread, but it is what Oracle recommends is the following
String tArray[] = tList.toArray(new String[0]);
Hope it is clear enough.
The google collections framework offers quote a good transform method,so you can transform your Objects into Strings. The only downside is that it has to be from Iterable to Iterable but this is the way I would do it:
Iterable<Object> objects = ....... //Your chosen iterable here
Iterable<String> strings = com.google.common.collect.Iterables.transform(objects, new Function<Object, String>(){
String apply(Object from){
return from.toString();
}
});
This take you away from using arrays,but I think this would be my prefered way.
This one is nice, but doesn't work as mmyers noticed, because of the square brackets:
Arrays.toString(objectArray).split(",")
This one is ugly but works:
Arrays.toString(objectArray).replaceFirst("^\\[", "").replaceFirst("\\]$", "").split(",")
If you use this code you must be sure that the strings returned by your objects' toString() don't contain commas.
If you want to get a String representation of the objects in your array, then yes, there is no other way to do it.
If you know your Object array contains Strings only, you may also do (instread of calling toString()):
for (int i=0;i<String_Array.length;i++) String_Array[i]= (String) Object_Array[i];
The only case when you could use the cast to String[] of the Object_Array would be if the array it references would actually be defined as String[] , e.g. this would work:
Object[] o = new String[10];
String[] s = (String[]) o;
You can use type-converter.
To convert an array of any types to array of strings you can register your own converter:
TypeConverter.registerConverter(Object[].class, String[].class, new Converter<Object[], String[]>() {
#Override
public String[] convert(Object[] source) {
String[] strings = new String[source.length];
for(int i = 0; i < source.length ; i++) {
strings[i] = source[i].toString();
}
return strings;
}
});
and use it
Object[] objects = new Object[] {1, 23.43, true, "text", 'c'};
String[] strings = TypeConverter.convert(objects, String[].class);
For your idea, actually you are approaching the success, but if you do like this should be fine:
for (int i=0;i<String_Array.length;i++) String_Array[i]=(String)Object_Array[i];
BTW, using the Arrays utility method is quite good and make the code elegant.
Object arr3[]=list1.toArray();
String common[]=new String[arr3.length];
for (int i=0;i<arr3.length;i++)
{
common[i]=(String)arr3[i];
}
Easily change without any headche
Convert any object array to string array
Object drivex[] = {1,2};
for(int i=0; i<drive.length ; i++)
{
Str[i]= drivex[i].toString();
System.out.println(Str[i]);
}