Java 8:Lambda-Streams,按带有异常的方法过滤

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19757300/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 19:57:36  来源:igfitidea点击:

Java 8: Lambda-Streams, Filter by Method with Exception

javaexception-handlinglambdajava-8

提问by Martin Weber

I have a problem trying out the Lambda expressions of Java 8. Usually it works fine, but now I have methods that throw IOException's. It's best if you look at the following code:

我在尝试 Java 8 的 Lambda 表达式时遇到问题。通常它工作正常,但现在我有 throwIOException的方法。最好查看以下代码:

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

The problem is, it doesn't compile, because I have to catch the possible exceptions of the isActive- and the getNumber-Methods. But even if I explicitly use a try-catch-Block like below, it still doesn't compile because I don't catch the Exception. So either there is a bug in JDK, or I don't know how to catch these Exceptions.

问题是,它无法编译,因为我必须捕获 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){
        }
    }
    ....
}

How can I get it work? Can someone hint me to the right solution?

我怎样才能让它工作?有人可以提示我正确的解决方案吗?

采纳答案by Marko Topolnik

You must catch the exception beforeit escapes the lambda:

您必须它转义 lambda之前捕获异常:

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

Consider the fact that the lambda isn't evaluated at the place you write it, but at some completely unrelated place, within a JDK class. So that would be the point where that checked exception would be thrown, and at that place it isn't declared.

考虑这样一个事实,即 lambda 不是在您编写它的地方计算的,而是在 JDK 类中的某个完全不相关的地方计算的。所以那将是抛出该检查异常的地方,并且在那个地方它没有被声明。

You can deal with it by using a wrapper of your lambda that translates checked exceptions to unchecked ones:

您可以使用 lambda 的包装器来处理它,该包装器将已检查的异常转换为未检查的异常:

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

Your example would be written as

你的例子将被写成

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


In my projects I deal with this issue without wrapping; instead I use a method which effectively defuses compiler's checking of exceptions. Needless to say, this should be handled with care and everybody on the project must be aware that a checked exception may appear where it is not declared. This is the plumbing code:

在我的项目中,我没有包装就处理这个问题;相反,我使用了一种有效地消除了编译器对异常检查的方法。不用说,这应该小心处理,项目中的每个人都必须意识到检查异常可能出现在未声明的地方。这是管道代码:

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;
}

and you can expect to get an IOExceptionthrown in your face, even though collectdoes not declare it. In most, but not allreal-life cases you would want to just rethrow the exception, anyway, and handle it as a generic failure. In all those cases, nothing is lost in clarity or correctness. Just beware of those other cases, where you would actually want to react to the exception on the spot. The developer will not be made aware by the compiler that there is an IOExceptionto catch there and the compiler will in fact complain if you try to catch it because we have fooled it into believing that no such exception can be thrown.

IOException即使collect没有声明,您也可能会被扔到脸上。在大多数(但不是所有)现实生活中,无论如何,您只想重新抛出异常,并将其作为一般故障处理。在所有这些情况下,都不会丢失任何清晰度或正确性。请注意其他情况,在这些情况下,您实际上希望当场对异常做出反应。编译器不会让开发人员意识到那里有一个IOException要捕获的对象,如果您尝试捕获它,编译器实际上会抱怨,因为我们已经欺骗它相信不会抛出此类异常。

回答by Andrey Chaschev

You can also propagate your static pain with lambdas, so the whole thing looks readable:

您还可以使用 lambda 来传播您的静态痛苦,因此整个事情看起来可读:

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

propagatehere receives java.util.concurrent.Callableas a parameter and converts any exception caught during the call into RuntimeException. There is a similar conversion method Throwables#propagate(Throwable)in Guava.

propagateherejava.util.concurrent.Callable作为参数接收并将调用期间捕获的任何异常转换为RuntimeException. Guava 中有类似的转换方法Throwables#propagate(Throwable)

This method seems being essential for lambda method chaining, so I hope one day it will be added to one of the popular libs or this propagating behavior would be by default.

这个方法对于 lambda 方法链来说似乎是必不可少的,所以我希望有一天它会被添加到一个流行的库中,否则这种传播行为将是默认的。

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

