Java 8 Stream.findAny() 与在流中查找随机元素
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25912185/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java 8 Stream.findAny() vs finding a random element in the stream
提问by Patrick Grimard
In my Spring application, I have a Couchbase repository for a document type of QuoteOfTheDay
. The document is very basic, just has an id field of type UUID, value field of type String and created date field of type Date.
在我的 Spring 应用程序中,我有一个 Couchbase 存储库,用于QuoteOfTheDay
. 该文档非常基础,只有一个 UUID 类型的 id 字段、String 类型的 value 字段和 Date 类型的创建日期字段。
In my service class, I have a method that returns a random quote of the day. Initially I tried simply doing the following, which returned an argument of type Optional<QuoteOfTheDay>
, but it would seem that findAny() would pretty much always return the same element in the stream. There's only about 10 elements at the moment.
在我的服务类中,我有一个方法可以返回当天的随机报价。最初我尝试简单地执行以下操作,它返回一个 type 参数Optional<QuoteOfTheDay>
,但似乎 findAny() 几乎总是返回流中的相同元素。目前只有大约 10 个元素。
public Optional<QuoteOfTheDay> random() {
return StreamSupport.stream(repository.findAll().spliterator(), false).findAny();
}
Since I wanted something more random, I implemented the following which just returns a QuoteOfTheDay
.
由于我想要更随机的东西,我实现了以下只返回一个QuoteOfTheDay
.
public QuoteOfTheDay random() {
int count = Long.valueOf(repository.count()).intValue();
if(count > 0) {
Random r = new Random();
List<QuoteOfTheDay> quotes = StreamSupport.stream(repository.findAll().spliterator(), false)
.collect(toList());
return quotes.get(r.nextInt(count));
} else {
throw new IllegalStateException("No quotes found.");
}
}
I'm just curious how the findAny()
method of Stream actually works since it doesn't seem to be random.
我只是好奇findAny()
Stream的方法实际上是如何工作的,因为它似乎不是随机的。
Thanks.
谢谢。
回答by Keppil
The reason behind findAny()
is to give a more flexible alternative to findFirst()
. If you are not interested in getting a specific element, this gives the implementing stream more flexibility in case it is a parallel stream.
背后的原因findAny()
是为findFirst()
. 如果您对获取特定元素不感兴趣,这会为实现流提供更大的灵活性,以防它是并行流。
No effort will be made to randomize the element returned, it just doesn't give the same guarantees as findFirst()
, and might therefore be faster.
不会对返回的元素进行随机化,它只是不提供与 相同的保证findFirst()
,因此可能会更快。
This is what the Javadocsays on the subject:
这是Javadoc在这个主题上所说的:
The behavior of this operation is explicitly nondeterministic; it is free to select any element in the stream. This is to allow for maximal performance in parallel operations; the cost is that multiple invocations on the same source may not return the same result. (If a stable result is desired, use findFirst() instead.)
此操作的行为明显是不确定的;可以自由选择流中的任何元素。这是为了在并行操作中实现最大性能;代价是对同一源的多次调用可能不会返回相同的结果。(如果需要稳定的结果,请改用 findFirst()。)
回答by Holger
Don't collect into a List
when all you want is a single item. Just pick one item from the stream. By picking the item via Stream
operations you can even handle counts bigger than Integer.MAX_VALUE
and don't need the “interesting” way of hiding the fact that you are casting a long to an int
(that?Long.valueOf(repository.count()).intValue()
thing).
List
当你想要的只是一个项目时,不要收集到一个。只需从流中选择一项。通过Stream
操作选择项目,您甚至可以处理大于Integer.MAX_VALUE
并且不需要“有趣”的方式来隐藏您正在向int
(那个?Long.valueOf(repository.count()).intValue()
东西)投射 long 的事实。
public Optional<QuoteOfTheDay> random() {
long count = repository.count();
if(count==0) return Optional.empty();
Random r = new Random();
long randomIndex=count<=Integer.MAX_VALUE? r.nextInt((int)count):
r.longs(1, 0, count).findFirst().orElseThrow(AssertionError::new);
return StreamSupport.stream(repository.findAll().spliterator(), false)
.skip(randomIndex).findFirst();
}