[java] Java 8 : 스트림에서 예외 발생 메소드를 사용하려면 어떻게해야합니까?

클래스와 메소드가 있다고 가정하십시오.

class A {
  void foo() throws Exception() {
    ...
  }
}

이제 다음과 같은 A스트림 으로 전달되는 각 인스턴스에 대해 foo를 호출 하고 싶습니다.

void bar() throws Exception {
  Stream<A> as = ...
  as.forEach(a -> a.foo());
}

질문 : 예외를 올바르게 처리하려면 어떻게해야합니까? foo ()에서 발생할 수있는 가능한 예외를 처리하지 않기 때문에 코드가 컴퓨터에서 컴파일되지 않습니다. throws Exception의는 bar여기에 쓸모가있을 것으로 보인다. 왜 그런 겁니까?



답변

확인 된 예외를 발생 시키지 않는 다른 메소드로 메소드 호출을 랩핑해야합니다 . 하위 클래스 인 것을 던질 수 있습니다 RuntimeException.

일반적인 랩핑 관용구는 다음과 같습니다.

private void safeFoo(final A a) {
    try {
        a.foo();
    } catch (Exception ex) {
        throw new RuntimeException(ex);
    }
}

(슈퍼 타입 예외 Exception는 예제 로만 사용되며, 절대 스스로 잡으려고 시도하지 마십시오)

그러면 다음과 같이 호출 할 수 있습니다 as.forEach(this::safeFoo)..


답변

원하는 모든 것을 호출 foo하고 예외를 그대로 (포장하지 않고) 전파하는 것을 선호한다면 for대신 Java의 루프를 대신 사용할 수 있습니다 ( 트릭이 있는 Stream을 Iterable로 바꾼 후 ).

for (A a : (Iterable<A>) as::iterator) {
   a.foo();
}

이것은 적어도 JUnit 테스트에서 수행하는 작업으로, 확인 된 예외를 래핑하는 데 어려움을 겪고 싶지 않습니다 (실제로 래핑되지 않은 원래 예외를 던지는 테스트를 선호합니다)


답변

이 질문은 약간 오래되었지만 여기서 “올바른”답은 나중에 코드에서 숨겨진 문제를 일으킬 수있는 한 가지 방법이라고 생각하기 때문에. 논란 이 적더라도 확인 된 예외는 이유가 있습니다.

내 생각에 가장 우아한 방법은 Misha가 제시 한 것
입니다. “미래”에서 작업을 수행하여 Java 8 스트림에서 런타임 예외를 집계합니다 . 따라서 모든 작업 부분을 실행하고 작동하지 않는 예외를 단일 항목으로 수집 할 수 있습니다. 그렇지 않으면 목록에서 모두 수집하여 나중에 처리 할 수 ​​있습니다.

비슷한 접근 방식이 Benji Weber 에서 제공됩니다 . 그는 작업 부품이 아닌 작업 부품을 수집하기 위해 자체 유형을 만들 것을 제안합니다.

실제로 입력 값과 출력 값 사이의 간단한 매핑을 달성하려는 대상에 따라 예외가 발생할 수도 있습니다.

이러한 방법 중 어느 것도 마음에 들지 않으면 최소한 원래 예외에 따라 (원래 예외에 따라) 사용하는 것이 좋습니다.


답변

Google Guava Throwables 클래스를 사용하는 것이 좋습니다.

전파 ( Throwable Throwable)

RuntimeException 또는 Error의 인스턴스이거나 마지막 수단으로 Throwable을있는 그대로 전파하면 RuntimeException에 랩된 다음 전파됩니다. **

void bar() {
    Stream<A> as = ...
    as.forEach(a -> {
        try {
            a.foo()
        } catch(Exception e) {
            throw Throwables.propagate(e);
        }
    });
}

최신 정보:

더 이상 사용되지 않습니다.

void bar() {
    Stream<A> as = ...
    as.forEach(a -> {
        try {
            a.foo()
        } catch(Exception e) {
            Throwables.throwIfUnchecked(e);
            throw new RuntimeException(e);
        }
    });
}


답변

이 방법으로 예외를 랩핑하고 랩핑 해제 할 수 있습니다.

class A {
    void foo() throws Exception {
        throw new Exception();
    }
};

interface Task {
    void run() throws Exception;
}

static class TaskException extends RuntimeException {
    private static final long serialVersionUID = 1L;
    public TaskException(Exception e) {
        super(e);
    }
}

void bar() throws Exception {
      Stream<A> as = Stream.generate(()->new A());
      try {
        as.forEach(a -> wrapException(() -> a.foo())); // or a::foo instead of () -> a.foo()
    } catch (TaskException e) {
        throw (Exception)e.getCause();
    }
}

static void wrapException(Task task) {
    try {
        task.run();
    } catch (Exception e) {
        throw new TaskException(e);
    }
}


답변

다음 중 하나를 수행 할 수 있습니다.

  • 전파 된 예외 확인
  • 랩핑하고 확인되지 않은 예외를 전파하거나
  • 예외를 포착하고 전파를 중지하십시오.

여러 라이브러리를 통해 쉽게 할 수 있습니다. 아래 예제는 내 NoException 라이브러리를 사용하여 작성되었습니다 .

// Propagate checked exception
as.forEach(Exceptions.sneak().consumer(A::foo));

// Wrap and propagate unchecked exception
as.forEach(Exceptions.wrap().consumer(A::foo));
as.forEach(Exceptions.wrap(MyUncheckedException::new).consumer(A::foo));

// Catch the exception and stop propagation (using logging handler for example)
as.forEach(Exceptions.log().consumer(Exceptions.sneak().consumer(A::foo)));


답변

더 읽기 쉬운 방법 :

class A {
  void foo() throws MyException() {
    ...
  }
}

RuntimeException과거에 그것을 얻기 위해 그것을 숨기십시오forEach()

  void bar() throws MyException {
      Stream<A> as = ...
      try {
          as.forEach(a -> {
              try {
                  a.foo();
              } catch(MyException e) {
                  throw new RuntimeException(e);
              }
          });
      } catch(RuntimeException e) {
          throw (MyException) e.getCause();
      }
  }

이 시점에서 나는 스트림을 건너 뛰고 for 루프를 사용한다고 말하면 누군가를 붙들 지 않을 것입니다.

  • 을 사용하여 스트림을 만들지 않습니다 Collection.stream(). 즉 for 루프로 변환하지 않습니다.
  • 당신은 사용하려고합니다 parallelstream()