Suppose, you have a list of
prime numbers
and you need to
find the first prime number which is greater than a given number?
How do you find it? Don't tell that you will
loop through the list
and check each element and return the first element which is greater than the given number. Well, that's right but that's not what you should do in
Java 8
. That's good for Java 7 or earlier version but Java 8 offers you many better alternatives and one of them is Stream. You can use the Stream class along with
filter()
and
findFirst()
methods to find out an element based upon a
Predicate
, a
functional interface
for defining a condition which returns a boolean.
The
java.util.stream.Stream
class provides a couple of find methods to search elements in Stream,
findFirst()
and
findAny()
.
As the name suggests, the findFirst method returns the first element from the Stream, wrapped in an Optional, but only if the Stream maintains an order like a Stream generated from an
ArrayList
or
LinkedHashMap
which keeps elements in order.
If Stream doesn't maintain order then any element will be returning and this is what the
findAny()
method does. It returns an element from Stream.
That's why
it's not guaranteed to receive the same element
if you call this method again.
Both
findFirst()
and
findAny()
are short-circuit methods, much like short circuit AND (&&) and
OR (||)
operators which will not evaluate any more elements once they found one. If you are not familiar with what is a short circuit operation in Java, I suggest you go through the
Complete Java Masterclass
course
on Udemy, one of the most comprehensive courses on Java.
How to find the first element from a Stream with a filter
Now, let's come back to the task at hand. As the problem statement says, we have a list of prime numbers in the increasing order e.g. 2, 3, 5, 7, 11, 13 and we need to find the first
prime number
which is greater than 5 i.e. our code should return 7.
In order to achieve that
we'll first get the
Stream
from the
List
and then call the
filter()
method with the predicate
number > 7
, after that we'll call the
findFirst()
method. This will give us the result.
If you remember, filter() is an intermediate method which means after applying a filter, you can still call other methods on stream. It's also lazy which means it will not do anything until you call a terminal method like
findFirst()
. You can further see
Learn Java Functional Programming with Lambdas and Stream
course
by Ranga Karnam to learn more about Stream features.
Java 8 Stream filter + findFirst Example
Here is the code to
find the first element from a List in Java 8 after applying a predicate
:
import java.util.Arrays;
import java.util.List;
* A simple example find the first element from
* List based upon condition.
public class Hello {
public static void main(String args[]) {
List<Integer> primes = Arrays.asList(2, 3, 5, 7, 11, 13);
int primeGreaterThanFive = primes.stream()
.peek(num -> System.out.println("will filter " + num))
.filter(x -> x > 5)
.findFirst()
.get();
System.out.println(primeGreaterThanFive);
Output:
will filter 2
will filter 3
will filter 5
will filter 7
The code is simple, except for the peek() and get() method. I have used peek() to demonstrate that filter will not do anything until you call the findFirst() method which is a terminal operation.
Since filter() is lazy it will only process the element needed to satisfy the criterion by findFirst() and that's why all elements will not be required to process.
You can see that only 2, 3, 5, and 7 are processed to return the result. It has not touched 11 and 13.
If you change the condition to return prime which is greater than 3, then only 2, 3, and 5 will be touched. This provides a big performance boost if you are dealing with a large list e.g. something with 1 million numbers or Strings.
The get() method is used to retrieve a value from the Optional return by the findFrst() method. If you want you can also use the OrElse() method to define a default value just in case Optional is empty.
Btw, this is an extremely common code if you have started coding in Java because most of my Java 8 refactoring is replacing the loop with a functional equivalent. If you are also refactoring your code to take advantage of Java 8, I suggest you check out Heinz Kabutz's Refactoring to Java 8 Streams and Lambdas course which provides many tips with the explanation to take full advantage of Java 8 features.
That's all about how to find the first element from a List or Stream in Java 8 which satisfies a condition. As you can see that we can specify the condition using a Predicate, which is nothing but a Functional interface with just one method test(), which returns a boolean. You can use it along with methods like the filter to perform several interesting jobs in Java 8.
Btw, if you are just starting with Java 8 then The Complete Java SE 8 Developer BootCamp course on Udemy is a nice place to start with. It nicely covers all the Java 8 topics and also helps you to prepare for OCAJP 8.
Other Java 8 Lambda and Stream Tutorials You may like