Reputation: 4380
In what cases should we use the older foreach
loop over the new collection.forEach()
in JDK 8 or is it best practice to convert every foreach
loop? Are there any important performance differences?
The only case I can think of is if you want to iterate over an array and don't want to convert your array to a list first.
Upvotes: 3
Views: 1592
Reputation: 132350
It's hard to think of best practices at this point since JDK 8 hasn't even shipped yet. However, there are some interesting observations based on early use of these APIs.
The forEach()
method is now on Iterable
, which is inherited by Collection
, so all collections can use forEach()
.
An array can be wrapped in a collection with Arrays.asList()
or in a stream with Arrays.stream()
. These are just wrappers; they don't copy all the elements into a new container.
Regarding performance, the default implementation of Iterable.forEach(action)
is simply the usual "enhanced for-loop" which creates an iterator and issues successive hasNext()
and next()
calls and calls to the action
method within a loop. There is a little bit of extra overhead for the extra method calls, compared to a bare enhanced-for loop, but it's probably very small.
I would make a choice on stylistic grounds, not performance.
It's probably not worth it to convert every enhanced-for loop to use forEach()
. Consider:
for (String s : coll) {
System.out.println("---");
System.out.println(s);
System.out.println("---");
}
versus
coll.forEach(s -> {
System.out.println("---");
System.out.println(s);
System.out.println("---");
});
If the lambda is a true one-liner it might be worth it, but in my opinion a multi-line statement lambda within forEach()
isn't any clearer than a nice for-loop.
However, if the body of the for-loop has logic in it, or if it needs to maintain some kind of running state, it might be worthwhile to recast the loop into a stream pipeline. Consider this snippet that finds the length of the longest string in a collection:
int longest = -1;
for (String s : strings) {
int len = s.length();
if (len > longest)
longest = len;
}
Rewritten using lambdas and the streams library, it would look like this:
OptionalInt longest =
strings.stream()
.mapToInt(s -> s.length())
.max();
This is new and unfamiliar, of course, but after working with this for a while, I find it to be concise and readable.
Upvotes: 3