gpt4 book ai didi

Java 8 findFirst 和遇到顺序

转载 作者:IT老高 更新时间:2023-10-28 20:39:02 25 4
gpt4 key购买 nike

JavaDocs for findFirst说如果流有遇到顺序,那么总是返回第一个元素,但是如果流没有遇到顺序,则可以返回任何元素。

我试图演示它是如何在没有遇到顺序的流上工作的,但除了实际的第一个元素之外,我无法让它返回任何内容。

我尝试将元素添加到 Set,它没有定义遇到顺序:

    Set<String> words = new HashSet<>();
words.addAll(Arrays.asList("this", "is", "a", "stream", "of", "strings"));
Optional<String> firstString = words.stream()
.findFirst();
System.out.println(firstString);

每次我运行时,我都会得到 a 作为第一个字符串。然后我尝试在 List 上执行 Collections.shuffle,然后将其添加到 Set,但这并没有改变任何东西。

    List<String> wordList = Arrays.asList("this", "is", "a", "stream", "of", "strings");
words = new HashSet<>();
words.addAll(wordList);
firstString = words.stream()
.findFirst();
System.out.println(firstString);

我仍然每次都回想起a这个词。

然后我尝试使用 BaseStream 中的 unordered 方法,该方法声称返回没有遇到顺序的流,但没有区别:

    firstString = Stream.of("this", "is", "a", "stream", "of", "strings")
.unordered()
.findFirst();
System.out.println(firstString);

现在我每次都会得到 this 这个词。我错过了什么吗?有什么方法可以证明无序流上的 findFirst 返回不同的值?

最佳答案

嗯,“任何”包括“第一”的可能性。当然,Stream 的实现并没有浪费时间随机化数据,所以在很多情况下,尤其是顺序执行的情况下,它仍然是第一个元素,如果我们可以这样调用它(因为没有顺序,有没有区分的第一个元素)。

findFirst 展示不同结果的最佳机会是使用并行流。但即便如此,也不是每一种操作组合都适合表现出无序性。

有一点是,在当前的实现中,findFirst() 操作在流无序时不会改变它的行为,即它不会主动尝试像 findAny() 那样。由于 Stream 的 source,它仍可能表现出不可预测的行为,但如果您的源是 Stream.of("this", "is", "a", "stream", "of", "strings"),即已知大小的不可变序列,它已经具有可能的最佳并行性能,因此根本无法从链式 unordered(),因此,当前的实现不会改变它的行为。

这可能令人惊讶,但这在某种程度上甚至适用于 HashSet。虽然它有一个未指定的顺序,但在某个时间点,它的后备数组中会有一个实际的顺序,只要你不修改 Set,就没有理由打乱这些条目因此,对于特定的 HashSet 实例,您可能会重复获得相同的“第一个”元素,尽管没有指定哪个元素,甚至在单个运行时,另一个 HashSet 实例表示相同的内容,但具有不同的历史,可能有不同的顺序。


distinct 是已知从无序特征中获益的一个操作示例。虽然它必须对重复项进行排序,但它必须保持 first 遇到的相等元素,如果它产生显着差异的话。这会显着降低性能,因此,如果流是无序的,实现将立即尝试获得好处。例如

List<String> equal=IntStream.range(0, 100)
.mapToObj(i->new String("test")) // don't do this in normal code
.collect(Collectors.toList());
Map<String, Integer> map = IntStream.range(0, equal.size())
.collect(IdentityHashMap::new, (m,i)->m.put(equal.get(i),i), Map::putAll);

equal.parallelStream().distinct().map(map::get)
.findFirst().ifPresent(System.out::println);

这会创建一堆 equal 但可区分的 String 实例(您通常不应该这样做),并在 IdentityHashMap< 中使用它们的位置编号注册它们,因此我们可以找出 distinct 保留了哪个实例。由于上面的代码使用了由 List 创建的有序流,因此无论您多久执行一次,它都会始终打印 0

相比之下,

equal.parallelStream().unordered().distinct().map(map::get)
.findFirst().ifPresent(System.out::println);

将打印范围的任意数字,因为我们已经发布了 ordered 合约并允许选择任何相等的字符串。


如前所述,这都是特定于实现的。你永远不应该假设一个操作是否真的能带来好处,从而改变它对无序流的行为。上面的解释只是为了说明为什么有时特定实现的行为对于无序流可能不会改变。不过,它仍然可能在下一个版本或不同的 JRE 实现中。

关于Java 8 findFirst 和遇到顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41894173/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com