簡體   English   中英

使用Java 8中的供應商填充具有通用列表的數組會拋出類型擦除的ClassCastEx b / c

[英]Fill an Array with generic Lists using supplier in Java 8 throws ClassCastEx b/c of type erasure

我想使用Supplier和Stream.generate將帶有通用列表的數組填充為元素。

看起來像這樣:

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

錯誤輸出為:

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

現在,如何使用Java 8提供的技術填充具有泛型類型的數組? 或者這是不可能的(還),我必須以“經典”的方式做到這一點?

此致,Claas M.

編輯

根據@ Water的要求,我使用stream.collect(使用Cast測試數組)和傳統的迭代方法對填充數組/列表進行了一些性能測試。

首先使用列表進行性能測試:

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


}

第二個使用數組的性能測試:

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


    }

}

正如你所看到的,Water確實是對的 - Cast讓它變慢了。 但對於Lists,新方法更快; 至少從100k-1M元素。 我還是不知道為什么它對於10M Elements這么慢,我真的很想聽到一些評論。

Stream生成器仍然生成你想要的對象,唯一的問題是調用toArray()將返回一個對象數組,並且你不能從Object數組向下轉換為子對象數組(因為你有類似的東西: Object [] {ArrayList,ArrayList})。

這是一個正在發生的事情的例子:

你認為你有這個:

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

但你實際上有:

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

你回到上面的直接塊,這就是你得到一個投射錯誤的原因。

有幾種方法可以解決它。 如果你想查看你的列表,你可以很容易地從它們中制作一個數組。

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

如果您正在設置處理該功能,您可以執行以下操作:

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

根據Stream Javadocs你可以使用另一個toArray()方法,如果你想把它變成一個數組,但我還沒有探索過這個函數,所以我不想討論我不知道的事情。

認為問題是你使用toArray()而沒有返回Object []的參數。 看一眼

public <T> T[] toArray(T[] a)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM