我已经讨论了前面的几个问题,比如java stream中的遭遇顺序保存、Brian Goetz的回答,以及javadoc for stream。reduce()和java。util。流包javadoc,但我仍然无法理解以下内容:
以这段代码为例:
public static void main(String... args) {
final String[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");
System.out.println("Alphabet: ".concat(Arrays.toString(alphabet)));
System.out.println(new HashSet<>(Arrays.asList(alphabet))
.parallelStream()
.unordered()
.peek(System.out::println)
.reduce("", (a,b) -> a + b, (a,b) -> a + b));
}
为什么减少总是保持遭遇顺序?
TLDR:。reduce()
并不总是保持顺序,它的结果基于流拆分器的特性。
分离器
流的相遇顺序取决于流拆分器(前面提到的答案都没有)。
基于源流有不同的分裂器。您可以从这些集合的源代码中获得分裂器的类型。
HashSet-
ArrayDeque命令
ArrayList=有序
树集-
logicbig.com-订购logicbig.com-有状态vs无状态
此外,您可以应用. unorder()
中间流操作,该操作指定流中的以下操作不应依赖于排序。
受拆分器和使用影响的流操作(大部分是有状态的)。unordered()
方法包括:
这些操作将根据流及其拆分器的顺序属性给出不同的结果。
。peek()
方法不考虑排序,如果流并行执行,它将始终以无序方式打印/接收元素。
.减少()
现在是终端。reduce()
方法。中间操作。unordered()
对拆分器的类型没有任何影响(正如@Eugene提到的)。但需要注意的是,它仍然和源拆分器中的一样。如果订购了源拆分器,则返回结果。如果源是的无序结果,则reduce()将被排序。reduce()将是无序的。
您正在使用新的HashSet
哈希集。reduce()-无序
"A","B","C","D","E","F" -> "ABCDEF"
"a","b","c","1","2","3","A","B","C" -> "a1Ab2Bc3C"
"Apple","Orange","Banana","Mango" -> "AppleMangoOrangeBanana"
TreeSet。reduce()-已排序
"A","B","C","D","E","F" -> "ABCDEF"
"a","b","c","1","2","3","A","B","C" -> "123ABCabc"
"Apple","Orange","Banana","Mango" -> "AppleBananaMangoOrange"
减少排序
"A","B","C","D","E","F" -> "ABCDEF"
"a","b","c","1","2","3","A","B","C" -> "abc123ABC"
"Apple","Orange","Banana","Mango" -> "AppleOrangeBananaMango"
您可以看到测试
。reduce()
仅对字母表源流进行操作可能会导致错误结论。
答案是
。reduce()
并不总是保持顺序,它的结果基于流拆分器的特性。
为了帮助解释这一点,我将把这个字符串的范围缩小到ABCD
。
并行流会把字符串分成两部分:AB
和CD
,当我们后面去组合这些的时候,AB
端的结果会是传入函数的第一个参数,而CD
端的结果会是传入函数的第二个参数,这是不管这两者到底哪个先完成的。
无序
运算符会影响流上的一些操作,比如一个限制
操作,它不影响一个简单的减少
。
首先,unordered
并不意味着真正的洗牌;它所做的一切都为流管道设置了一个标志——以后可以利用这个标志。
源元素的洗牌可能比流管道上的操作本身更昂贵,因此实现可能选择不这样做(就像在本例中一样)。
目前(测试和查看源代码)的jdk-8
和jdk-9
-减少
没有考虑到这一点。请注意,这在未来的构建或发布中很可能会改变。
另外,当你说unordered
——你实际上是说你不关心这个顺序,返回相同结果的流并不违反这个规则。
例如,请注意这个问题/答案,它解释了findFirst
例如(只是另一个终端操作)改变为在java-9中考虑无序
,而不是java-8。
我已经讨论了一些相关问题,比如如何确保java8流中的处理顺序?,我仍然不完全清楚输出元素的顺序。因此,请澄清我的以下疑问。 我认为至少在理论上(或根据java规范),它可以按1、2、3、4、5、6、7、8以外的随机顺序打印。我说得对吗? 还有一个相关的问题——遭遇订单保存的决定是在执行的哪个点做出的?更准确地说,在执行开始之前,是否通过检查源、中间操作和终端操作的特性来评估整个流水线的订单特性?
假设我有这样的代码: 输出是相同的线程名称,所以这里没有的好处--我的意思是有一个线程来完成所有的工作。 在内部有以下代码: 我理解强制属性如果“outer”流将是并行的(它们可能会阻塞),“outer”将不得不等待“flatmap”完成,反过来(因为使用了相同的公共池),但为什么总是强制这样做呢? 这是一个可以在以后的版本中改变的东西吗?
问题内容: 假设我有以下代码: 输出是相同的线程名称,因此这里没有任何好处-我的意思是,只有一个线程可以完成所有工作。 里面是这段代码: 我知道如果“外部”流是并行的(可能会阻塞),则强制该属性,“外部”将不得不等待“ flatMap”完成,反之亦然(因为使用了相同的公共池),但是为什么 总是 强迫那个? 那是在以后的版本中 可能会 更改的事情之一吗? 问题答案: 有两个不同方面。 首先,只有一个
问题内容: 以下代码以相同的插入顺序为我提供了输出。我阅读了Javadoc,他们甚至没有谈论插入顺序。有人可以帮助我获取正确的信息。 问题答案: 不,不是的。要保留插入顺序,请改用(javadoc)。 而且,现在优先于,因为它具有不必要的并发开销。(请参见HashMap和Hashtable之间的区别?。)
问题内容: 是否可以保留“ IN”条件子句的顺序? 我在SO上发现了这个问题,但在他的示例中,OP已经有一个排序的“ IN”子句。 我的情况不同,’IN’子句的顺序是随机的: 我想按(45,2,445,12,789)顺序检索结果。我正在使用Oracle数据库。也许SQL中有一个属性,我可以将其与条件子句一起使用以指定保持子句的顺序。 问题答案: 除非您使用ORDER BY子句..否则不会有可靠的排
问题内容: 我知道React可以异步并批量执行状态更新以优化性能。因此,在调用之后,您将永远无法相信要更新的状态。但是你可以信任的反应 更新相同的顺序状态被称为对 相同的组件? 不同的组件? 考虑在以下示例中单击按钮: 1. 在以下情况下,是否有可能 a为假而b为真 : 2. 在以下情况下,是否有可能 a为假而b为真 : 请记住,这些是我用例的极端简化。我意识到我可以以不同的方式进行操作,例如,在