programing

Java 8: Lambda-Streams, 메서드로 필터링(예외 포함)

javaba 2022. 8. 3. 22:45
반응형

Java 8: Lambda-Streams, 메서드로 필터링(예외 포함)

자바8의 람다 표현식을 시험하는 데 문제가 있습니다.평소에는 잘 먹히는데 지금은 던질 수 있는 방법이 있어요.IOException 좋습니다. 다음 코드를 참조하는 것이 가장 좋습니다.

class Bank{
    ....
    public Set<String> getActiveAccountNumbers() throws IOException {
        Stream<Account> s =  accounts.values().stream();
        s = s.filter(a -> a.isActive());
        Stream<String> ss = s.map(a -> a.getNumber());
        return ss.collect(Collectors.toSet());
    }
    ....
}

interface Account{
    ....
    boolean isActive() throws IOException;
    String getNumber() throws IOException;
    ....
}

문제는 isActive-와 getNumber-Methods의 가능한 예외를 파악해야 하기 때문에 컴파일이 되지 않는다는 것입니다.단, 다음과 같은 try-catch-block을 명시적으로 사용해도 예외를 포착하지 못하여 컴파일되지 않습니다.그래서 JDK에 버그가 있거나 이러한 예외를 포착하는 방법을 모릅니다.

class Bank{
    ....
    //Doesn't compile either
    public Set<String> getActiveAccountNumbers() throws IOException {
        try{
            Stream<Account> s =  accounts.values().stream();
            s = s.filter(a -> a.isActive());
            Stream<String> ss = s.map(a -> a.getNumber());
            return ss.collect(Collectors.toSet());
        }catch(IOException ex){
        }
    }
    ....
}

어떻게 하면 될까요?누가 나에게 올바른 해결책을 알려줄 수 있나요?

예외가 람다를 벗어나기 전에 잡아야 합니다.

s = s.filter(a -> {
    try {
        return a.isActive();
    } catch (IOException e) {
        throw new UncheckedIOException(e);
    }
});

람다는 사용자가 작성한 장소가 아니라 JDK 클래스 내에서 전혀 관련이 없는 장소에서 평가된다는 사실을 고려하십시오.체크 마크가 붙어 있는 예외는, 그 장소에서는 선언되지 않습니다.

체크된 예외를 체크되지 않은 예외로 변환하는 람다 래퍼를 사용하여 처리할 수 있습니다.

