2월 05, 2024

[Java8] Stream에서 가장 처음 나오는 요소 받기, findAny(), findFirst() 차이점

Java 8에서 자주 사용되는 Lambda 식과 Stream, 그 중에서도 findAny() 와 findFirst()가 자주 쓰인다. 둘 다 Stream에서 발견되는 첫 요소를 return 해준다는 점에서 공통점이 있지만 차이점도 있으니 예시를 통해 알아보자. 


1) findFirst()

findFirst()는 filter() 안에 있는 조건에 일치하는 요소 하나를 return 해준다. 

List<String> lists = Arrays.asList("apple", "banana", "alien", "boat");

Optional<String> foundElement = lists.stream()
.filter(element -> element.startsWith("a")).findFirst(); System.out.println("first element found: " + foundElement.get()); 
 


와 같이 findFirst를 사용하고 결과값을 출력해주면 

first element found: apple

이라는 결과값이 출력된다. 


2) findAny() 

findAny() 또한 findFirst()와 크게 다르지 않다. 위와 같은 예제 코드에 findFirst()만 findAny()로 바꾸어서 출력을 해보겠다. 

List<String> lists = Arrays.asList("apple", "banana", "alien", "boat");

Optional<String> foundElement = lists.stream()
.filter(element -> element.startsWith("a")).findAny(); System.out.println("first element found: " + foundElement.get()); 
 


마찬가지로 

first element found: apple


a로 시작하는 가장 처음에 있는 요소인 apple이 반환된다. 


3. findFirst()와 findAny()의 차이점

findFirst()와 findAny()는 Multi thread 환경에서 차이점을 보인다. 직렬로 처리할 때는 둘 사이에 차이가 없고 return 되는 결과값에도 차이가 없다. 

다만 multi thread 환경에서는 차이가 있을 수 있다.

findFirst()는 multi thread 환경에서도 우리가 예상하는 결과처럼 항상 동일하게 가장 앞에 있는 요소가 return된다.


다만 findAny()의 경우 병렬 환경에서 Stream 상에서 가장 먼저 발견된 요소가 return 되기 때문에 가장 앞에 있는 요소가 return 되지 않을 수도 있다. 


즉, 

List<String> lists = Arrays.asList("apple", "banana", "alien", "boat");

Optional<String> foundElement = lists.stream().parallel()
.filter(element -> element.startsWith("a")).findAny(); System.out.println("first element found: " + foundElement.get()); 
 


만약 parallel() 이 붙어서 병렬 환경에서 요소를 찾는다면 

apple 이 아닌 alien이 return 될 수도 있다는 말이다. 


하지만 findAny()가 아닌, findFirst()라면 언제나 apple이 return된다는 차이가 있다.