Difference between findAny() and findFirst() in Java 8

JavaJava 8Java Stream

Java Problem Overview


I am little confused between Stream#findAny() and Stream#findFirst() of the Stream API in Java 8.

What I understood is that both will return the first matched element from the stream, for example, when used in conjunction with filter?

So, why two methods for the same task? Am I missing something?

Java Solutions


Solution 1 - Java

> What I understood is that both will return the first matched element > from the stream, for example, when used in conjunction with filter?

That's not true. According to the javadoc, Stream#findAny():

> Returns an Optional<T> describing some element of the stream, or an empty > Optional<T> if the stream is empty. > 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;

while Stream.findFirst() will return an Optional<T> describing strictly the first element of the stream. The Stream class doesn't have a .findOne() method, so I suppose you meant .findFirst().

Solution 2 - Java

No, both will not return the first element of the Stream.

From Stream.findAny() (emphasis mine): >Returns an Optional describing some element of the stream, or an empty Optional if the stream is empty. > >This is a short-circuiting terminal operation. > 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.)

So to put it more simply, it may or may not choose the first element of the Stream.

With the current Oracle-specific implementation, I believe that it will return the first element in a non-parallel pipeline. However, in a parallel pipeline, it won't always, executing for example

System.out.println(IntStream.range(0, 100).parallel().findAny());

it returned OptionalInt[50] when I ran it. Anyhow, you must not rely on that.

Solution 3 - Java

findFirst return the first elements of the stream but findAny is free to select any element in the stream.

List<String> lst1 = Arrays.asList("Jhonny", "David", "Jack", "Duke", "Jill","Dany","Julia","Jenish","Divya");
List<String> lst2 = Arrays.asList("Jhonny", "David", "Jack", "Duke", "Jill","Dany","Julia","Jenish","Divya");

Optional<String> findFirst = lst1.parallelStream().filter(s -> s.startsWith("D")).findFirst();
Optional<String> fidnAny = lst2.parallelStream().filter(s -> s.startsWith("J")).findAny();

System.out.println(findFirst.get()); //Always print David
System.out.println(fidnAny.get()); //Print Jack/Jill/Julia :behavior of this operation is explicitly nondeterministic

Solution 4 - Java

in parallel mode the findAny does not guaranteed order, but the findFirst does.

I wrote some code snippet to show the difference, visit it

Solution 5 - Java

In stream findFirst and findAny return first element and do not execute the rest but in parallelStream, it is not passible to say the order and parallelStream executes the rest of the collection.

Reference

Time 1:25:00

Solution 6 - Java

I will just say that beware Of findFirst() And findAny() while using.

As from from their Javadoc (here and here) both methods return an arbitrary element from the stream – unless the stream has an encounter order, in which case findFirst() returns the first element while findAny() will return any element.

Suppose we have custom list consisting ISBN and BOOK name. For a scenario look at this example:

public class Solution {
   private Integer ISBN;
   private String BookName;
   
public Solution(int i, String string) {
	ISBN =i;
	BookName = string;
}
//getters and setters
}

public static void main(String[] args) {
		List<Solution> Library = Arrays.asList(new Solution(12,"Java in Action"),new Solution(13,"Java 8"),new Solution(15,"Java 8 Features"),new Solution(16,"Java in Action"));
 System.out.println(Library.stream()
		.map(p->p.getBookName())
		.sorted(Comparator.reverseOrder())
		.findFirst());
	}

Output: Optional[Java in Action]

There can be scenarios when the Book name are same but ISBN numbers are different, in that case sorting and finding the book can be much similar to findAny() and will give wrong result. Think of a scenario where 5 books are named "Java Reference" but have different ISBN numbers and findFirst() book by name will result in same as findAny().

Think of a scenario where:

 ISBN    Name Of book
+-----+------------------+
| 100 | Java-8 in Action |
+-----+------------------+
| 101 | Java-8 in Action |
+-----+------------------+
| 102 | Java-8 in Action |
+-----+------------------+
| 103 | Java-8 in Action |
+-----+------------------+
| 104 | Java-8 in Action |
+-----+------------------+

