development

Java8 Lambda 및 예외

big-blog 2020. 11. 14. 10:48
반응형

Java8 Lambda 및 예외


누군가가 나에게 다음과 같은 이상한 점을 설명해 줄 수 있는지 궁금합니다. Java 8 업데이트 11을 사용하고 있습니다.

이 방법이 주어지면

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

먼저 함수 Object를 생성하고 위의 메서드에 전달하면 모든 것이 컴파일됩니다.

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

}

그러나 함수를 람다로 인라인하면 컴파일러는 다음과 같이 말합니다.

보고되지 않은 예외 X; 잡히거나 던지도록 선언해야합니다

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

실행 가능한 테스트 코드는 여기참조 하십시오 .


이것은 Eclipse에 영향을 미치지 않는 버그 JDK-8054569 의 경우처럼 보입니다 .

Function을 Supplier로 바꾸고 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")));
}

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


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


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


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"));

참고URL : https://stackoverflow.com/questions/25523375/java8-lambdas-and-exceptions

반응형