在我的Spring应用程序中,我有一个Couchbase存储库,用于文档类型QuoteOfTheDay
.该文档非常基础,只有一个类型为UUID的id字段,类型为String的值字段,以及类型为Date的创建日期字段.
在我的服务类中,我有一个返回当天随机引用的方法.最初我尝试简单地执行以下操作,返回一个类型的参数Optional
,但似乎findAny()几乎总是返回流中的相同元素.目前只有大约10个元素.
public Optionalrandom() { return StreamSupport.stream(repository.findAll().spliterator(), false).findAny(); }
由于我想要更随机的东西,我实现了以下只返回一个QuoteOfTheDay
.
public QuoteOfTheDay random() { int count = Long.valueOf(repository.count()).intValue(); if(count > 0) { Random r = new Random(); Listquotes = StreamSupport.stream(repository.findAll().spliterator(), false) .collect(toList()); return quotes.get(r.nextInt(count)); } else { throw new IllegalStateException("No quotes found."); } }
我只是很好奇findAny()
Stream 的方法是如何实际工作的,因为它似乎不是随机的.
谢谢.
背后的原因findAny()
是提供更灵活的替代方案findFirst()
.如果您对获取特定元素不感兴趣,那么在实现流是并行流的情况下,这将为实现流提供更大的灵活性.
不会努力随机化返回的元素,它只是不提供相同的保证findFirst()
,因此可能更快.
这就是Javadoc在这个问题上所说的:
此操作的行为明确是不确定的; 可以自由选择流中的任何元素.这是为了在并行操作中实现最大性能; 成本是同一源上的多次调用可能不会返回相同的结果.(如果需要稳定的结果,请改用findFirst().)
List
当你想要的只是一个项目时,不要收集到.只需从流中选择一个项目即可.通过Stream
操作选择项目,你甚至可以处理大于Integer.MAX_VALUE
和不需要"有趣"的方法来隐藏你正在投入一个长期int
( Long.valueOf(repository.count()).intValue()
事情)的事实.
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(); }