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

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

内容简介:假设你已经使用了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类型的变量,以使代码尽可能清晰地显示给读者。


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

查看所有标签

猜你喜欢:

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

游戏编程模式

游戏编程模式

Robert Nystrom / GPP翻组 / 人民邮电出版社 / 2016-9-1 / 61.4

游戏开发一直是热门的领域,掌握良好的游戏编程模式是开发人员的应备技能。本书细致地讲解了游戏开发需要用到的各种编程模式,并提供了丰富的示例。 全书共分20章,通过三大部分内容全面介绍了与游戏编程模式相关的各类知识点。首部分介绍了基础知识和框架;第二部分深入探索设计模式,并介绍了模式与游戏开发之间的关联;第三部分介绍了13种有效的游戏设计模式。 本书提供了丰富的代码示例,通过理论和代码示例......一起来看看 《游戏编程模式》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试