public static <T> T uncheckCall(Callable<T> callable) {
    try {
        return callable.call();
    } catch (RuntimeException e) {
        throw e;
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

예시는 다음과 같습니다.

return s.filter(a -> uncheckCall(a::isActive))
        .map(Account::getNumber)
        .collect(toSet());

프로젝트에서는 이 문제를 래핑하지 않고 처리합니다.대신 컴파일러의 예외 확인을 효과적으로 해제하는 방법을 사용하고 있습니다.말할 필요도 없이, 이것은 신중하게 취급할 필요가 있습니다.또, 프로젝트의 모든 사람은, 체크 마크가 붙어 있는 예외가 선언되어 있지 않은 경우에 표시되는 경우가 있습니다.배관 코드는 다음과 같습니다.

public static <T> T uncheckCall(Callable<T> callable) {
    try {
        return callable.call();
    } catch (Exception e) {
        return sneakyThrow(e);
    }
}

public static void uncheckRun(RunnableExc r) {
    try {
        r.run();
    } catch (Exception e) {
        sneakyThrow(e);
    }
}

public interface RunnableExc {
    void run() throws Exception;
}

@SuppressWarnings("unchecked")
private static <T extends Throwable> void sneakyThrow(Throwable t) throws T {
    throw (T) t;
}

그렇게 선언하지 않아도 얼굴에 튕겨질 수 있습니다.모든 실제 케이스가 아닌 대부분의 경우 예외를 재투입하여 일반적인 장애로 취급할 수 있습니다.이 모든 경우 명확성이나 정확성 면에서 손실되는 것은 없습니다.그 외의 경우는 주의해 주세요.즉석에서 예외에 대응하고 싶은 경우가 있습니다.디벨로퍼는 컴파일러에 의해 컴파일러에 의해 인식되지 않습니다.IOException만약 당신이 그것을 잡으려고 한다면 컴파일러는 실제로 불평할 것입니다. 왜냐하면 우리는 그러한 예외는 던져질 수 없다고 믿도록 속여왔기 때문입니다.

또한 람다로 정전기 통증을 전파할 수 있으므로 모든 내용을 읽을 수 있습니다.

s.filter(a -> propagate(a::isActive))

propagate서 받다java.util.concurrent.Callable는, 「」로 합니다.RuntimeException. Guava에서도 비슷한 변환방식인 Throughables#propagate(Troughable)가 있습니다.

이 방법은 람다 메서드 체인에 필수적인 것 같기 때문에 언젠가 인기 있는 lib에 추가되거나 이 전파 동작이 디폴트로 되어 있으면 좋겠습니다.

public class PropagateExceptionsSample {
    // a simplified version of Throwables#propagate
    public static RuntimeException runtime(Throwable e) {
        if (e instanceof RuntimeException) {
            return (RuntimeException)e;
        }

        return new RuntimeException(e);
    }

    // this is a new one, n/a in public libs
    // Callable just suits as a functional interface in JDK throwing Exception 
    public static <V> V propagate(Callable<V> callable){
        try {
            return callable.call();
        } catch (Exception e) {
            throw runtime(e);
        }
    }

    public static void main(String[] args) {
        class Account{
            String name;    
            Account(String name) { this.name = name;}

            public boolean isActive() throws IOException {
                return name.startsWith("a");
            }
        }


        List<Account> accounts = new ArrayList<>(Arrays.asList(new Account("andrey"), new Account("angela"), new Account("pamela")));

        Stream<Account> s = accounts.stream();

        s
          .filter(a -> propagate(a::isActive))
          .map(a -> a.name)
          .forEach(System.out::println);
    }
}

★★★★★★★★★★★★★★★★★.UtilException도우미 클래스에서는 Java 스트림에서 다음과 같이 체크된 예외를 사용할 수 있습니다.

Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
      .map(rethrowFunction(Class::forName))
      .collect(Collectors.toList());

: ★Class::forNameClassNotFoundException체크되어 있습니다.시냇물 자체도 던진다.ClassNotFoundException체크되지 않은 랩핑 예외가 아닙니다.

public final class UtilException {

@FunctionalInterface
public interface Consumer_WithExceptions<T, E extends Exception> {
    void accept(T t) throws E;
    }

@FunctionalInterface
public interface BiConsumer_WithExceptions<T, U, E extends Exception> {
    void accept(T t, U u) throws E;
    }

@FunctionalInterface
public interface Function_WithExceptions<T, R, E extends Exception> {
    R apply(T t) throws E;
    }

@FunctionalInterface
public interface Supplier_WithExceptions<T, E extends Exception> {
    T get() throws E;
    }

@FunctionalInterface
public interface Runnable_WithExceptions<E extends Exception> {
    void run() throws E;
    }

/** .forEach(rethrowConsumer(name -> System.out.println(Class.forName(name)))); or .forEach(rethrowConsumer(ClassNameUtil::println)); */
public static <T, E extends Exception> Consumer<T> rethrowConsumer(Consumer_WithExceptions<T, E> consumer) throws E {
    return t -> {
        try { consumer.accept(t); }
        catch (Exception exception) { throwAsUnchecked(exception); }
        };
    }

public static <T, U, E extends Exception> BiConsumer<T, U> rethrowBiConsumer(BiConsumer_WithExceptions<T, U, E> biConsumer) throws E {
    return (t, u) -> {
        try { biConsumer.accept(t, u); }
        catch (Exception exception) { throwAsUnchecked(exception); }
        };
    }

/** .map(rethrowFunction(name -> Class.forName(name))) or .map(rethrowFunction(Class::forName)) */
public static <T, R, E extends Exception> Function<T, R> rethrowFunction(Function_WithExceptions<T, R, E> function) throws E {
    return t -> {
        try { return function.apply(t); }
        catch (Exception exception) { throwAsUnchecked(exception); return null; }
        };
    }

/** rethrowSupplier(() -> new StringJoiner(new String(new byte[]{77, 97, 114, 107}, "UTF-8"))), */
public static <T, E extends Exception> Supplier<T> rethrowSupplier(Supplier_WithExceptions<T, E> function) throws E {
    return () -> {
        try { return function.get(); }
        catch (Exception exception) { throwAsUnchecked(exception); return null; }
        };
    }

/** uncheck(() -> Class.forName("xxx")); */
public static void uncheck(Runnable_WithExceptions t)
    {
    try { t.run(); }
    catch (Exception exception) { throwAsUnchecked(exception); }
    }

/** uncheck(() -> Class.forName("xxx")); */
public static <R, E extends Exception> R uncheck(Supplier_WithExceptions<R, E> supplier)
    {
    try { return supplier.get(); }
    catch (Exception exception) { throwAsUnchecked(exception); return null; }
    }

/** uncheck(Class::forName, "xxx"); */
public static <T, R, E extends Exception> R uncheck(Function_WithExceptions<T, R, E> function, T t) {
    try { return function.apply(t); }
    catch (Exception exception) { throwAsUnchecked(exception); return null; }
    }

@SuppressWarnings ("unchecked")
private static <E extends Throwable> void throwAsUnchecked(Exception exception) throws E { throw (E)exception; }

}

예으로 Import(Import) 후)UtilException

@Test
public void test_Consumer_with_checked_exceptions() throws IllegalAccessException {
    Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
          .forEach(rethrowConsumer(className -> System.out.println(Class.forName(className))));

    Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
          .forEach(rethrowConsumer(System.out::println));
    }

@Test
public void test_Function_with_checked_exceptions() throws ClassNotFoundException {
    List<Class> classes1
          = Stream.of("Object", "Integer", "String")
                  .map(rethrowFunction(className -> Class.forName("java.lang." + className)))
                  .collect(Collectors.toList());

    List<Class> classes2
          = Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
                  .map(rethrowFunction(Class::forName))
                  .collect(Collectors.toList());
    }

@Test
public void test_Supplier_with_checked_exceptions() throws ClassNotFoundException {
    Collector.of(
          rethrowSupplier(() -> new StringJoiner(new String(new byte[]{77, 97, 114, 107}, "UTF-8"))),
          StringJoiner::add, StringJoiner::merge, StringJoiner::toString);
    }

@Test    
public void test_uncheck_exception_thrown_by_method() {
    Class clazz1 = uncheck(() -> Class.forName("java.lang.String"));

    Class clazz2 = uncheck(Class::forName, "java.lang.String");
    }

@Test (expected = ClassNotFoundException.class)
public void test_if_correct_exception_is_still_thrown_by_method() {
    Class clazz3 = uncheck(Class::forName, "INVALID");
    }

그러나 다음과 같은 장점, 단점제한 사항을 이해하기 전에는 사용하지 마십시오.

• 호출 코드가 선택된 예외를 처리하는 경우 스트림을 포함하는 메서드의 throws 구에 추가해야 합니다.컴파일러는 더 이상 추가하도록 강요하지 않기 때문에 쉽게 잊어버릴 수 있습니다.

• 호출 코드가 이미 선택된 예외를 처리하고 있는 경우, 컴파일러는 스트림을 포함하는 메서드 선언에 구를 추가하도록 알려줍니다(그렇지 않은 경우: 예외는 대응하는 try 문의 본문에 삽입되지 않습니다).

·어쨌든 스트림 자체를 둘러싸서 스트림을 포함한 메서드 내부에서 체크된 예외를 검출할 수 없습니다(실행하면 컴파일러는 예외는 대응하는 try 문 본문에 삽입되지 않습니다).

• 문자 그대로 선언한 예외를 슬로우할 수 없는 메서드를 호출하는 경우에는 슬로우 절을 포함하지 마십시오.예를 들어 new String(byteArr, "UTF-8")은 UnsupportedEncodingException을 슬로우하지만 UTF-8은 Java 사양에 의해 항상 존재함을 보증합니다.여기서 슬로우 선언은 성가신 일이며 최소한의 보일러 플레이트로 이를 침묵시키는 어떤 해결책도 환영한다.

• 체크된 예외를 싫어하고, 처음부터 Java 언어에 추가되어서는 안 된다고 생각되는 경우는(저는 그렇게 생각하는 사람이 증가하고 있지만, 저는 그 중 하나가 아닙니다), 스트림을 포함한 메서드의 throws 절에 체크된 예외를 추가하지 마십시오.그러면 체크된 예외는 UN 체크되지 않은 예외와 동일하게 동작합니다.

• 스로우 선언을 추가할 수 있는 옵션이 없는 엄격한 인터페이스를 구현하고 있지만 예외를 설정하는 것이 전적으로 적절하다면, 예외를 던지는 특권을 얻기 위해서만 예외를 래핑하면 스택 트레이스(스플리어스 예외 포함)가 발생하고 실제로 무엇이 잘못되었는지에 대한 정보는 전혀 기여하지 않습니다.좋은 예로는 Runnable.run()을 들 수 있습니다.이 예에서는 체크된 예외가 발생하지 않습니다.이 경우 스트림을 포함하는 메서드의 throws 구에 체크박스를 켠 예외를 추가하지 않을 수 있습니다.

• 어떤 경우에도 스트림을 포함하는 메서드의 throws 절에 체크된 예외를 추가(또는 추가하지 않음)하지 않기로 결정한 경우, CHECKED 예외 슬로우의 다음 두 가지 결과에 유의하십시오.

1) 발신 코드는 이름으로 검출할 수 없습니다(사용자가 시도하면 컴파일러는 예외는 대응하는 try 스테이트먼트에 삽입되지 않습니다).이것은 버블이 되어 메인 프로그램 루프에서 "예외 캐치" 또는 "스로우 가능 캐치 캐치"에 의해 캐치될 수 있습니다.어쨌든 원하는 것이 될 수 있습니다.

