Java Language `return` only returns from the lambda, not the outer method


Example

The return method only returns from the lambda, not the outer method.

Beware that this is different from Scala and Kotlin!

void threeTimes(IntConsumer r) {
  for (int i = 0; i < 3; i++) {
    r.accept(i);
  }
}

void demo() {
  threeTimes(i -> {
    System.out.println(i);
    return; // Return from lambda to threeTimes only!
  });
}

This can lead to unexpected behavior when attempting to write own language constructs, as in builtin constructs such as for loops return behaves differently:

void demo2() {
  for (int i = 0; i < 3; i++) {
    System.out.println(i);
    return; // Return from 'demo2' entirely
  }
}

In Scala and Kotlin, demo and demo2 would both only print 0. But this is not more consistent. The Java approach is consistent with refactoring and the use of classes - the return in the code at the top, and the code below behaves the same:

void demo3() {
  threeTimes(new MyIntConsumer());
}

class MyIntConsumer implements IntConsumer {
  public void accept(int i) {
    System.out.println(i);
    return;
  }
}

Therefore, the Java return is more consistent with class methods and refactoring, but less with the for and while builtins, these remain special.

Because of this, the following two are equivalent in Java:

IntStream.range(1, 4)
    .map(x -> x * x)
    .forEach(System.out::println);
IntStream.range(1, 4)
    .map(x -> { return x * x; })
    .forEach(System.out::println);

Furthermore, the use of try-with-resources is safe in Java:

class Resource implements AutoCloseable {
  public void close() { System.out.println("close()"); }
}

void executeAround(Consumer<Resource> f) {
  try (Resource r = new Resource()) {
    System.out.print("before ");
    f.accept(r);
    System.out.print("after ");
  }
}

void demo4() {
  executeAround(r -> {
    System.out.print("accept() ");
    return; // Does not return from demo4, but frees the resource.
  });
}

will print before accept() after close(). In the Scala and Kotlin semantics, the try-with-resources would not be closed, but it would print before accept() only.