Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Checked exceptions thrown from within lambda expressions

Can you please explain why checked exceptions have to be caught from within lambda expressions? In other words, why does the following code not compile...

public void doSomething(ObjectInputStream istream) throws IOException {
  // The read method throws an IOException.
  IntStream.range(0, 10).forEach(i -> someList.add(read(istream)));
}

but this one will?

public void doSomething(ObjectInputStream istream) throws IOException {
  IntStream.range(0, 10).forEach(i -> {
    try {
      // The read method throws an IOException.
      someList.add(read(istream));
    }
    catch (IOException ioe) {
      // Callee has to handle checked exception, not caller.
    }
  });
}

It seems like the callee now has to handle any checked exceptions that are thrown and not the caller.

like image 291
BJ Dela Cruz Avatar asked Feb 24 '15 22:02

BJ Dela Cruz


2 Answers

The issue isn't the lambda expression, it's the interface it's implementing. Remember, a lambda expression is basically just shorthand for an anonymous class that implements a given interface.

In this case, forEach takes a java.util.function.Consumer<T>:

public interface Consumer<T> {
    void accept(T t);
    ...
}

Note that accept is not declared to throw anything. This means that no implementation of it can throw anything; not a named class, not an anonymous class, and not a lambda.

like image 164
yshavit Avatar answered Oct 13 '22 21:10

yshavit


It seems that your read method throws IOException.

The signature of IntStream.forEach is forEach(IntConsumer action), where IntConsumer has a void accept(int value) method. In that context your lambda expression i -> someList.add(read(istream)) is equivalent to:

public class IntConsumerImplementation implements IntConsumer {
   ObjectInputStream istream;
   public void accept(int i) {
      someList.add(read(istream));
   };
}

which doesn't compile because read throws a checked exception.

On the other hand, lambda expressions may throw checked exceptions if the functional interface defines them (which is not the case for consumers or other java.util functional interfaces).

Suppose the following made up example:

 @FunctionalInterface
 public interface NotAnIntConsumer {
    public void accept(int i) throws IOException;
 }

Now the following compiles:

forEach(NotAnIntConsumer naic) { ... }
doSomething(ObjectInputStream istream) throws IOException {
   IntStream.range(0, 10).forEach(i -> someList.add(read(istream)));
}
like image 44
Javier Avatar answered Oct 13 '22 21:10

Javier