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"}).forEach(System.out::println);
or
Arrays.stream(new String[]{"hallo","hi"}).forEach(System.out::println);
Is the difference significant or are there any better solutions to solve this?
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.
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; } }