2) 덜 놀랍다는 원칙에 위배된다: 더 이상 런타임을 포착하기에 충분하지 않다.가능한 모든 예외를 확실하게 포착할 수 있는 예외입니다.따라서 프레임워크 코드가 아니라 완전히 제어하는 비즈니스 코드로만 해야 한다고 생각합니다.

i : 저는 가 심각하지 생각합니다.UtilException이치노릇을 하다지만, 그건그그!

요.Stream되지 않은 후 에 터미널되지 않은 .

@FunctionalInterface
public interface ThrowingPredicate<T, X extends Throwable> {
    public boolean test(T t) throws X;
}

@FunctionalInterface
public interface ThrowingFunction<T, R, X extends Throwable> {
    public R apply(T t) throws X;
}

@FunctionalInterface
public interface ThrowingSupplier<R, X extends Throwable> {
    public R get() throws X;
}

public interface ThrowingStream<T, X extends Throwable> {
    public ThrowingStream<T, X> filter(
            ThrowingPredicate<? super T, ? extends X> predicate);

    public <R> ThrowingStream<T, R> map(
            ThrowingFunction<? super T, ? extends R, ? extends X> mapper);

    public <A, R> R collect(Collector<? super T, A, R> collector) throws X;

    // etc
}

class StreamAdapter<T, X extends Throwable> implements ThrowingStream<T, X> {
    private static class AdapterException extends RuntimeException {
        public AdapterException(Throwable cause) {
            super(cause);
        }
    }

