8

I am trying to track down why a specific behavior is happening with .orElseThrow in a Java Stream. This code block

private SomeContainer getSomeContainerFromList(SomeContainerList containerList, String containerId) {

   return containerList.stream()
           .filter(specificContainer -> specificContainer.getId().equals(containerId))
           .findAny()
           .orElseThrow(() -> {
               String message = "some special failure message";
               log.error(message);
               throw new CustomInternalException(message)});
}

results in this error: unreported exception X; must be caught or declared to be thrown

I don't want to report the exception because that would cause me to add that to every other method who interacts with this.

However, when I remove the curly braced lambda expression, leaving just the new exception to be thrown, like so:

private SomeContainer getSomeContainerFromList(SomeContainerList containerList, String containerId) {

   return containerList.stream()
           .filter(specificContainer -> specificContainer.getId().equals(containerId))
           .findAny()
           .orElseThrow(() -> new CustomInternalException("some special failure message"));
}

It compiles just fine and the exception no longer needs to be reported, although, I can't log the message or do any other logic in that .orElseThrow statement.

Why does this happen? I've seen a sort of similar question which explains that this could be a bug in the JDK but I want to make sure that is the case in my situation.

Naman
  • 27,789
  • 26
  • 218
  • 353
Zach
  • 83
  • 5
  • 2
    under `java-8` tag, read [two questions back](https://stackoverflow.com/questions/60118056/the-method-mapfunction-super-role-extends-r-in-the-type-streamrole-is-n) – Eugene Feb 07 '20 at 21:29

2 Answers2

7

Don’t throw the exception, return it:

.orElseThrow(() -> {
    String message = "some special failure message";
    log.error(message);
    // change “throw” to “return”:
    return new CustomInternalException(message)});

.orElseThrow() accepts a Supplier<Exception>, which should return, rather than throw, an exception.

Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • Oh thanks, my mistake I'll edit that. Its actually supposed to say throw. – Zach Feb 07 '20 at 21:41
  • 1
    @Zach that’s the problem. The lambda is supposed to be a *Producer* of Exception, of not *throw* one. – Bohemian Feb 07 '20 at 21:43
  • @Bohhemian, I see, so now with a returned exception I need to catch it when the method is called? – Zach Feb 07 '20 at 21:47
  • 1
    @Zach if nothing in the stream matches your filter, your lambda will be called and its returned exception thrown. If `CustomInternalException` is not a `RuntimeException` you must catch it or declare the calling method as `throws CustomInternalException` – Bohemian Feb 07 '20 at 21:50
  • Thanks for the help! – Zach Feb 07 '20 at 21:59
0
.orElseThrow(() -> {
    String message = "some special failure message";
    log.error(message);
    // change “throw” to “return”:
    new CustomInternalException(message)});

You dont want throw keyword inside orElseThrow`

Dasun
  • 602
  • 1
  • 11
  • 34