Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Throwing exception from lambda [duplicate]

Given this java 8 code

public Server send(String message) {
    sessions.parallelStream()
        .map(Session::getBasicRemote)
        .forEach(basic -> {
          try {
            basic.sendText(message);
          } catch (IOException e) {
            e.printStackTrace();
          }
        });

    return this;
}

how do we properly make this IOException be delegated up the stack of the method call? (in nutshell how to make this method throw this IOException ?)

Lambdas in java does not look very friendly to error handling...

like image 862
vach Avatar asked Jul 26 '15 14:07

vach


3 Answers

My approach would be to sneakily throw it from the lambda, but take care to have the send method declare it in its throws clause. Using the Exceptional class I posted here:

public Server send(String message) throws IOException {
  sessions.parallelStream()
          .map(Session::getBasicRemote)
          .forEach(basic -> Exceptional.from(() -> basic.sendText(message)).get());
  return this;
}

This way you're effectively making the compiler "look away" for just a bit, disabling its exception checking at one spot in your code, but by declaring the exception on your send method, you restore the regular behavior for all its callers.

like image 158
Marko Topolnik Avatar answered Nov 12 '22 20:11

Marko Topolnik


I wrote an extension to the Stream API which allows for checked exceptions to be thrown.

public Server send(String message) throws IOException {
    ThrowingStream.of(sessions, IOException.class)
        .parallelStream()
        .map(Session::getBasicRemote)
        .forEach(basic -> basic.sendText(message));

    return this;
}
like image 34
Jeffrey Avatar answered Nov 12 '22 21:11

Jeffrey


The problem is indeed that all @FunctionalInterfaces used in lambdas do not allow exceptions to be thrown, save for unchecked exceptions.

One solution is using a package of mine; with it, your code can read:

sessions.parallelStream()
    .map(Session::getBasicRemote)
    .forEach(Throwing.consumer(basic -> basic.sendText(message)));
return this;
like image 2
fge Avatar answered Nov 12 '22 19:11

fge