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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值