Java streams 22. FindAny, findFirst, max, min

Terminal operations either return values (of the same or other types) or do not return anything at all (produce just side effects). They do not allow other operations to be applied and close the stream.

Today we will cover three terminal operations, each returning an Optional object:

Optional<T> findAny(). Returns an Optional describing an element of the stream, or an empty Optional if the stream is empty.

Optional<T> findFirst(). Returns an Optional describing the first element of this stream, or an empty Optional if the stream is empty.

Optional<T> max(Comparator<T> comparator)
. Returns the maximum element of this stream according to the provided Comparator.

Optional<T> min(Comparator<T> comparator). Returns the minimum element of this stream according to the provided Comparator.

The reason these operators return an Optional is that, generally, there may be not a single element emitted (the Stream object is empty). An Optional object allows checking for the presence of the value before committing to getting it, thus avoiding unexpected behavior.



findAny()

The findAny() is a quite straightforward operator, especially useful when a stream is processed in parallel and you do not care which element you are going to get:

   
  String res1 = Stream.of("b", "c", "c", "a")
        .findAny()
        .orElse("x");
  System.out.print(res1);                //prints: b

  String res2 = Stream.of("b", "c", "c", "a")
        .parallel()
        .findAny()
        .orElse("x");
  System.out.print(res2);   //prints: c (may differ from run to run)

  String res3 = Stream.of("b", "c", "c", "a")
        .filter(s -> s.equals("z"))
        .findAny()
        .orElse("x");
  System.out.print(res3);                //prints: x
     

As you have probably guessed, this operation is optimized to not process all the stream elements but return a result as soon as it can be determined – at least one element was emitted by the Stream object.



findFirst()

The findFirst() operator behaves exactly as the findAny() operator when the stream is sequential. But when the stream is parallel, it may return quite different result:

      
  String res1 = Stream.of("b", "c", "c", "a")
        .findFirst()
        .orElse("x");
  System.out.print(res1);                //prints: b

  String res2 = Stream.of("b", "c", "c", "a")
        .parallel()
        .findFirst()
        .orElse("x");
  System.out.print(res2);   //prints: b (may differ from run to run)

  String res3 = Stream.of("b", "c", "c", "a")
        .filter(s -> s.equals("z"))
        .findFirst()
        .orElse("x");
  System.out.print(res3);                //prints: x
     

The findFirst() operator does not process all the stream elements too and returns the result as soon as the first element is emitted and received by one of the processing threads.



max() and min()

Please, notice, that the max() and min() operators of Stream object require a Comparator object as an input parameter. That is how they can process elements of any type – by sorting them using the provided comparator and taking the most left or the most right object correspondingly. And that is why the max() and min() operators of the numeric streams  IntStreamLongStream, and DoubleStream do not require any parameter – because the elements’ type is known.

In the examples of usage of the max() and min() Stream operators, we are going to use class Box:

     
  class Box implements Comparable<Box>{
     int weight;
     String color;

     public Box(int weight, String color) {
        this.weight = weight;
        this.color = color;
     }

     @Override
     public int compareTo(Box otherBox) {
        return this.color.compareTo(otherBox.color);
     }

     @Override
     public String toString() {
        return "Box{weight=" + weight +
                ", color='" + color + "'}";
     }
  }
     

Notice that the class Box implements the interface Comparable (method compareTo()). Using min() and max() does not require to do it. We just would like to demonstrate that they ignore Comparable implementation while calculating maximum and minimum value using the provided Comparator.

The following are examples of the max() operator usage:

   
  String max1 = Stream.of("a", "b", "c", "c", "a")
        .max(Comparator.naturalOrder())
        .get();
  System.out.print(max1);                //prints: c

  int max2 = Stream.of(22, 56, 3, -100)
        .max(Comparator.naturalOrder())
        .get();
  System.out.print(max2);                //prints: 56

  int max3 = Stream.of(22, 56, 3, -100)
        .max(Comparator.reverseOrder())
        .get();
  System.out.print(max3);                //prints: -100

  Box max4 = Stream.of(new Box(5, "red"), 
                     new Box(8, "green"), 
                     new Box(3, "blue"))
        .sorted(Comparator.naturalOrder())
        .findFirst()
        .get();
  System.out.print(max4);   //prints: Box{weight=3, color='blue'}

  Box max5 = Stream.of(new Box(5, "red"), 
                     new Box(8, "green"), 
                     new Box(3, "blue"))
        .max(Comparator.comparingInt(b -> b.weight))
        .get();
  System.out.print(max5);  //prints: Box{weight=8, color='green'}
        

And here are similar examples of the min() operator usage: 

    
  String min1 = Stream.of("a", "b", "c", "c", "a")
        .min(Comparator.naturalOrder())
        .get();
  System.out.print(min1);                //prints: a

  int min2 = Stream.of(22, 56, 3, -100)
        .min(Comparator.naturalOrder())
        .get();
  System.out.print(min2);                //prints: -100

  int min3 = Stream.of(22, 56, 3, -100)
        .min(Comparator.reverseOrder())
        .get();
  System.out.print(min3);                //prints: 56

  Box min4 = Stream.of(new Box(5, "red"), 
                     new Box(8, "green"), 
                     new Box(3, "blue"))
        .sorted(Comparator.reverseOrder())
        .findFirst()
        .get();
  System.out.print(min4);   //prints: Box{weight=5, color='red'}

  Box min5 = Stream.of(new Box(5, "red"), 
                     new Box(8, "green"), 
                     new Box(3, "blue"))
        .min(Comparator.comparingInt(b -> b.weight))
        .get();
  System.out.print(min5);  //prints: Box{weight=3, color='blue'}
     

As you can see, the min() and max() operator ignore Comparable implementation and return maximum and minimum value using the provided Comparator.

In the next post, we will continue discussing terminal operations and discuss the following two:

--Object[] toArray()
--A[] toArray(IntFunction<A[]> generator)

See other posts on Java 8 streams and posts on other topics.
You can also use navigation pages for Java stream related blogs:
— Java 8 streams blog titles
— Create stream
— Stream operations
— Stream operation collect()
The source code of all the code examples is here in GitHub

, ,

Send your comments using the link Contact or in response to my newsletter.
If you do not receive the newsletter, subscribe via link Subscribe under Contact.

Powered by WordPress. Designed by Woo Themes