问题描述
问题背景是有一个List<String>
你要找到最长的字符串长度,最初的思路就是采用
var ans = buffer.stream()
.reduce(0, (identity,element)->identity>element.length()?identity:element.length);
System.out.println(ans);
可是上面的代码就是会报错
按照正常的思路,初始值是0(就是这里的identity),然后接受链表里的元素,然后一路下来比较出最大的字符串长度,思路没有问题啊.于是我尝试了一下换了
var ans = buffer.stream()
.reduce(0, (identity, element) -> element.length() > identity ? element.length() : identity, Math::max);
System.out.println(ans);
这下就完全是对了
问题答案
其实这个问题,我查了下SO,发现有相应的回答,我先把原答案贴出来吧
我在这简便记录一下,做下总结
自我总结
- 为什么reduce 需要combiner
- reduce 是个什么样的过程
- reduce 怎么用
问题回答
reduce() 有两种,一种是
T reduce(T identity,
BinaryOperator<T> accumulator)
另一种是
<U> U reduce(U identity,
BiFunction<U,? super T,U> accumulator,
BinaryOperator<U> combiner)
分别对应上边报错和正确的解法,我们的目的是把String reduce成 Integer,对应两种不同的类型,上面的那种就是reduce成相同类型,所以我们这里需要一个combiner,这个方面完全就是从调用角度上来看的,没有啥太大意义,正如我刚才所说的,按照正常的思路完全可以实现,就像这样
那为什么java 库硬要搞出来一个combiner.这是因为
one of the design principles of the Streams API is that the API shouldn’t differ between sequential and parallel streams, or put another way, a particular API shouldn’t prevent a stream from running correctly either sequentially or in parallel. If your lambdas have the right properties (associative, non-interfering, etc.) a stream run sequentially or in parallel should give the same results.
简单来说就是并行和串行要准守同一套设计原则,不能我专门设计一个方法给你串行,然后我的并行没法用,反之同理.所以我们要看看,并行是如何进行reduce 的,拿一下原答案的图
一图胜千言,图解释的很清楚了,没啥要说了.
nuget:
- 之后想要reduce成另外一种类型,就得注意combiner了,可以注意并行流操作,并行流速度快一点
- 还是建议先map 或者其他操作转化成相同的类型在处理.比如
maptoInt()
转化成字符串的长度
配上相应的reduce教程
https://www.baeldung.com/java-stream-reduce
看完reduce ,打算再看看Collector
,groupingBy
啥的,嗯,妙~~~~啊