    private final Stream<T> delegate;
    private final Class<X> x;

    StreamAdapter(Stream<T> delegate, Class<X> x) {
        this.delegate = delegate;
        this.x = x;
    }

    private <R> R maskException(ThrowingSupplier<R, X> method) {
        try {
            return method.get();
        } catch (Throwable t) {
            if (x.isInstance(t)) {
                throw new AdapterException(t);
            } else {
                throw t;
            }
        }
    }

    @Override
    public ThrowingStream<T, X> filter(ThrowingPredicate<T, X> predicate) {
        return new StreamAdapter<>(
                delegate.filter(t -> maskException(() -> predicate.test(t))), x);
    }

    @Override
    public <R> ThrowingStream<R, X> map(ThrowingFunction<T, R, X> mapper) {
        return new StreamAdapter<>(
                delegate.map(t -> maskException(() -> mapper.apply(t))), x);
    }

    private <R> R unmaskException(Supplier<R> method) throws X {
        try {
            return method.get();
        } catch (AdapterException e) {
            throw x.cast(e.getCause());
        }
    }

    @Override
    public <A, R> R collect(Collector<T, A, R> collector) throws X {
        return unmaskException(() -> delegate.collect(collector));
    }
}

이 은 '이것'과 할 수 .Stream:

Stream<Account> s = accounts.values().stream();
ThrowingStream<Account, IOException> ts = new StreamAdapter<>(s, IOException.class);
return ts.filter(Account::isActive).map(Account::getNumber).collect(toSet());

