[java] 예외를 발생시키는 Java 8 Lambda 함수?

String매개 변수가 있고를 반환하는 메서드에 대한 참조를 만드는 방법을 알고 있습니다 int.

Function<String, Integer>

그러나 함수가 예외를 던지면 작동하지 않습니다.

Integer myMethod(String s) throws IOException

이 참조를 어떻게 정의합니까?



답변

다음 중 하나를 수행해야합니다.

  • 코드 인 경우 검사 된 예외를 선언하는 고유 한 기능 인터페이스를 정의하십시오.

    @FunctionalInterface
    public interface CheckedFunction<T, R> {
       R apply(T t) throws IOException;
    }

    그것을 사용하십시오 :

    void foo (CheckedFunction f) { ... }
  • 그렇지 않으면 Integer myMethod(String s)확인 된 예외를 선언하지 않는 메소드를 래핑 하십시오.

    public Integer myWrappedMethod(String s) {
        try {
            return myMethod(s);
        }
        catch(IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    그리고:

    Function<String, Integer> f = (String t) -> myWrappedMethod(t);

    또는:

    Function<String, Integer> f =
        (String t) -> {
            try {
               return myMethod(t);
            }
            catch(IOException e) {
                throw new UncheckedIOException(e);
            }
        };

답변

당신은 실제로 확장 할 수 있습니다 Consumer(그리고 Function자바 8의 사용 – 핸들 예외가있는 새로운 인터페이스 등)을 기본 방법을 !

이 인터페이스를 고려하십시오 (extends Consumer).

@FunctionalInterface
public interface ThrowingConsumer<T> extends Consumer<T> {

    @Override
    default void accept(final T elem) {
        try {
            acceptThrows(elem);
        } catch (final Exception e) {
            // Implement your own exception handling logic here..
            // For example:
            System.out.println("handling an exception...");
            // Or ...
            throw new RuntimeException(e);
        }
    }

    void acceptThrows(T elem) throws Exception;

}

예를 들어 목록이있는 경우 :

final List<String> list = Arrays.asList("A", "B", "C");

forEach예외를 발생시키는 일부 코드로 (예 : with )을 사용하려면 일반적으로 try / catch 블록을 설정했을 것입니다.

final Consumer<String> consumer = aps -> {
    try {
        // maybe some other code here...
        throw new Exception("asdas");
    } catch (final Exception ex) {
        System.out.println("handling an exception...");
    }
};
list.forEach(consumer);

그러나이 새로운 인터페이스를 사용하면 람다 식으로 인스턴스화 할 수 있으며 컴파일러는 불평하지 않습니다.

final ThrowingConsumer<String> throwingConsumer = aps -> {
    // maybe some other code here...
    throw new Exception("asdas");
};
list.forEach(throwingConsumer);

또는 더 간결하게 캐스팅하십시오! :

list.forEach((ThrowingConsumer<String>) aps -> {
    // maybe some other code here...
    throw new Exception("asda");
});

업데이트 : 외모의 아주 좋은 유틸리티 라이브러리 부분이처럼 두리안 라는 오류 많이 더 유연성이 문제를 해결하는 데 사용할 수 있습니다. 예를 들어, 위의 구현에서 오류 처리 정책 ( System.out...또는 throw RuntimeException)을 명시 적으로 정의 했지만 Durian의 오류를 사용하면 대규모 유틸리티 메소드를 통해 정책을 즉시 적용 할 수 있습니다. 공유해 주셔서 감사 합니다 , @NedTwigg !.

샘플 사용법 :

list.forEach(Errors.rethrow().wrap(c -> somethingThatThrows(c)));


답변

두리안의 Errors수업 은 위의 다양한 제안의 많은 장점을 결합한 것 같습니다 .

프로젝트에 Durian을 포함 시키려면 다음 중 하나를 수행하십시오.


답변

이것은 Java 8에만 국한된 것이 아닙니다. 다음과 동등한 것을 컴파일하려고합니다.

interface I {
    void m();
}
class C implements I {
    public void m() throws Exception {} //can't compile
}


답변

면책 조항 : 아직 Java 8을 사용하지 않았으며 그것에 대해 읽었습니다.

Function<String, Integer>던지지 IOException않으므로 코드를 넣을 수 없습니다 throws IOException. 를 기대하는 메소드를 호출하는 경우 Function<String, Integer>해당 메소드에 전달하는 람다는 IOException마침표를 던질 수 없습니다 . 다음과 같이 람다를 작성할 수 있습니다 (확실하지 않은 람다 구문이라고 생각합니다).

(String s) -> {
    try {
        return myMethod(s);
    } catch (IOException ex) {
        throw new RuntimeException(ex);
        // (Or do something else with it...)
    }
}

또는 람다를 전달하는 메소드가 직접 작성한 메소드 인 경우 새 기능 인터페이스를 정의하고 대신 매개 변수 유형으로 사용할 수 있습니다 Function<String, Integer>.

public interface FunctionThatThrowsIOException<I, O> {
    O apply(I input) throws IOException;
}


답변

타사 라이브러리를 사용하지 않아도되는 경우 ( Vavr ) 다음을 작성할 수 있습니다.

CheckedFunction1<String, Integer> f = this::myMethod;

또한 오류를 처리하는 소위 Try 모나드가 있습니다.

Try(() -> f.apply("test")) // results in a Success(Integer) or Failure(Throwable)
        .map(i -> ...) // only executed on Success
        ...

더 읽어주세요 여기를 하십시오 .

면책 조항 : 저는 Vavr의 제작자입니다.


답변

던지지 않은 래퍼를 사용할 수 있습니다

Function<String, Integer> func1 = s -> Unthrow.wrap(() -> myMethod(s));

또는

Function<String, Integer> func2 = s1 -> Unthrow.wrap((s2) -> myMethod(s2), s1);