纯函数(pure function)的结果仅取决于其输入:它不依赖于任何可变状态,也不更新任何状态。

坏味道

// Uses the streams API but not the paradigm--Don't do this!
Map<String, Long> freq = new HashMap<>();
try (Stream<String> words = new Scanner(file).tokens()) {words.forEach(word -> {freq.merge(word.toLowerCase(), 1L, Long::sum);});
}

forEach 操作应仅用于报告流计算的结果,而不是用于执行计算

// Proper use of streams to initialize a frequency table
Map<String, Long> freq;
try (Stream<String> words = new Scanner(file).tokens()) {freq = words.collect(groupingBy(String::toLowerCase, counting()));
}

Collectors有三个这样的收集器: toList() 、toSet() 和toCollection(collectionFactory) 。它们分别返回集合、列表和程序员指定的集合类型

// Pipeline to get a top-ten list of words from a frequency table
List<String> topTen = freq.keySet().stream().sorted(comparing(freq::get).reversed()).limit(10).collect(toList());

toMap(keyMapper、valueMapper)最简单的映射收集器 ,它接受两个函数,一个将流元素映射到键,另一个映射到值

// Using a toMap collector to make a map from string to enum
private static final Map<String, Operation> stringToEnum =Stream.of(values()).collect(toMap(Object::toString, e -> e));

如果流中的每个元素都映射到唯一键,则这种简单的 toMap 形式是完美的。 如果多个流元素映射到同一个键,则管道将以 IllegalStateException 终止。

toMap 的三个参数形式对于从键到与该键关联的选定元素的映射也很有用。例如,假设我们有一系列不同艺术家(artists)的唱片集(albums),我们想要一张从唱片艺术家到最畅销专辑的 map。这个收集器将完成这项工作。

public class Apple implements Serializable {/*** 颜色.*/private String color;/*** 总量.*/private Integer weight;//get/set...
}
final Map<String, Apple> singleMap = list.stream().collect(Collectors.toMap(Apple::getColor, it -> it, BinaryOperator.maxBy(Comparator.comparing(Apple::getWeight))));

请注意,比较器使用静态工厂方法 maxBy ,它是从 BinaryOperator 静态导入的。 此方法将 Comparator<T>转换为 BinaryOperator<T> ,用于计算指定比较器隐含的最大值。

toMap 的三个参数形式的另一个用途是产生一个收集器,当发生冲突时强制执行 last-write-wins 策略。 对于许多流,结果是不确定的,但如果映射函数可能与键关联的所有值都相同,或者它们都是可接受的,则此收集器的行为可能正是您想要的:

// Collector to impose last-write-wins policy
final Map<String, Apple> singleMap = list.stream().collect(Collectors.toMap(Apple::getColor, it -> it, (oldVal, newVal) -> newVal));

toMap 的第三个也是最后一个版本采用第四个参数,它是一个 map 工厂,用于指定特定的 map 实现,例如EnumMap 或 TreeMap 。

groupingBy 方法,该方法返回收集器以生成基于分类器函数(classifier function) 将元素分组到类别中的 map。 分类器函数接受一个元素并返回它所属的类别。 此类别来用作元素的 map 的键。

Map<String, Long> freq = words.collect(groupingBy(String::toLowerCase, counting()));

join ,它仅对 CharSequence 实例(如字符串)的流进行操作。 在其无参数形式中,它返回一个简单地连接元素的收集器。

List<String> items =Arrays.asList("apple", "apple", "banana");
final String str = items.stream().collect(Collectors.joining(",", "[", "]"));//[apple,apple,banana]

