Populating an array with a common list using vendors in Java 8 throws classcastex B / C with type erasure

I want to use supplier and stream Generate populates an array with a generic list as elements

It looks like this:

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

The error output is:

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

Now, how do I populate arrays with generic types using the techniques provided by Java 8? Or is it impossible (also) that I have to do it in a "classic" way?

Greetings, Klass M

edit

According to @ water's request, I use stream Collect (using cast to test the array) and the traditional iterative method do some performance tests on filling the array / list

First, use the list to test the performance:

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);


}

The second performance test 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 is really right – cast makes it slow down But for lists, the new method is faster; At least 100k-1m elements I still don't know why it's much slower for 10m elements. I really want to hear some comments

Solution

The stream generator still generates the object you want. The only problem is that calling toArray () will return an object array, and you can't convert down from the object array to the sub object array (because you have something similar: Object [] {ArrayList, ArrayList})

Here is an example of what is happening:

You think you have this:

String[] hi = { "hi" };
    Object[] test = (Object[]) hi; // It's 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 go back to the direct block above, which is why you get a projection error

There are several ways to solve it If you want to see your list, you can easily make an array

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 setting up to handle this feature, you can do the following:

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 something I don't know

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>