79

I wonder if someone could explain the following weirdness to me. I'm using Java 8 update 11.

Given this method

private <F,T> T runFun(Function<Optional<F>, T> fun, Optional<F> opt) {
 return fun.apply(opt) ;
}

If I first construct a function Object, and pass that in to the method above, things compile.

private void doesCompile() {
 Function<Optional<String>, String> fun = o -> o.orElseThrow(() -> new RuntimeException("nah"));
 runFun(fun, Optional.of("foo"));
}

But, if I inline the function as a lambda, the compiler says

unreported exception X; must be caught or declared to be thrown

private void doesNotCompile () {
 runFun(o -> o.orElseThrow(() -> new RuntimeException("nah")), Optional.of("foo"));
}

Update: Turns out the error message was abbreviated by maven. If compiled directly with javac, the error is:

error: unreported exception X; must be caught or declared to be thrown
 runFun(o -> o.orElseThrow(() -> new RuntimeException("nah")), Optional.of("foo"));
 ^
 where X,T are type-variables:
 X extends Throwable declared in method <X>orElseThrow(Supplier<? extends X>)
 T extends Object declared in class Optional

Also see here for runnable test code.

Free-Minded
5,4306 gold badges53 silver badges100 bronze badges
asked Aug 27, 2014 at 9:21
4
  • 6
    Sounds like yet another type inference bug. Be sure to include detailed information on the compiler you get this error from since Eclipse uses its own. Commented Aug 27, 2014 at 9:27
  • notice that the same thing happens if you use an anonymous class, so its not a lambda issue. Commented Aug 27, 2014 at 10:38
  • 7
    An aside: Eclipse compiles this just fine, and using o.<RuntimeException>orElseThrow(()... solves the issue, however, this should not be necessary. (I think a similar issue was reported in another stackoverflow question a while ago, but I did not find it right now...) Commented Aug 27, 2014 at 11:42
  • "mvn -e" can be helpful. Commented Sep 25, 2015 at 8:49

5 Answers 5

130

This is what solved the problem for me:

instead of writing

optional.map(this::mappingFunction).orElseThrow(() -> new BadRequestException("bla bla"));

I wrote:

optional.map(this::mappingFunction).<BadRequestException>orElseThrow(() -> new BadRequestException("bla bla"));

Adding the explicit <BadRequestException> helps with these lambda edge cases (which are quite annoying...)

UPDATE: This is in case you can't update to the latest JDK version, if you can you should...

answered Nov 29, 2016 at 11:56
Sign up to request clarification or add additional context in comments.

5 Comments

I am on the latest version of Java and still get an error. .<RuntimeException>getOrElseThrow(throwable helped me out. Thank you.
This helped thanks, couldn't upgrade as I don't own the machine
I am on 1.8.0_144, still had to use your solution. It helped
Oracle's 1.8.0_171 is also broken.
1.8.0_181 also needs the explicit cast.
48

This looks like a case of bug JDK-8054569, which doesn't affect Eclipse.

I was able to narrow it down by replacing Function with Supplier and extracting the orElseThrow method:

abstract <T> void f(Supplier<T> s);
abstract <T, X extends Throwable> T g(Supplier<? extends X> x) throws X;
void bug() {
 f(() -> g(() -> new RuntimeException("foo")));
}

and then further by removing the suppliers and lambdas altogether:

abstract <T> void f(T t);
abstract <T, X extends Throwable> T g(X x) throws X;
void bug() {
 f(g(new RuntimeException("foo")));
}

which is actually a cleaner example than the one in the bug report. This shows the same error if compiled as Java 8, but works fine with -source 1.7.

I guess something about passing a generic method return type to a generic method parameter causes the type inference for the exception to fail, so it assumes the type is Throwable and complains that this checked exception type isn't handled. The error disappears if you declare bug() throws Throwable or change the bound to X extends RuntimeException (so it's unchecked).

answered Aug 27, 2014 at 17:27

1 Comment

Updated from 1.8.0_45 to 1.8.0_92 and it resolved my problems. Thanks
2

If you are trying to compile someone else's project try to upgrade to 1.8.0_92

answered Apr 4, 2017 at 21:12

1 Comment

Are you sure? I still have this error in _101 and other people report this error in _171
1

Similar to @keisar I could solve my problem (see maven-compiler-plugin fails to compile a file that Eclipse has no problem with) by specifying the type parameter.

However, I found it much more convenient (since I use NotFoundException in a number of places) to simply make my exception class its own Supplier:

public class NotFoundException extends RuntimeException
 implements Supplier<NotFoundException> {
 // Rest of the code
 @Override
 public NotFoundException get() {
 return this;
 }
}

Then you can simply do:

// Distribution.rep().get(id) returns a java.util.Optional
Distribution distro = Distribution.rep().get(id).orElseThrow(
 new NotUniqueException("Exception message"));
answered Jan 11, 2019 at 10:07

Comments

1

If explicitly adding <RunTimeException> looks ugly then as a workaround you can replace with orElseGet()

.orElseGet(() -> throw new RunTimeException("foo"));
answered Jun 23, 2020 at 23:37

1 Comment

I don't think you can throw an exception in-line like that... the throw statement needs to be in a block.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.