Java 8 findFirst和Conference顺序
如果流具有遭遇顺序,则始终返回第一个元素,但是如果流没有遭遇顺序,则可以返回任何元素 我试图演示这在没有遭遇顺序的流上是如何工作的,但是除了实际的第一个元素之外,我无法让它返回任何东西 我尝试将元素添加到未定义遭遇顺序的Java 8 findFirst和Conference顺序,java,java-8,Java,Java 8,如果流具有遭遇顺序,则始终返回第一个元素,但是如果流没有遭遇顺序,则可以返回任何元素 我试图演示这在没有遭遇顺序的流上是如何工作的,但是除了实际的第一个元素之外,我无法让它返回任何东西 我尝试将元素添加到未定义遭遇顺序的集合中: Set<String> words = new HashSet<>(); words.addAll(Arrays.asList("this", "is", "a", "stream", "of", "strings"));
集合中:
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
然后我尝试使用BaseStream
中的unordered
方法,该方法声称返回一个没有遭遇顺序的流,但没有区别:
firstString = Stream.of("this", "is", "a", "stream", "of", "strings")
.unordered()
.findFirst();
System.out.println(firstString);
现在我每次都会听到这个词。我错过什么了吗?有什么方法可以证明无序流上的findFirst
返回不同的值吗?通过将流标记为无序流,实际上您并没有使其成为无序流(您的集合中的顺序没有任何不同),而是删除了有序流可能施加的任何限制
证明这将返回不同结果的方法是使用并行流
Set<String> words = new HashSet<>();
words.addAll(Arrays.asList("this", "is", "a", "stream", "of", "strings"));
Optional<String> firstString = words.stream().parallel()
.findFirst();
System.out.println(firstString);
将集合更改为列表并并行运行将保留顺序:
List<String> words = new ArrayList<>();
words.addAll(Arrays.asList("this", "is", "a", "stream", "of", "strings"));
Optional<String> firstString = words.stream().parallel()
.findFirst();
System.out.println(firstString); // always Optional[this]
List words=new ArrayList();
addAll(Arrays.asList(“this”、“is”、“a”、“stream”、“of”、“strings”));
可选的firstString=words.stream().parallel()
.findFirst();
System.out.println(第一个字符串);//始终可选[此]
这里必须阅读的绝对值是,正如@Eugene已经提到的,调用无序
并不一定会改变元素的实际物理顺序。不要忘记,unordered
是一个中间操作,在调用终端操作之前,它不会执行任何操作
因此,我倾向于这样想:
当创建一个包含元素“this”、“is”、“a”、“stream”、“of”、“strings”
的集时,当迭代集中的第一个元素是“a”
,因此findFirst
只返回该值
当您使用stream.of(“this”、“is”、“stream”、“of”、“strings”)
创建流时,它返回一个带有排序限制的流,findFirst
。调用unordered
会删除该限制,但元素“this”
在物理上仍然是第一个元素,因为unordered
不一定会更改源数组中的顺序
一个稍微好一点的例子可能是:
Set<String> words = new HashSet<>();
words.addAll(Arrays.asList("this", "is", "stream", "of", "strings"));
Optional<String> firstString1 = words.stream().findFirst();
// Optional[strings]
System.out.println(firstString1);
Optional<String> firstString2 = words.stream()
.sorted().findFirst();
// Optional[is]
System.out.println(firstString2);
Optional<String> firstString3 = Stream.of("this", "is", "stream", "of", "strings")
.findFirst();
// Optional[this]
System.out.println(firstString3);
Optional<String> firstString4 = Stream.of("this", "is", "stream", "of", "strings")
.unordered().findFirst();
// Optional[this]
System.out.println(firstString4);
Set words=newhashset();
addAll(Arrays.asList(“this”、“is”、“stream”、“of”、“strings”));
可选的firstString1=words.stream().findFirst();
//可选[字符串]
System.out.println(firstString1);
可选的firstString2=words.stream()
.sorted().findFirst();
//可选的[是]
System.out.println(firstString2);
可选firstString3=Stream.of(“this”、“is”、“Stream”、“of”、“strings”)
.findFirst();
//可选[此]
System.out.println(firstString3);
可选firstString4=Stream.of(“this”、“is”、“Stream”、“of”、“strings”)
.unordered().findFirst();
//可选[此]
System.out.println(firstString4);
请注意sorted()
方法是如何更改结果的,因为它强制执行排序限制,而unordered
方法没有效果。好的,“any”包括“first”的可能性。当然,流实现不会在随机化数据方面浪费精力,因此对于很多情况,尤其是顺序执行,如果我们可以这样称呼它,它仍然是第一个元素(因为没有顺序,就没有可区分的第一个元素)
对于findFirst
,显示不同结果的最佳机会是使用并行流。但即便如此,并不是所有的操作组合都适合表现出无序性
一点是,在当前的实现中,findFirst()
操作在流无序时不会改变其行为,即它不会主动尝试像findAny()
。由于流的来源,它可能仍然表现出不可预测的行为,但是如果您的源是流。of(“this”、“is”、“a”、“Stream”、“of”、“strings”)
,即一个已知大小的不可变序列,它已经有了可能的最佳并行性能,因此根本无法从链式无序()中获益
,因此,当前实现不会改变其行为
这可能会让人惊讶,但在某种程度上,这甚至适用于HashSet
。虽然它有一个未指定的顺序,但在某个时间点它的支持数组中会有一个实际的顺序,并且只要您不修改集合
,就没有理由对这些条目进行混洗,因此对于特定的HashSet
实例,您可能会重复获得相同的“first”元素,虽然没有指定哪一个,甚至在单个运行时内,但另一个表示相同内容但具有不同历史的HashSet
实例可能具有不同的顺序
已知可从无序特征中获益的操作的一个示例是distinct
。虽然它必须对重复项进行排序,但如果有显著差异,它必须保持第一个遇到的元素相等。这会显著降低性能,因此,如果流无序,实现将立即尝试获得好处。例如
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);
将打印范围的任意数字,因为我们已发布订购合同,并允许选择任何相等的字符串
阿尔雷亚
Set<String> words = new HashSet<>();
words.addAll(Arrays.asList("this", "is", "stream", "of", "strings"));
Optional<String> firstString1 = words.stream().findFirst();
// Optional[strings]
System.out.println(firstString1);
Optional<String> firstString2 = words.stream()
.sorted().findFirst();
// Optional[is]
System.out.println(firstString2);
Optional<String> firstString3 = Stream.of("this", "is", "stream", "of", "strings")
.findFirst();
// Optional[this]
System.out.println(firstString3);
Optional<String> firstString4 = Stream.of("this", "is", "stream", "of", "strings")
.unordered().findFirst();
// Optional[this]
System.out.println(firstString4);
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.parallelStream().unordered().distinct().map(map::get)
.findFirst().ifPresent(System.out::println);
List<String> wordList = Arrays.asList("this", "is", "a", "stream", "of", "strings");
Set<String> words = new HashSet<>(wordList);
Set<String> words2 = new HashSet<>(wordList);
IntStream.range(0, 50).forEachOrdered(i -> words2.add(String.valueOf(i)));
words2.retainAll(wordList);
System.out.println(words.equals(words2));
System.out.println(words);
System.out.println(words2);
true
[a, strings, stream, of, this, is]
[this, is, strings, stream, of, a]