이 솔루션에는 꽤 많은 보일러 플레이트가 필요합니다.그래서 제가 이미 만든 라이브러리를 보시기 바랍니다.이 라이브러리는 제가 여기서 설명한 것과 정확히 일치합니다.Stream★★★★★★★★★★★★★★★★★★★★★」

#propagate() 메서드를 사용합니다.Sam Beran의 Java 8 Blog에서의 비구아바 구현 예시:

public class Throwables {
    public interface ExceptionWrapper<E> {
        E wrap(Exception e);
    }

    public static <T> T propagate(Callable<T> callable) throws RuntimeException {
        return propagate(callable, RuntimeException::new);
    }

    public static <T, E extends Throwable> T propagate(Callable<T> callable, ExceptionWrapper<E> wrapper) throws E {
        try {
            return callable.call();
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            throw wrapper.wrap(e);
        }
    }
}

이것은 질문에 직접 답하는 것은 아니지만(다른 많은 답변이 있습니다) 처음부터 문제를 회피하려고 합니다.

지금까지의 경험으로 볼 때 예외 처리 필요성은Stream(또는 다른 람다 표현식)은 종종 예외가 던져져서는 안 되는 방법에서 던져진다고 선언된 사실에서 비롯됩니다.이는 종종 비즈니스 로직과 내부 및 출력의 혼합에서 비롯됩니다.의 ★★★★★★★★★★★★★★★★★.Account입니다.interface 완완완 。

interface Account {
    boolean isActive() throws IOException;
    String getNumber() throws IOException;
}

투척하는 대신IOException 다음과 같은합니다.

interface AccountReader {
    Account readAccount(…) throws IOException;
}

interface Account {
    boolean isActive();
    String getNumber();
}

AccountReader.readAccount(…)데이터베이스나 파일 등에서 계정을 읽고 성공하지 못할 경우 예외를 발생시킬 수 있습니다. 명령어는 ""를 합니다.Account모든 값이 이미 포함되어 사용할 준비가 된 개체입니다.readAccount(…) 겟터들은 예외없이, 겟터들은 예외 없이.따라서 예외를 감싸거나 마스킹하거나 숨길 필요 없이 람다에서 자유롭게 사용할 수 있습니다.

물론 설명대로 할 수 있는 것은 아닙니다만, 많은 경우, 클리너 코드(IMHO)로 이어집니다.

  • 문제를 더 잘 분리하여 단일 책임 원칙을 준수합니다.
  • 코드.throws IOException시키는 것 .
  • 오류 처리:필드 값을 얻고 싶어서 비즈니스 로직 중간에 있는 것이 아니라 파일 또는 데이터베이스에서 오류를 읽을 때 오류를 처리합니다.
  • 하면 만들 수 요.Account 장점(예: 스레드 안전성)에서 이익을 얻고 불변한다.
  • '더러운 나 '때 ' 속임수'나 '방책'을 쓰지 않아도 .Account를 들어 (( a)로Stream)

