0. Overview
Stream API 관련 강의를 듣던 중 Optional 과 연관지어 사용하다가 findAny() 메서드와 findFirst() 메서드의 차이가 궁금해졌습니다.
findAny()는 Stream에서 가장 먼저 탐색되는 요소를 리턴하고, findFirst()는 조건에 일치하는 요소들 중 Stream에서 순서가 가장 앞에 있는 요소를 리턴하는데, 둘의 차이가 뭘까요 ?
🔍 findAny()
- findAny() 메서드는 스트림에서 임의의 요소를 반환합니다.
- 병렬 처리된 스트림에서는 빠르게 결과를 반환할 수 있고, 요소의 순서를 고려하지 않습니다.
- 대부분의 경우 병렬 처리된 스트림에서 성능상 이점을 가질 수 있어요.
🔍 findFirst()
- findFirst() 메서드는 스트림의 첫 번째 요소를 반환합니다.
- 스트림의 요소 순서를 기준으로 가장 처음에 나오는 요소를 찾습니다.
- 병렬 처리된 스트림에서도 항상 같은 요소를 반환합니다.
1. findAny() vs findFirst()
간단하게 findAny()와 findFirst() 메서드의 특징을 살펴보았는데요, 말로만 보았을때는 이해가 어려울 수 있습니다. 따라서 예제를 통해 살펴볼게요.
(1) 직렬 수행
public class FindAnyAndFirst {
public static void main(String[] args) {
Stream<Integer> integerStream = Arrays.asList(1, 2, 3, 4, 5)
.stream();
Optional<Integer> firstResult = integerStream
.filter(num -> num % 2 == 0) // 짝수 찾기
.findFirst();
System.out.println("findFirst(): " + firstResult.orElse(null));
-----------------------------------------------------------------------------
integerStream = Arrays.asList(1, 2, 3, 4, 5)
.stream();
Optional<Integer> anyResult = integerStream
.filter(num -> num % 2 == 0) // 짝수 찾기
.findAny();
System.out.println("findAny(): " + anyResult.orElse(null));
}
}
코드를 살펴보면, findFirst() 예제와 findAny()를 직렬로 처리하는 코드이기 때문에 둘의 결과는 2로 같은 값을 도출합니다.
(2) 병렬 수행
public class ParallelFindExample {
public static void main(String[] args) {
Stream<Integer> integerStream = Arrays.asList(1, 2, 3, 4, 5)
.parallelStream(); // 병렬 스트림으로 변경
Optional<Integer> firstResult = integerStream
.filter(num -> num % 2 == 0) // 짝수 찾기
.findFirst();
System.out.println("findFirst(): " + firstResult.orElse(null));
integerStream = Arrays.asList(1, 2, 3, 4, 5)
.parallelStream(); // 병렬 스트림으로 변경
Optional<Integer> anyResult = integerStream
.filter(num -> num % 2 == 0) // 짝수 찾기
.findAny();
System.out.println("findAny(): " + anyResult.orElse(null));
}
}
다음과 같이 병렬적으로 수행하게 되면, 둘의 출력 결과는 달라지게 됩니다. findFirst()는 그대로 2를 출력하고, findAny()는 2를 출력하기도 하고, 4를 출력하기도 합니다.
즉, findAny()는 Multi thread에서 Stream을 처리할 때 가장 먼저 찾은 요소를 리턴하므로 뒤쪽에 있는 요소가 반환될 수 있는것이죠.
결국 병렬스트림에선 findAny()가 더 빠른 결과값을 반환할 수 있습니다. 다만 요소의 순서를 고려하지 않는것이죠. 또한 findAny() 같은 경우 만족하는 값을 찾게 되면 즉시 종료하는 반면 , findFirst()는 끝까지 스트림을 탐색하고 이후 반환된 값 중 첫번째 값을 반환하게 됩니다.
결론
- 요소의 순서가 중요하지 않고, 그냥 스트림에서 어떠한 값이라도 찾고자 한다면 findAny()를 사용하자.
- 요소의 성능과 무관하고, 스트림의 성능과 무관한 경우 findFirst() 를 사용하자.