回答by The Coordinator

To properly add IOException (to RuntimeException) handling code, your method will look like this:

要正确添加 IOException(到 RuntimeException)处理代码,您的方法将如下所示:

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

The problem now is that the IOExceptionwill have to be captured as a RuntimeExceptionand converted back to an IOException-- and that will add even more code to the above method.

现在的问题是必须IOException将the捕获为 aRuntimeException并将其转换回 an IOException-- 这将为上述方法添加更多代码。

Why use Streamwhen it can be done just like this -- and the method throws IOExceptionso no extra code is needed for that too:

为什么Stream在可以像这样完成时使用- 并且该方法抛出IOException因此也不需要额外的代码:

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

回答by Jeffrey

You can potentially roll your own Streamvariant by wrapping your lambda to throw an unchecked exception and then later unwrapping that unchecked exception on terminal operations:

你可以Stream通过包装你的 lambda 来抛出一个未经检查的异常,然后在终端操作中解开那个未经检查的异常,从而有可能推出你自己的变体:

@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));
    }
}

Then you could use this the same exact way as a Stream:

然后你可以使用与 a 完全相同的方式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());

This solution would require quite a bit of boilerplate, so I suggest you take a look at the library I already madewhich does exactly what I have described here for the entire Streamclass (and more!).

这个解决方案需要相当多的样板文件,所以我建议你看看我已经制作,它完全符合我在此处为整个Stream类(以及更多!)描述的内容。

回答by n0mer

Use #propagate() method. Sample non-Guava implementation from Java 8 Blog by Sam Beran:

使用 #propagate() 方法。来自Sam Beran 的 Java 8 博客的示例非 Guava 实现:

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

回答by MarcG

This UtilExceptionhelper class lets you use any checked exceptions in Java streams, like this:

这个UtilException帮助器类允许您在 Java 流中使用任何已检查的异常,如下所示:

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

Note Class::forNamethrows ClassNotFoundException, which is checked. The stream itself also throws ClassNotFoundException, and NOT some wrapping unchecked exception.

注意Class::forName抛出ClassNotFoundException,这是检查。流本身也会抛出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; }

}

Many other examples on how to use it (after statically importing UtilException):

关于如何使用它的许多其他示例(静态导入后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");
    }

But don't use it before understanding the following advantages, disadvantages, and limitations:

但在了解以下优点、缺点和限制之前,请勿使用它

? If the calling-code is to handle the checked exception you MUST add it to the throws clause of the method that contains the stream. The compiler will not force you to add it anymore, so it's easier to forget it.

? 如果调用代码要处理已检查的异常,则必须将其添加到包含流的方法的 throws 子句中。编译器不会再强迫您添加它,因此更容易忘记它。