@marcg 솔루션을 확장하면 Streams에서 체크된 예외를 검출할 수 있습니다.즉, 컴파일러는 스트림 외부에 있을 때와 마찬가지로 캐치/재투구를 요구합니다.

@FunctionalInterface
public interface Predicate_WithExceptions<T, E extends Exception> {
    boolean test(T t) throws E;
}

/**
 * .filter(rethrowPredicate(t -> t.isActive()))
 */
public static <T, E extends Exception> Predicate<T> rethrowPredicate(Predicate_WithExceptions<T, E> predicate) throws E {
    return t -> {
        try {
            return predicate.test(t);
        } catch (Exception exception) {
            return throwActualException(exception);
        }
    };
}

@SuppressWarnings("unchecked")
private static <T, E extends Exception> T throwActualException(Exception exception) throws E {
    throw (E) exception;
}

그런 다음 예제를 다음과 같이 작성합니다(검정을 추가하여 더 명확하게 표시).

@Test
public void testPredicate() throws MyTestException {
    List<String> nonEmptyStrings = Stream.of("ciao", "")
            .filter(rethrowPredicate(s -> notEmpty(s)))
            .collect(toList());
    assertEquals(1, nonEmptyStrings.size());
    assertEquals("ciao", nonEmptyStrings.get(0));
}

private class MyTestException extends Exception { }

private boolean notEmpty(String value) throws MyTestException {
    if(value==null) {
        throw new MyTestException();
    }
    return !value.isEmpty();
}

@Test
public void testPredicateRaisingException() throws MyTestException {
    try {
        Stream.of("ciao", null)
                .filter(rethrowPredicate(s -> notEmpty(s)))
                .collect(toList());
        fail();
    } catch (MyTestException e) {
        //OK
    }
}

아래 간단한 코드 Stream and Try in Abacus Util로 해결할 수 있습니다.

Stream.of(accounts).filter(a -> Try.call(a::isActive)).map(a -> Try.call(a::getNumber)).toSet();

★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★AbacusUtil.

IOException을 (런타임에)예외) 코드 처리 방법은 다음과 같습니다.

Stream<Account> s =  accounts.values().stream();

s = s.filter(a -> { try { return a.isActive(); } 
  catch (IOException e) { throw new RuntimeException(e); }});

Stream<String> ss = s.map(a -> { try { return a.getNumber() }
  catch (IOException e) { throw new RuntimeException(e); }});

return ss.collect(Collectors.toSet());

는...IOException로서 포착해야 할 것이다.RuntimeException다시 로 변환되었습니다.IOException메서드에 더 됩니다.-----------------------------------------------------------------------------------------------------------------------------------------------

「」를 사용하는가?Stream 할 수 메서드는 「」를 슬로우 합니다.-- 「 」를 슬로우 합니다.IOException이치노

Set<String> set = new HashSet<>();
for(Account a: accounts.values()){
  if(a.isActive()){
     set.add(a.getNumber());
  } 
}
return set;

이 문제를 염두에 두고 체크된 예외사항과 람다를 처리할 수 있는 작은 라이브러리를 개발했습니다.커스텀 어댑터를 사용하면 기존 기능 유형과 통합할 수 있습니다.

stream().map(unchecked(URI::new)) //with a static import

https://github.com/TouK/ThrowingFunction/

예시는 다음과 같이 기술할 수 있습니다.

import utils.stream.Unthrow;

class Bank{
   ....
   public Set<String> getActiveAccountNumbers() {
       return accounts.values().stream()
           .filter(a -> Unthrow.wrap(() -> a.isActive()))
           .map(a -> Unthrow.wrap(() -> a.getNumber()))
           .collect(Collectors.toSet());
   }
   ....
}

Unthrow 클래스는 https://github.com/SeregaLBN/StreamUnthrower 에서 수강할 수 있습니다.

