Java 8 Stream.findAny () versus finding a random element in a stream

In my Spring application, I have a Couchbase repository for the QuoteOfTheDay document QuoteOfTheDay . The document is very simple, just has an id field of type UUID, a value field of type String and created a date field of type Date.

In my service class, I have a method that returns a random quote of the day. At first I tried just to do the following, which returned an argument of type Optional<QuoteOfTheDay> , but it would seem that findAny () almost always returns the same element in the stream. At the moment, only about 10 elements.

 public Optional<QuoteOfTheDay> random() { return StreamSupport.stream(repository.findAll().spliterator(), false).findAny(); } 

Since I wanted something more random, I implemented the following, which simply returns 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 wondering how the findAny() Stream method works, since it doesn't seem random.

Thanks.

+6
source share
2 answers

The reason for findAny() is to provide a more flexible alternative to findFirst() . If you are not interested in getting a specific element, this gives the implementation thread more flexibility in the case of a parallel thread.

No effort will be made to randomize the returned item, it just does not give the same guarantees as findFirst() , and therefore can be faster.

Here is what Javadoc says:

The behavior of this operation is clearly non-deterministic; he can freely select any element in the stream. This should ensure maximum performance in parallel operations; the cost is that multiple calls in the same source may not return the same result. (If you want a stable result, use findFirst () instead.)

+21
source

Do not compile in a List when all you need is a separate item. Just select one item from the stream. By selecting an item using Stream operations, you can even process accounts more than Integer.MAX_VALUE , and you don’t need an “interesting” way to hide the fact that you are making a long int (this is Long.valueOf(repository.count()).intValue() thing).

 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(); } 
+10
source

Source: https://habr.com/ru/post/975484/


All Articles