? If the calling-code already handles the checked exception, the compiler WILL remind you to add the throws clause to the method declaration that contains the stream (if you don't it will say: Exception is never thrown in body of corresponding try statement).

? 如果调用代码已经处理了已检查的异常,编译器会提醒您在包含流的方法声明中添加 throws 子句(如果不这样做,它会说:在相应的 try 语句的主体中永远不会抛出异常) .

? In any case, you won't be able to surround the stream itself to catch the checked exception INSIDE the method that contains the stream (if you try, the compiler will say: Exception is never thrown in body of corresponding try statement).

? 在任何情况下,您都无法包围流本身以捕获包含流的方法内部的已检查异常(如果您尝试,编译器会说:在相应的 try 语句的主体中永远不会抛出异常)。

? If you are calling a method which literally can never throw the exception that it declares, then you should not include the throws clause. For example: new String(byteArr, "UTF-8") throws UnsupportedEncodingException, but UTF-8 is guaranteed by the Java spec to always be present. Here, the throws declaration is a nuisance and any solution to silence it with minimal boilerplate is welcome.

? 如果您调用的方法实际上永远不会抛出它声明的异常,那么您不应该包含 throws 子句。例如: new String(byteArr, "UTF-8") 抛出 UnsupportedEncodingException,但 Java 规范保证 UTF-8 始终存在。在这里,throws 声明是一个令人讨厌的东西,欢迎任何用最少的样板来使其静音的解决方案。

? If you hate checked exceptions and feel they should never be added to the Java language to begin with (a growing number of people think this way, and I am NOT one of them), then just don't add the checked exception to the throws clause of the method that contains the stream. The checked exception will, then, behave just like an UNchecked exception.

? 如果您讨厌受检异常并且认为它们不应该从一开始就被添加到 Java 语言中(越来越多的人这样认为,而我不是其中之一),那么就不要将受检异常添加到 throws包含流的方法的子句。然后,受检异常的行为就像未受检异常一样。

? If you are implementing a strict interface where you don't have the option for adding a throws declaration, and yet throwing an exception is entirely appropriate, then wrapping an exception just to gain the privilege of throwing it results in a stacktrace with spurious exceptions which contribute no information about what actually went wrong. A good example is Runnable.run(), which does not throw any checked exceptions. In this case, you may decide not to add the checked exception to the throws clause of the method that contains the stream.

? 如果你正在实现一个严格的接口,你没有添加 throws 声明的选项,但抛出异常是完全合适的,那么包装异常只是为了获得抛出它的特权会导致堆栈跟踪与虚假异常不提供有关实际出错的信息。一个很好的例子是 Runnable.run(),它不会抛出任何已检查的异常。在这种情况下,您可能决定不向包含流的方法的 throws 子句添加已检查的异常。

? In any case, if you decide NOT to add (or forget to add) the checked exception to the throws clause of the method that contains the stream, be aware of these 2 consequences of throwing CHECKED exceptions:

? 在任何情况下,如果您决定不向包含流的方法的 throws 子句添加(或忘记添加)已检查异常,请注意抛出 CHECKED 异常的以下 2 个后果:

1) The calling-code won't be able to catch it by name (if you try, the compiler will say: Exception is never thrown in body of corresponding try statement). It will bubble and probably be catched in the main program loop by some "catch Exception" or "catch Throwable", which may be what you want anyway.

1) 调用代码将无法按名称捕获它(如果您尝试,编译器会说:在相应的 try 语句体中永远不会抛出异常)。它会冒泡,并可能在主程序循环中被某些“catch Exception”或“catch Throwable”捕获,无论如何这可能是您想要的。

2) It violates the principle of least surprise: it will no longer be enough to catch RuntimeException to be able to guarantee catching all possible exceptions. For this reason, I believe this should not be done in framework code, but only in business code that you completely control.

2)它违反了最小惊奇原则:仅仅捕获 RuntimeException 已经不足以保证捕获所有可能的异常。为此,我认为这不应该在框架代码中完成,而只能在您完全控制的业务代码中完成。

In conclusion: I believe the limitations here are not serious, and the UtilExceptionclass may be used without fear. However, it's up to you!

总结:相信这里的限制并不严重,UtilException可以放心使用类。然而,这取决于你!

回答by PaoloC

Extending @marcg solution, you can normally throw and catch a checkedexception in Streams; that is, compiler will ask you to catch/re-throwas is you were outside streams!!

扩展@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;
}

Then, your example would be written as follows (adding tests to show it more clearly):

然后,您的示例将编写如下(添加测试以更清楚地显示它):

@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
    }
}

回答by Grzegorz Piwowarek

Keeping this issue in mind I developed a small library for dealing with checked exceptions and lambdas. Custom adapters allow you to integrate with existing functional types:

牢记这个问题,我开发了一个用于处理检查异常和 lambda 的小型库。自定义适配器允许您与现有功能类型集成:

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

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

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

回答by John McClean

If you don't mind using 3rd party libraries, AOL's cyclops-reactlib, disclosure::I am a contributor, has a ExceptionSoftenerclass that can help here.

如果您不介意使用 3rd 方库,AOL 的cyclops-react库,披露::我是贡献者,有一个ExceptionSoftener类可以在这里提供帮助。

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

回答by SeregaLBN

Your example can be written as:

你的例子可以写成:

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());
   }
   ....
}

The Unthrowclass can be taken here https://github.com/SeregaLBN/StreamUnthrower

Unthrow类可以在这里拍摄https://github.com/SeregaLBN/StreamUnthrower