findFirst() and findAny() are short-circuiting terminal operations that each return an Optional wrapping a single stream element. findFirst() guarantees the element that appears first in encounter order, while findAny() makes no such guarantee.
Key Points: • findFirst() always returns the first element according to the stream's encounter order, making it deterministic for sequential and ordered streams. • findAny() is free to return any matching element, which allows the runtime to pick whichever element is fastest to produce. • On sequential streams the two often behave identically in practice, but the contract only guarantees this for findFirst(). • On parallel streams, findAny() can be significantly faster because it avoids the coordination needed to determine which element came first. • Both return an empty Optional if the stream has no elements.
Example: list.stream().filter(x -> x > 10).findFirst() reliably returns the first element greater than 10, while list.parallelStream().filter(x -> x > 10).findAny() may return any qualifying element, potentially different across runs.
Code Example:
List<Integer> nums = Arrays.asList(3, 7, 15, 22, 9);
Optional<Integer> first = nums.stream()
.filter(n -> n > 10)
.findFirst();
Optional<Integer> any = nums.parallelStream()
.filter(n -> n > 10)
.findAny();Interview Tip: A concise interview answer is:
"findFirst() always returns the first matching element in encounter order, so it's deterministic. findAny() can return any matching element and doesn't guarantee order, which lets parallel streams return faster because they don't need to coordinate on which element came first. I use findAny() only when order genuinely doesn't matter."