当前位置: 首页 > 知识库问答 >
问题:

为什么我不能使用过滤器作为流中的最后一步

巫马泓
2023-03-14

我一直被告知,不通过collect和findFirst等方法终止流是不好的做法,但没有真正的反馈,为什么在博客中没有太多关于它的内容。

看看下面的示例,我没有使用大规模的嵌套 if 检查,而是使用 Optional 来取回 List 值。如您所见,我的最后一步是在该流中过滤。这对我来说是预期的,这是为了取回一个列表。为什么这是错误的,我应该如何写它?

import lombok.Getter;
import lombok.Setter;
import java.util.*;

public class Main {
    public static void main(String[] args) {

        RequestBean requestBean = new RequestBean();
        // if I uncomment this I will get the list values printed as expected
//        FruitBean fruitBean = new FruitBean();
//        AnotherBean anotherBean = new AnotherBean();
//        InnerBean innerBean = new InnerBean();
//        requestBean.setFruitBeans(Collections.singletonList(fruitBean));
//        fruitBean.setAnotherBeans(Collections.singletonList(anotherBean));
//        anotherBean.setInnerBeans(Collections.singletonList(innerBean));
//        List<String> beans = Arrays.asList("apple", "orange");
//        innerBean.setBeans(beans);

        List<String> result = getBeanViaOptional(requestBean);

        if(result != null){
            for(String s : result){
                System.out.println(s);
            }
        }else {
            System.out.println("nothing in list");
        }

    }

    private static List<String> getBeanViaOptional(RequestBean bean){
        Optional<List<String>> output = Optional.ofNullable(bean)
                .map(RequestBean::getFruitBeans)
                .map(n -> n.get(0))
                .map(FruitBean::getAnotherBeans)
                .map(n -> n.get(0))
                .map(AnotherBean::getInnerBeans)
                .map(n -> n.get(0))
                .map(InnerBean::getBeans)
                // why is this bad practice to end with a filter. how should I write this then?
                .filter(n -> n.contains("apple"));

        if(!output.isPresent()){
            throw new CustomException();
        }

        return output.get();
    }

    // not using this. just to show that optional was preferable compared to this.
    private static List<String> getBeanViaIfChecks(RequestBean bean){
        if(bean != null){
            if(bean.getFruitBeans() != null){
                if(bean.getFruitBeans().get(0) != null){
                    if(bean.getFruitBeans().get(0).getAnotherBeans() != null){
                        if(bean.getFruitBeans().get(0).getAnotherBeans().get(0) != null){
                            if(bean.getFruitBeans().get(0).getAnotherBeans().get(0).getInnerBeans() != null){
                                if(bean.getFruitBeans().get(0).getAnotherBeans().get(0).getInnerBeans().get(0) != null){
                                    return bean.getFruitBeans().get(0).getAnotherBeans().get(0).getInnerBeans().get(0).getBeans();
                                }
                            }
                        }
                    }
                }
            }
        }
        return null;
    }
}

@Getter
@Setter
class RequestBean{
    List<FruitBean> fruitBeans;
}

@Getter
@Setter
class FruitBean{
    List<AnotherBean> anotherBeans;
}

@Getter
@Setter
class AnotherBean{
    List<InnerBean> innerBeans;
}

@Getter
@Setter
class InnerBean{
    List<String> beans;
}

class CustomException extends RuntimeException{
    // do some custom exception stuff
}

共有2个答案

吕鸿文
2023-03-14

对于流,当没有终端操作时,通常不会执行任何中间操作。您的示例使用“可选”。其操作映射筛选器与流中的某些中间操作具有相同的名称,但它们是不同的。您的示例在您的问题所问的行中是可以的(不是不好的做法)。

另一件事是(正如Aomine已经指出的). orElseThrow是获取可选中的值并在没有异常时抛出异常的更短方法。更重要的是,使用. orElseThrow(或. orElse如果有默认值)更安全。Optional.get()应尽可能避免。如果没有值,您将获得NoSuchElementException。这几乎和不使用可选时获取NullPointerException一样糟糕。以适当的方式使用可选可以保护您免受NullPointerException的影响。

夔修伟
2023-03-14

我一直被告知不通过收集和findFirst等方法终止Stream是不好的做法,但没有真正的反馈,说明为什么在博客中没有太多关于它的说法。

这实际上取决于上下文,如果你说“我是否可以用中间操作(例如过滤器)结束一个流,而不是调用终端操作(消耗流的操作)”,那么是的,这是不好的做法,有点毫无意义,因为你刚刚定义了一些标准,但从未要求“结果”。

流是懒惰的,因为它们不做任何事情,除非被终端操作告知,例如< code>collect、< code>findFirst等。

如果你说“从方法返回流是不是不好的做法”,那么可能值得一读这个答案,关于是否应该返回流或集合。

此外,请注意,您的getBeanVia可选逻辑正在可选上运行

如果s在易读性、维护等方面明显更好,那么您使用可选而不是命令式的方法。所以我建议您继续使用这种方法,尽管您可以通过使用orElseThrow对其进行一点改进,即:

return Optional.ofNullable(bean)
               .map(RequestBean::getFruitBeans)
               .map(n -> n.get(0))
               .map(FruitBean::getAnotherBeans)
               .map(n -> n.get(0))
               .map(AnotherBean::getInnerBeans)
               .map(n -> n.get(0))
               .map(InnerBean::getBeans)
               .filter(n -> n.contains("apple"))
               .orElseThrow(CustomException::new);

 类似资料:
  • 我试图在一个变量中保存得分为80分或80分以上的学生的姓名,但我无法使用filter进行保存,它返回整个对象,尽管我指定只打印这些对象的键值,即这些学生的姓名。 我的代码: 我怎样才能得到得分在80分以上的学生的名字?

  • 我了解在lambda中捕获此(修改对象属性)的正确方法如下: 但我对我所看到的以下特点感到好奇: 我感到困惑(并希望得到回答)的奇怪之处在于,为什么以下方法有效: 以及为什么我无法通过引用明确捕获此内容:

  • 我有一个代表文件夹的对象集合。我想让用户创建文件夹,因为他们喜欢与应用程序将创建一个“根”文件夹(对象)的约束,我想控制这个文件夹的_id属性。根据mongoDB文档,我应该能够设置_id字段,但是当我尝试时,我得到一个错误: mongo文档说_id可以是数组以外的任何BSON数据类型,因此我不理解为什么“0”无效。为什么我不能使用“0”作为\u id? 为了清楚起见,我希望mongoDB为根文件

  • 大家好,我想问一下为什么我在Javascript上的过滤器只显示第一行,不能取消过滤?我是javascript的新手,我已经给了这个类一个数字来检查,但似乎不起作用,这是我的代码 null null

  • 问题内容: 我只想知道,我们通常会在最后关闭流,但是为什么不通过以下方式关闭PrintStream 呢? 问题答案: 如果将其关闭,则将无法再写入控制台,因此,当进程终止时,让我们将此任务留给VM。您应该只关闭自己拥有或手动创建的流。不在您的控制范围之内,因此请留给创作者照顾。

  • 我可以使用SQLDeveloper连接到远程数据库。 我试图从命令行使用sqlcl连接到同一个数据库,但我收到一个错误。 下面是我正在运行的命令: 我也尝试过: 以下是我收到的错误: 同样在SQLDeveloper中,我只是在“自定义jdbc url”下输入以下内容,它连接没有任何问题,所以我希望我可以使用相同的URL通过命令行连接,但到目前为止,它不起作用: