Java8 лямбды и исключения
интересно, может ли кто-нибудь объяснить мне следующую странность. Я использую Java 8 обновление 11.
учитывая, этот метод
private <F,T> T runFun(Function<Optional<F>, T> fun, Optional<F> opt) {
return fun.apply(opt) ;
}
если я сначала создаю объект функции и передаю его в метод выше, вещи компилируются.
private void doesCompile() {
Function<Optional<String>, String> fun = o -> o.orElseThrow(() -> new RuntimeException("nah"));
runFun(fun, Optional.of("foo"));
}
но, если я встрою функцию как лямбда, компилятор говорит
несообщаемого исключение Х; должен быть пойман или объявленные быть бросил
private void doesNotCompile () {
runFun(o -> o.orElseThrow(() -> new RuntimeException("nah")), Optional.of("foo"));
}
обновление: Оказывается, сообщение об ошибке было сокращено maven. При компиляции непосредственно с javac, ошибка:
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
см. Также здесь для выполняемого тестового кода.
3 ответа:
это похоже на ошибку JDK-8054569, что не влияет на затмение.
я смог сузить его, заменив функцию поставщиком и извлекая
orElseThrow
способ: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"))); }
а затем дальше, удалив поставщиков и лямбды в целом:
abstract <T> void f(T t); abstract <T, X extends Throwable> T g(X x) throws X; void bug() { f(g(new RuntimeException("foo"))); }
который на самом деле является более чистым примером, чем тот, что в отчете об ошибке. Это показывает ту же ошибку при компиляции как Java 8, но отлично работает с
-source 1.7
.Я предполагаю, что что-то о передаче универсального метода возвращаемого типа в параметр универсального метода приводит к ошибке вывода типа для исключения, поэтому он предполагает, что тип является Throwable и жалуется, что этот проверенный тип исключения не обрабатывается. Ошибка исчезнет, если вы объявите
bug() throws Throwable
или измените привязку наX extends RuntimeException
(так что это не отмечено).
Это то, что решило проблему для меня:
вместо того, чтобы писать
optional.map(this::mappingFunction).orElseThrow(() -> new BadRequestException("bla bla"));
я писал:
optional.map(this::mappingFunction).<BadRequestException>orElseThrow(() -> new BadRequestException("bla bla"));
добавление явного
<BadRequestException>
помогает с этими лямбда-крайними случаями (которые довольно раздражают...)обновление: это в случае, если вы не можете обновить до последней версии JDK, если вы можете, вы должны...