Effective Java~46. 优先选择Stream 中无副作用的函数相关推荐

  1. Effective-Java 优先考虑流中无副作用的函数

    46. 优先考虑流中无副作用的函数 如果你是一个刚开始使用流的新手,那么很难掌握它们.仅仅将计算表示为流管道是很困难的.当你成功时,你的程序将运行,但对你来说可能没有意识到任何好处.流不仅仅是一个 A ...

  2. Java 8系列之Stream中万能的reduce

    Stream系列: Java 8系列之Stream的基本语法详解 Java 8系列之Stream的强大工具Collector Java 8系列之重构和定制收集器 Java 8系列之Stream中万能的 ...

  3. Effective Java~45. 谨慎使用Stream

    在 Java 8 中添加了 Stream API,以简化顺序或并行执行批量操作的任务. 该 API 提供了两个关键的抽象:流(Stream),表示有限或无限的数据元素序列,以及流管道 (stream ...

  4. java skip函数_【Java必修课】图说Stream中的skip()和limit()方法及组合使用

    1 简介 本文将讲解Java 8 Stream中的两个方法:skip()和limit().这两个方法是Stream很常用的,不仅各自会被高频使用,还可以组合出现,并能实现一些小功能,如subList和 ...

  5. Effective C# Item45 : 优先选择强异常安全保证

    当应用程序捕获一个异常时,代表着我们为应用程序引入了一个"具有破坏性的事件",异常可能会对系统资源或者应用程序的状态有破坏,我们应该避免这种情况发生. Dave Abrahams对 ...

  6. Effective Java之在细节消息中包含能捕获失败的消息(六十三)

    程序为捕获的异常而失败,系统会自动打印该异常的堆栈轨迹,在堆栈中包含该异常的字符串表示法(它的toString方法结果,包含类名,消息细节), 在这种情况下,我们有时看到一长串类名和自动生成的错误消息 ...

  7. Effective Java之优先使用标准的异常(六十)

    Java平台类库提供了一组基本的未受检的异常,他们满足了绝大部分API的异常抛出异常. 为什么优先使用标准异常 1.它使你的API可读性更强,因为它与程序员习惯的用法一致. 2.异常类越少,程序在类装 ...

  8. Effective Java之在公有类中使用访问方法而非公有域(十四)

    1.对于公有类来说,如果类可以在它所在的包的外部进行访问,就提供访问方法,以保留将来改变该类的内部表示法的灵活性. 如果公有域暴露了他的数据域,要想在将来改变它的内部表示法是不可能的,因为公有类的客户 ...

  9. python无返回值函数_理解Python 中无返回值函数的问题

    例如 list 的 append 操作就是无返回值的,换句话说就是不能进行形如 list = [] list.append(1).append(2) 这样的连续操作 注意函数返回的数据类型注意是 li ...

最新文章

  1. Tomcat 调优及 JVM 参数优化
  2. 百度地图的简单使用 ——html js
  3. 2021年技术人员的最佳Linux桌面前5名
  4. 在ionic/cordova中使用极光推送插件(jpush)
  5. 从这篇文章可以看出有些错误,由此可以看出,还是看msdn要好的多,这是我的经验
  6. 平移不变性:Translation Invariance 与 平移同变性:Translation equivariance
  7. 二叉树前序遍历python输出_Python 二叉树查找 前序 中序 后序遍历
  8. Codeforces 914D - Bash and a Tough Math Puzzle 线段树,区间GCD
  9. C语言不调用库函数画直线
  10. 转:VMware、微软等四种主要的网络IO虚拟化模型
  11. C++中动态定义一维数组,二维数组,三维数组的方法
  12. Linux查看版本信息及CPU内核、型号等
  13. 常用类 (三) ----- BigDecimal和BigInteger大数类
  14. python多线程提高速度_Python3如何使用多线程升程序运行速度
  15. python中print说法正确的是_python中的print()输出
  16. python入门11 元组tuple
  17. 设备管理系统未来发展的四大趋势
  18. Unity Editor 查找资源依赖、反向查找资源依赖Dependencies
  19. win10无法登录到你的账户->注销->重启->桌面初始化(只剩回收站+默认浏览器)等一系列问题出现
  20. JDK的下载与安装配置教程2022最新

热门文章

  1. 研讨会 | 知识图谱引领认知智能+
  2. 领域应用 | NLP 和知识图谱:金融科技领域的“双子星”
  3. 新闻文本内容知识图谱表示项目
  4. 配置opencv cmake
  5. 使用HDFS客户端java api读取hadoop集群上的信息
  6. Android开发中依赖注入的应用
  7. 电脑常用操作 (1)
  8. UVa10006-Carmichael Numbers
  9. 对一句正则表达式的理解
  10. 【剑指offer】面试题04:二维数组中的查找(java)