سؤال

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.

هل كانت مفيدة؟

المحلول

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.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top