Java 8函数式编程模式:不要使用巨长的Stream流

栏目: Java · 发布时间: 5年前

内容简介:假设你已经使用了lambdas流,巨长的Stream的代码如下:以上实现功能是:计算上一年订购产品的次数。现在,只接受频繁订购的产品(> = 10)并返回它们,前提是如果它们没有被逻辑删除或显式隐藏在数据库中。你写完这段代码很快乐地回家了...

假设你已经使用了lambdas流,巨长的Stream的代码如下:

<b>public</b> List<Product> getFrequentOrderedProducts(List<Order> orders) {
        <b>return</b> orders.stream()
                        .filter(o -> o.getCreationDate().isAfter(LocalDate.now().minusYears(1)))
                        .flatMap(o -> o.getOrderLines().stream())
                        .collect(groupingBy(OrderLine::getProduct, summingInt(OrderLine::getItemCount)))
                        .entrySet()
                        .stream()
                        .filter(e -> e.getValue() >= 10)
                        .map(Entry::getKey)
                        .filter(p -> !p.isDeleted())
                        .filter(p -> !productRepo.getHiddenProductIds().contains(p.getId()))
                        .collect(toList());

以上实现功能是:计算上一年订购产品的次数。现在,只接受频繁订购的产品(> = 10)并返回它们,前提是如果它们没有被逻辑删除或显式隐藏在数据库中。

你写完这段代码很快乐地回家了...

但我们会找到你的!管理层无法解雇你,谁可以读懂这堆代码?!谁愿意和你合作?

这段代码最糟糕的是每行返回不同的类型。除非您在IDE将鼠标悬停其中,否则你将看不到这些类型。

清洁代码最重要的规则之一是:小方法。所以,让我们通过查看我们.collect(..)后面看到的代码,将这个长链分成两个方法.stream()。既然你Collect了一个集合中的项目,为什么我们不通过提取一个好的方法名来解释那个集合是什么?

<b>public</b> List<Product> getFrequentOrderedProducts(List<Order> orders) {
          <b>return</b> getProductCountsOverTheLastYear(orders).entrySet().stream()
                             .filter(e -> e.getValue() >= 10)
                             .map(Entry::getKey)
                             .filter(Product::isNotDeleted)
                             .filter(p -> !productRepo.getHiddenProductIds().contains(p.getId()))
                             .collect(toList());
}
<b>private</b> Map<Product, Integer> getProductCountsOverTheLastYear(List<Order> orders) {
          <b>return</b> orders.stream()
                             .filter(o -> o.getCreationDate().isAfter(LocalDate.now().minusYears(1)))
                             .flatMap(o -> o.getOrderLines().stream())
                             .collect(groupingBy(OrderLine::getProduct, summingInt(OrderLine::getItemCount)));
}

但是,只有这样我们才注意到在第6行,我们可能会在循环中查询外部系统!我的天啊!这是你永远不应该做的事情。

让我们开始流之前先获得hiddenProductIds 列表,我们甚至可以进一步检查产品是否隐藏在Predicate局部变量中:

<b>public</b> List<Product> getFrequentOrderedProducts(List<Order> orders) {
        List<Long> hiddenProductIds = productRepo.getHiddenProductIds();
        Predicate<Product> productIsNotHidden = p -> !hiddenProductIds.contains(p.getId());
        <b>return</b> getProductCountsOverTheLastYear(orders).entrySet().stream()
                        .filter(e -> e.getValue() >= 10)
                        .map(Entry::getKey)
                        .filter(Product::isNotDeleted)
                        .filter(productIsNotHidden)
                        .collect(toList());

还有一件事我们可以做:我们可以命名被频繁订购的产品的流,并使其成为Stream类型的变量。众所周知,这些Stream项目实际上并未在此时进行计算评估,而是仅在结束时.collect()进行计算评估。但是,Stream<>有时不鼓励使用变量,因为粗心的开发人员可能会尝试重新使用它(重新遍历它),因此在执行此操作之前,请确保您的团队完全了解这种常见情况。

<b>public</b> List<Product> getFrequentOrderedProducts(List<Order> orders) {
        List<Long> hiddenProductIds = productRepo.getHiddenProductIds();
        Predicate<Product> productIsNotHidden = p -> !hiddenProductIds.contains(p.getId());
        Stream<Product> frequentProducts = getProductCountsOverTheLastYear(orders).entrySet().stream()
                        .filter(e -> e.getValue() >= 10)
                        .map(Entry::getKey);
        <b>return</b> frequentProducts
                        .filter(Product::isNotDeleted)
                        .filter(productIsNotHidden)
                        .collect(toList());
}
<p>[...]

这里的想法是通过引入解释变量来避免过多的方法链。这意味着 提取方法甚至使用函数或Stream类型的变量,以使代码尽可能清晰地显示给读者。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Adobe Dreamweaver CS5中文版经典教程

Adobe Dreamweaver CS5中文版经典教程

Adobe公司 / 陈宗斌 / 人民邮电 / 2011-1 / 45.00元

《Adobe Dreamweaver CS5中文版经典教程》由Adobe公司的专家编写,是AdobeDreamweavelCS5软件的官方指定培训教材。全书共分为17课,每一课先介绍重要的知识点,然后借助具体的示例进行讲解,步骤详细、重点明确,手把手教你如何进行实际操作。全书是一个有机的整体,它涵盖了Dreamweavercs5的基础知识、HTML基础、CSS基础、创建页面布局、使用层叠样式表、使......一起来看看 《Adobe Dreamweaver CS5中文版经典教程》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

SHA 加密
SHA 加密

SHA 加密工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具