serebit
serebit

Reputation: 380

Is the replacement of a foreach loop with Iterable.forEach purely cosmetic?

My question concerns the Java foreach loop, introduced in Java 5, and Iterable.forEach(), introduced in Java 8.

Let's say that a program exists with a List of String values, and the function of that program is to iterate over each individual string and use it as a method parameter.

Such a program could look like this as of Java 5:

for (String s : stringList) {
    doSomething(s);
}

However, with the introduction of Iterable.forEach() in Java 8, such a program could look like this:

stringList.forEach(this::doSomething);

My question is, is there any reason to use Iterable.forEach() instead of the foreach loop beyond the saving of a couple lines?

Upvotes: 1

Views: 584

Answers (4)

Jorn Vernee
Jorn Vernee

Reputation: 33865

Here are 3 differences to consider between the two:

  • Lambdas can not capture non-final variables.

  • A forEach does not allow for break/continue.

  • Checked exceptions must be caught within a passed lambda (since the type is Consumer<...>).

List<MyClass> list = ...;

MyClass mc = null;

for(MyClass e : list) {
    if(e.test("bla")) {
        mc = e;
        break;
    }
}               

list.forEach(e -> {
    if(e.test("bla")) {
        mc = e; // Does not compile
        break; // Also, does not compile
    }
});
void method() throws Exception {        
    ...
    for(MyClass e : list) {
        ...
        throw new Exception("Oops");
    }

    list.forEach(e -> {
        ...
        throw new Exception("Oops"); // Error: unhandled exception
    });
}

Upvotes: 5

Kedar Mhaswade
Kedar Mhaswade

Reputation: 4695

The fundamental benefit is that of internal iteration that you can utilize with forEach should the library decide to do it. When using the enhanced for loop (for x : xs), you insist on external iteration.

The idea is that you want some function to take every element of a list (or Iterable) and do something with it. The non-functional (traditional in Java) is to iterate over the list in your code and do it. This is called external iteration. This forces sequential execution.

With Java 8, you could create and pass lambda expression. So, you pass the behavior or function that accepts the element. Thus, you relinquish the control over iteration and let the list implementation (library code, so to speak) take care of iteration, possibly parallelizing the efforts.

Upvotes: 3

Thomas B Preusser
Thomas B Preusser

Reputation: 1189

Providing a forEach makes the action to be performed on the elements pluggable and very flexible. It can be an immediate lambda, a MethodHandle or even a MethodHanlde dynamically composed from a static portion of behavior and a runtime-defined part of it. Internally, the creation of an explicit Iterator object may be avoided. Otherwise, you can, of course, simulate the same behavior by an external loop. This might not look so nice though.

Upvotes: 5

Simon
Simon

Reputation: 6363

In the new Java8 API you can do things like

stringList.stream ().filter(...).map(...).forEach(...)

Which can many times be cleaner and less error prone than just doing the same transformationsize and filtering inside a for each for loop.

Upvotes: 2

Related Questions