Cla*_* M. 7 java arrays generics lambda
我想使用Supplier和Stream.generate将带有通用列表的数组填充为元素.
看起来像这样:
Supplier<List<Object>> supplier = () -> new ArrayList<Object>();
List<Object>[] test = (List<Object>[]) Stream.generate(supplier).limit(m).toArray();
Run Code Online (Sandbox Code Playgroud)
错误输出为:
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.util.List;
Run Code Online (Sandbox Code Playgroud)
现在,如何使用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);
}
Run Code Online (Sandbox Code Playgroud)
第二个使用数组的性能测试:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
正如你所看到的,Water确实是对的 - Cast让它变慢了.但对于Lists,新方法更快; 至少从100k-1M元素.我还是不知道为什么它对于10M Elements这么慢,我真的很想听到一些评论.
Stream 生成器仍然生成您想要的对象,唯一的问题是调用 toArray() 会给您返回一个对象数组,并且您不能从对象数组向下转换为子对象数组(因为您已经得到了类似的东西:对象[] { 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'
Run Code Online (Sandbox Code Playgroud)
但你实际上有:
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]);
Run Code Online (Sandbox Code Playgroud)
您将返回上面的直接块,这就是您收到转换错误的原因。
有几种方法可以解决这个问题。如果你想查看你的列表,你可以轻松地用它们创建一个数组。
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));
}
Run Code Online (Sandbox Code Playgroud)
如果您决定处理该函数,您可以执行以下操作:
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));
}
Run Code Online (Sandbox Code Playgroud)
根据Stream Javadocs,如果您想将其转换为数组,可以使用其他 toArray() 方法,但我还没有探索过这个函数,所以我不想讨论我不知道的东西。
| 归档时间: |
|
| 查看次数: |
4642 次 |
| 最近记录: |