8

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...

Vadzim
26.4k14 gold badges153 silver badges160 bronze badges
asked Jul 26, 2015 at 14:07
0

3 Answers 3

12

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.

answered Jul 26, 2015 at 14:35
Sign up to request clarification or add additional context in comments.

1 Comment

Oh now I like that. That is indeed very sneaky.
6

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;
}
answered Jul 29, 2015 at 16:32

1 Comment

thanks, now this is really nice interface :) will definitely check out your source code
3

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;
answered Jul 26, 2015 at 14:11

4 Comments

How does that let send throw the exception?
@MarkoTopolnik: I understand that. But a lot more work is required to then make send throw the IOException. If I'm not mistaken, you basically have to catch the ThrownByLambdaException, and then have a series of instanceof to figure out what the actual exception was so you can rethrow it. Maybe not that bad for one or two exceptions, but still pretty verbose.
@T.J.Crowder To stay fair to our colleague fge (and as you discovered in our chat), throwing-lambdas does support the sneaky throwing idiom.
@MarkoTopolnik: Although as far as I can tell, the above doesn't actually use it, nor was it explained (e.g., that if it does use a sneaky throw, the throws decl. on send is essential and the compiler won't force you to add it).

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.