또한 상위 수준에서 예외를 발생시키기 위해 다음과 같은 외부(스트림) 오류 표시기를 사용할 수도 있습니다.

List<String> errorMessages = new ArrayList<>(); // error indicator
//..
errorMessages.clear();

List<String> names = new ArrayList<>(Arrays.asList("andrey", "angela", "pamela"));

names.stream()
.map(name -> {
    if (name != "pamela") {
      errorMessages.add(name + " is wrong here!"); 
      return null; // triggering the indicator
    }
    return name;
} )
.filter(elem -> (elem != null)) // bypassing propagation of only current unwanted data
//.filter(elem -> (errorMessages.size() == 0)) // or blocking any propagation once unwanted data detected
.forEach(System.out::println);

if (errorMessages.size() > 0) { // handling the indicator
  throw  new RuntimeException(String,join(", ", errorMessages));
}

서드파티 라이브러리, AOL의 cyclops-react lib를 사용해도 괜찮으시다면 공개:저는 기고자로 Exception Softener 클래스를 수강하고 있습니다.

 s.filter(softenPredicate(a->a.isActive()));

Java의 기능 인터페이스는 체크 또는 체크되지 않은 예외를 선언하지 않습니다.메서드의 시그니처를 다음과 같이 변경해야 합니다.

boolean isActive() throws IOException; 
String getNumber() throwsIOException;

수신인:

boolean isActive();
String getNumber();

또는 try-catch block으로 처리:

public Set<String> getActiveAccountNumbers() {
  Stream<Account> s =  accounts.values().stream();
  s = s.filter(a -> 
    try{
      a.isActive();
    }catch(IOException e){
      throw new RuntimeException(e);
    }
  );
  Stream<String> ss = s.map(a -> 
    try{
      a.getNumber();
    }catch(IOException e){
      throw new RuntimeException(e);
    }
  );
  return ss.collect(Collectors.toSet());
}

또 다른 옵션은 커스텀 래퍼를 작성하거나 Thooting Function과 같은 라이브러리를 사용하는 것입니다.라이브러리에서는 pom.xml 의존관계만 추가하면 됩니다.

<dependency>
    <groupId>pl.touk</groupId>
    <artifactId>throwing-function</artifactId>
    <version>1.3</version>
</dependency>

또한 던지기 기능, 던지기 컨슈머, 던지기 프레디케이트, 던지기 실행 가능, 던지기 서플라이어 등의 특정 클래스를 사용합니다.

마지막 코드는 다음과 같습니다.

public Set<String> getActiveAccountNumbers() {
  return accounts.values().stream()
    .filter(ThrowingPredicate.unchecked(Account::isActive))
    .map(ThrowingFunction.unchecked(Account::getNumber))
    .collect(Collectors.toSet());
}

스트림 내에서 예외를 처리하고 추가 예외를 계속 처리하려면 Brian Vermeer가 DZone에서 어느 하나의 개념을 사용한 훌륭한 기사가 있습니다.그것은 이 상황을 다루는 훌륭한 방법을 보여준다.유일하게 누락된 것은 샘플 코드입니다.이것은 그 기사의 컨셉을 사용한 제 탐험의 샘플입니다.

@Test
public void whenValuePrinted_thenPrintValue() {

    List<Integer> intStream = Arrays.asList(0, 1, 2, 3, 4, 5, 6);
    intStream.stream().map(Either.liftWithValue(item -> doSomething(item)))
             .map(item -> item.isLeft() ? item.getLeft() : item.getRight())
             .flatMap(o -> {
                 System.out.println(o);
                 return o.isPresent() ? Stream.of(o.get()) : Stream.empty();
             })
             .forEach(System.out::println);
}

private Object doSomething(Integer item) throws Exception {

    if (item == 0) {
        throw new Exception("Zero ain't a number!");
    } else if (item == 4) {
        return Optional.empty();
    }

    return item;
}

언급URL : https://stackoverflow.com/questions/19757300/java-8-lambda-streams-filter-by-method-with-exception

반응형