Fill an array using shared lists using a provider in Java 8 throws ClassCastEx b / c erase type

I want to populate an array using generic lists as elements using Provider and Stream.generate.

Looks like:

Supplier<List<Object>> supplier = () -> new ArrayList<Object>(); List<Object>[] test = (List<Object>[]) Stream.generate(supplier).limit(m).toArray(); 

With the output of Error:

 Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.util.List; 

Now, how can I populate an array using a generic type using the methods provided by Java 8? Or is it just not possible (yet), and should I do it in a "classic" way?

Regards, Claas M

EDIT

In response to a @Water query, I tested several performance tests with filling out arrays / lists using stream.collect (with casting testing arrays) and the traditional iteration method.

First, performance tests using lists:

 private static int m = 100000; /** * Tests which way is faster for LISTS. * Results: * 1k Elements: about the same time (~5ms) * 10k Elements: about the same time (~8ms) * 100k Elements: new way about 1.5x as fast (~18ms vs ~27ms) * 1M Elements: new way about 2x as fast (~30ms vs ~60ms) * NOW THIS IS INTERESTING: * 10M Elements: new way about .1x as fast (~5000ms vs ~500ms) * (100M OutOfMemory after ~40Sec) * @param args */ public static void main(String[] args) { Supplier<String> supplier = () -> new String(); long startTime,endTime; //The "new" way startTime = System.currentTimeMillis(); List<String> test1 = Stream.generate(supplier).limit(m ).collect(Collectors.toList()); endTime = System.currentTimeMillis(); System.out.println(endTime - startTime); //The "old" way startTime = System.currentTimeMillis(); List<String> test2 = new ArrayList(); Iterator<String> i = Stream.generate(supplier).limit(m).iterator(); while (i.hasNext()) { test2.add(i.next()); } endTime = System.currentTimeMillis(); System.out.println(endTime - startTime); } 

And secondly, performance tests using arrays:

  private static int m = 100000000; /** * Tests which way is faster for ARRAYS. * Results: * 1k Elements: old way much faster (~1ms vs ~6ms) * 10k Elements: old way much faster (~2ms vs ~7ms) * 100k Elements: old way about 2x as fast (~7ms vs ~14ms) * 1M Elements: old way a bit faster (~50ms vs ~60ms) * 10M Elements: old way a bit faster (~5s vs ~6s) * 100M Elements: Aborted after about 5 Minutes of 100% CPU Utilisation on an i7-2600k * @param args */ public static void main(String[] args) { Supplier<String> supplier = () -> new String(); long startTime,endTime; //The "new" way startTime = System.currentTimeMillis(); String[] test1 = (String[]) Stream.generate(supplier).limit(m ).collect(Collectors.toList()).toArray(new String[m]); endTime = System.currentTimeMillis(); System.out.println(endTime - startTime); //The "old" way startTime = System.currentTimeMillis(); String[] test2 = new String[m]; Iterator<String> it = Stream.generate(supplier).iterator(); for(int i = 0; i < m; i++){ test2[i] = it.next(); } endTime = System.currentTimeMillis(); System.out.println(endTime - startTime); } } 

As you can see, Water really was right - Cast makes it slower. But for lists, the new method is faster; at least 100k - 1M elements. I still don’t know why its much slower when it comes to 10M Elements, and I would love to hear some comments about this.

+7
java arrays generics lambda
source share
2 answers

The stream generator still generates the objects you want, the only problem is calling toArray (), which will return an array of objects to you, and you cannot convert the array of objects to an array of objects (since you got something like: Object [] { ArrayList, ArrayList}).

Here is an example of what is happening:

You think you have this:

  String[] hi = { "hi" }; Object[] test = (Object[]) hi; // It still a String[] String[] out = (String[]) test; System.out.println(out[0]); // Prints 'hi' 

But you actually have:

  String[] hi = { "hi" }; Object[] test = new Object[1]; // This is not a String[] test[0] = hi[0]; String[] out = (String[]) test; // Cannot downcast, throws an exception. System.out.println(out[0]); 

You will return to the nearest block above, so you get a casting error.

There are several ways. If you want to view your list, you can easily make an array of them.

  Supplier<List<Integer>> supplier = () -> { ArrayList<Integer> a = new ArrayList<Integer>(); a.add(5); a.add(8); return a; }; Iterator<List<Integer>> i = Stream.generate(supplier).limit(3).iterator(); // This shows there are elements you can do stuff with. while (i.hasNext()) { List<Integer> list = i.next(); // You could add them to your list here. System.out.println(list.size() + " elements, [0] = " + list.get(0)); } 

If you are set to work with a function, you can do something like this:

  Supplier<List<Integer>> supplier = () -> { ArrayList<Integer> a = new ArrayList<Integer>(); a.add(5); a.add(8); return a; }; Object[] objArr = Stream.generate(supplier).limit(3).toArray(); for (Object o : objArr) { ArrayList<Integer> arrList = (ArrayList<Integer>) o; // This is not safe to do, compiler can't know this is safe. System.out.println(arrList.get(0)); } 

According to Stream Javadocs, you can use another toArray () method if you want to turn it into an array, but I haven't explored this function yet, so I don't want to discuss what I don't know.

+3
source share

Think that the problem is that you are using toArray () without parameters that return Object []. Take a look at

 public <T> T[] toArray(T[] a) 
0
source share

All Articles