Programming/Java

[Java] Stream - findAny() VS findFirst()

엥재 2023. 9. 22. 15:42

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() 를 사용하자.