here findFirst() and findAny() will give same result even if sorted on BookByName.

Detailed Article:

Solution 7 - Java

[1]I have developed a small code to test findAny and findFirst of stream. I have created 10 millions of dummy data and filter those data and apply findAny and findFirst by using parallel stream and sequential stream on both.

From the small experiment, I have found that findAny and findFirst gives same result and it provides the first result in sequential stream. but I found that findAny doesnot gurantee to produce same result each time in parallelStream and findFirst gives gurantee that it always produces the same result either stream is parallel or sequential.

public class TestFilter {
static class Employee {
	String name;
	double salary;
	long id;

	public Employee(String name, long id, double salary) {
		this.name = name;
		this.id = id;
		this.salary = salary;
	}

	String genNextName() {
		return "Emp-" + (this.id + 1);
	}

	double genNextSalary() {
		return new Random().nextDouble() * 1000000;
	}

	long genNextId() {
		return this.id + 1;
	}

	@Override
	public String toString() {
		return this.id + " " + this.name + " " + this.salary + "\n";
	}
}

public static void main(String[] args) {
	List<Employee> employees = createDummyEmployee(10000000l);
	List<Employee> emps = null;
	long time = 0;
	for (int i = 0; i < 50; i++) {
		
		Optional<Employee> e1 = employees.stream()
				.filter(e -> e.name.endsWith("999"))
				.filter(e -> e.salary > 10000)
				.filter(e -> e.id % 2 == 1)
				.findAny();
		
		Optional<Employee> e2 = employees.stream()
				.filter(e -> e.name.endsWith("999"))
				.filter(e -> e.salary > 10000)
				.filter(e -> e.id % 2 == 1)
				.findFirst();
		
		Optional<Employee> pe1 = employees.parallelStream()
				.filter(e -> e.name.endsWith("999"))
				.filter(e -> e.salary > 10000).filter(e -> e.id % 2 == 1)
				.findAny();
		
		Optional<Employee> pe2 = employees.parallelStream()
				.filter(e -> e.name.endsWith("999"))
				.filter(e -> e.salary > 10000)
				.filter(e -> e.id % 2 == 1)
				.findFirst();

		System.out.print("FindAny without parallel : " + (e1.isPresent() ? e1.get().id +"": "null"));
		System.out.print(" | FindFirst without parallel : " + (e2.isPresent() ? e2.get().id +"": "null"));
		System.out.print(" | FindAny by Parallel : " + (pe1.isPresent() ? pe1.get().id +"": "null"));
		System.out.print(" | FindFirst by Parallel : " + (pe2.isPresent() ? pe2.get().id +"": "null"));
		System.out.println();
	}
}

public static List<Employee> createDummyEmployee(long n) {
	Employee e1 = new Employee("Emp-1", 1l, 1.0);
	return Stream.iterate(e1, (Employee e) -> new Employee(e.genNextName(), e.genNextId(), e.genNextSalary()))
			.limit(n).collect(Collectors.toList());
}

}

[Output of Experiment] [1]: https://i.stack.imgur.com/HOZjA.png

Solution 8 - Java

When Stream is unordered, findFirst() and findAny() are the same. But when Stream is ordered, findAny() will be better.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMandeep RajpalView Question on Stackoverflow
Solution 1 - JavaKonstantin YovkovView Answer on Stackoverflow
Solution 2 - JavaTunakiView Answer on Stackoverflow
Solution 3 - JavaAmirView Answer on Stackoverflow
Solution 4 - JavajiahutView Answer on Stackoverflow
Solution 5 - JavaemonView Answer on Stackoverflow
Solution 6 - JavaVishwa RatnaView Answer on Stackoverflow
Solution 7 - Javaprabhat gyawaliView Answer on Stackoverflow
Solution 8 - JavalogbasexView Answer on Stackoverflow