Java Arrays.asList与Arrays.stream使用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的流,所以让它负责效

如果您有一个数组,并且希望使用Java8 forEach()方法,那么哪种方法更好或更有效:

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