Java Arrays.asList与Arrays.stream使用forEach()的比较
如果您有一个数组,并且希望使用Java8 forEach()方法,那么哪种方法更好或更有效:Java Arrays.asList与Arrays.stream使用forEach()的比较,java,lambda,java-8,java-stream,Java,Lambda,Java 8,Java Stream,如果您有一个数组,并且希望使用Java8 forEach()方法,那么哪种方法更好或更有效: Arrays.asList(new String[]{"hallo","hi"}).forEach(System.out::println); 或 差异是否显著,或者是否有更好的解决方案。如果您已经有一个数组 String[] array; 我将使用: Arrays.stream(array).forEach(System.out::println); 因为您将数组转换为JDK的流,所以让它负责效
Arrays.asList(new String[]{"hallo","hi"}).forEach(System.out::println);
或
差异是否显著,或者是否有更好的解决方案。如果您已经有一个数组
String[] array;
我将使用:
Arrays.stream(array).forEach(System.out::println);
因为您将数组转换为JDK的流,所以让它负责效率等
但,由于并没有数组,我将使用Stream.of()
的varargs创建一个值流:
Stream.of("hallo","hi").forEach(System.out::println);
这再次让JDK承担起责任,在它认为合适的情况下高效地流式传输值。这似乎几乎没有什么不同。我为此创建了一个测试类。在五次运行过程中,我的输出如下:
Run 1:
Arrays.asList() method................: 3231 ms
Arrays.stream() method................: 3111 ms
Stream.of() method....................: 3031 ms
Arrays.asList() (premade array) method: 3086 ms
Arrays.stream() (premade array) method: 3231 ms
Stream.of() (premade array) method....: 3191 ms
Run 2:
Arrays.asList() method................: 3270 ms
Arrays.stream() method................: 3072 ms
Stream.of() method....................: 3086 ms
Arrays.asList() (premade array) method: 3002 ms
Arrays.stream() (premade array) method: 3251 ms
Stream.of() (premade array) method....: 3271 ms
Run 3:
Arrays.asList() method................: 3307 ms
Arrays.stream() method................: 3092 ms
Stream.of() method....................: 2911 ms
Arrays.asList() (premade array) method: 3035 ms
Arrays.stream() (premade array) method: 3241 ms
Stream.of() (premade array) method....: 3241 ms
Run 4:
Arrays.asList() method................: 3630 ms
Arrays.stream() method................: 2981 ms
Stream.of() method....................: 2821 ms
Arrays.asList() (premade array) method: 3058 ms
Arrays.stream() (premade array) method: 3221 ms
Stream.of() (premade array) method....: 3214 ms
Run 5:
Arrays.asList() method................: 3338 ms
Arrays.stream() method................: 3174 ms
Stream.of() method....................: 3262 ms
Arrays.asList() (premade array) method: 3064 ms
Arrays.stream() (premade array) method: 3269 ms
Stream.of() (premade array) method....: 3275 ms
从输出来看,Stream.of()
方法的效率非常低(但一致),而且
Stream.of("hallo","hi").forEach(System.out::println);
是非常可读的代码。Stream.of的优势在于它不必将数组转换为列表,也不必创建数组然后创建流,而是可以直接从元素创建流。令我稍感意外的是,由于我进行测试的方式,每次使用stream.of()
实例化一个新的数组流要比传入一个预先制作的数组快,这可能是因为“捕获”lambda(引用外部变量的lambda)的效率稍低
下面是我的测试类的代码:
import java.util.Arrays;
import java.util.function.Consumer;
import java.util.stream.Stream;
public class StreamArrayTest {
public static void main(String[] args){
System.out.println("Arrays.asList() method................: " + arraysAsListMethod() + " ms");
System.out.println("Arrays.stream() method................: " + arraysStreamMethod() + " ms");
System.out.println("Stream.of() method....................: " + streamOfMethod() + " ms");
System.out.println("Arrays.asList() (premade array) method: " + presetArraysAsListMethod() + " ms");
System.out.println("Arrays.stream() (premade array) method: " + presetArraysStreamMethod() + " ms");
System.out.println("Stream.of() (premade array) method....: " + presetStreamsOfMethod() + " ms");
}
private static Long timeOneMillion(Runnable runner){
MilliTimer mt = MilliTimer.start();
for (int i = 0; i < 1000000; i++){
runner.run();
}
return mt.end();
}
private static Long timeOneMillion(String[] strings, Consumer<String[]> consumer){
MilliTimer mt = MilliTimer.start();
for (int i = 0; i < 1000000; i++){
consumer.accept(strings);
}
return mt.end();
}
public static Long arraysAsListMethod(){
return timeOneMillion(()->Arrays.asList(new String[]{"hallo","hi","test","test2","test3","test4","test5","test6","test7","test8"}).forEach(StreamArrayTest::doSomething));
}
public static Long arraysStreamMethod(){
return timeOneMillion(()->Arrays.stream(new String[]{"hallo","hi","test","test2","test3","test4","test5","test6","test7","test8"}).forEach(StreamArrayTest::doSomething));
}
public static Long streamOfMethod(){
return timeOneMillion(()->Stream.of("hallo","hi","test","test2","test3","test4","test5","test6","test7","test8").forEach(StreamArrayTest::doSomething));
}
public static Long presetArraysAsListMethod(){
String[] strings = new String[]{"hallo","hi","test","test2","test3","test4","test5","test6","test7","test8"};
return timeOneMillion(strings, (s)->Arrays.asList(s).forEach(StreamArrayTest::doSomething));
}
public static Long presetArraysStreamMethod(){
String[] strings = new String[]{"hallo","hi","test","test2","test3","test4","test5","test6","test7","test8"};
return timeOneMillion(strings, (s)->Arrays.stream(s).forEach(StreamArrayTest::doSomething));
}
public static Long presetStreamsOfMethod(){
String[] strings = new String[]{"hallo","hi","test","test2","test3","test4","test5","test6","test7","test8"};
return timeOneMillion(strings, (s)->Stream.of(s).forEach(StreamArrayTest::doSomething));
}
public static void doSomething(String s){
String result = s;
for (int i = 0; i < 10; i++){
result = result.concat(s);
}
}
}
当您将doSomething更改为实际不执行任何操作时,如下所示:
public static void doSomething(String s){
}
然后测量这些操作的实际速度,而不是操作字符串=字符串+字符串;这就是doSomething所做的,当然它的速度是一致的。但是,实际的速度并不相同,带有预制阵列的asList要快得多
这里的实际结果已经被其他人注意到,您应该注意流,因为它通常比普通的旧java(非lambda)方法慢4倍。可能
asList
,它似乎涉及较少的对象。但在程序执行过程中,您仍然没有注意到什么。您可以编写数组。asList(“hello”,“hi”)
如果您还没有数组,则不需要创建数组。如果您已经有数组,我不理解您的。无论如何,他们需要一个数组stream
接受数组,而asList
也接受数组。@SotiriosDelimanolis“已经有一个数组”表示“不在线编码文字元素”-即数组是在中的代码外部声明和填充的question@SotiriosDelimanolis是的,可读性(在设计雷达上总是很高,我相信“代码越少越好”)性能-它更多地交给JDK(我们倾向于相信JDK“写得很好”)。为了使决策更加困难,我加了一句,如果你没有现有的数组,你也可以说Stream.of(“hallo”,“hi”).forEach(System.out::println)代码>。在长度1
的特殊情况下,这将更加有效,因为在这种情况下,不会创建任何数组。优化器更喜欢局部值。因此,使用临时数组的代码可能确实与使用准备好的数组的代码一样快,甚至更快,但是,不清楚这是否适用于您的基准测试,因为它有缺陷。您的方法doSomething
可能看起来很复杂,但实际上什么都不做,因为其中的所有内容都没有实际效果。现代JVM能够识别这一点。除此之外,您应该使用System.nanoTime()
而不是System.currentTimeMillis()
,因为后者返回的值不能保证不断向前移动。doSomething方法实际上做了一些事情。。。它实例化许多字符串对象并将它们连接在一起。如果你不相信,那就把这四行删掉,观察执行时间是如何从3200毫秒左右变为30毫秒左右的。如果你调整doSomething方法中循环的迭代次数,这也会影响执行时间。如果你删除doSomething的主体,您没有考虑各种处理方法的输入/输出。是的,可以使用Arrays.asList()
比Stream.of()
或Arrays.Stream()
更快地实例化列表,但是如果您实际上没有对数组中的值执行任何操作,则不会产生处理开销,因为优化器将识别noop方法并将其删除。doSomething()的时间应该是一致的,因为它们是完全相同的操作,剩下的大部分应该是调用各种处理方法的开销。
public class MilliTimer {
private long startTime = 0L;
private MilliTimer(long startTime){
this.startTime = startTime;
}
public static MilliTimer start(){
return new MilliTimer(System.currentTimeMillis());
}
public long end() throws IllegalArgumentException {
return System.currentTimeMillis() - startTime;
}
}
Arrays.asList() method................: 22 ms
Arrays.stream() method................: 26 ms
Stream.of() method....................: 26 ms
Arrays.asList() (premade array) method: 8 ms
Arrays.stream() (premade array) method: 30 ms
Stream.of() (premade array) method....: 17 ms
public static void doSomething(String s){
}