纯函数(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]