第46项:优先选择Stream中无副作用的函数

  如果你是一个【使用】流的新手,可能很难掌握它们。仅仅将你的计算【过程】表示为流管道可能很难。当你成功的时候【成功地将计算过程用流管道表示出来】,你的程序会运行,但你可能几乎没有任何好处。Streams不仅仅是一个API,它还是一个基于函数式编程的范例。为了获得流必须提供的表现力,速度和某些情况下的并行性,你必须采用范例和API。

  流范例中最重要的部分是将计算结构化为一系列转换,其中每个阶段的结果尽可能接近前一阶段结果的纯函数( 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);
    });
}

  这段代码出了什么问题? 毕竟,它使用流,lambdas和方法引用,并得到正确的答案。简单地说,它根本不是流代码; 它的迭代代码伪装成流代码。它没有从流API中获益,并且它比相应的迭代代码更长,更难以阅读,并且可维护性更小。问题源于这样一个事实:这个代码在一个终端forEach操作中完成所有工作,使用一个变异外部状态的lambda(频率表)。执行除了呈现流执行的计算结果之外的任何操作的forEach操作都是“代码中的坏味道”,就比如一个变异状态的lambda。那么这段代码应该怎么样?

// Proper use of streams to initialize a frequency table
Map<String
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值