Arrays.asList vs. Arrays.stream to use forEach()

前端 未结 3 783
生来不讨喜
生来不讨喜 2020-12-31 05:12

If you have an Array and you want to use the Java8 forEach() method, which approach is better or more efficient:

Arrays.asList(new String[]{\"hallo\",\"hi\"}         


        
相关标签:
3条回答
  • 2020-12-31 05:52

    Neither. If you already had an array,

    String[] array;
    

    I would use:

    Arrays.stream(array).forEach(System.out::println);
    

    because you leave the conversion of the array to a stream to the JDK - let it be responsible for efficiency etc.

    But, since you don't have an array, I would use Stream.of()'s varargs to create a stream of the values:

    Stream.of("hallo","hi").forEach(System.out::println);
    

    Which again lets the JDK take the responsibility of efficiently streaming the values as it sees fit.

    0 讨论(0)
  • 2020-12-31 05:53
    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
    

    When you change doSomething to actually do nothing as follows:

    public static void doSomething(String s){
    }
    

    Then you're measuring the actual speed of these operations instead of the operation String = String + String; This is what doSomething was doing, and of course it is about the same speed consistently. However, the actual speed isn't the same and asList with a premade array is much faster.

    The real result here has already been noted by others that you should beware of the stream as it is typically 4 times slower than the plain old java (non-lambda) approach.

    0 讨论(0)
  • 2020-12-31 06:04

    It seems to make almost absolutely no difference. I created a test class for this. Over the course of five runs, my output was this:

    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
    

    From the output, It looks like the Stream.of() method is very marginally (but consistently) the most efficent, and

    Stream.of("hallo","hi").forEach(System.out::println);
    

    is very readable code. Stream.of has the advantage in that it doesn't have to convert the array into a list, or create an array and then create a stream, but can create a stream directly from the elements. What was mildly surprising to me, was that because of the way I did my tests, it was faster to instantiate a new array stream each time with Stream.of() than it was to pass in a pre-made array, probably because "capturing" lambdas - those that reference an external variable - are a little less efficient.

    Here's the code for my test class:

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

    And the MilliTimer class I used:

    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;
        }
    }
    
    0 讨论(0)
提交回复
热议问题