Computer >> 컴퓨터 >  >> 프로그래밍 >> Java

Java에서 Collection.stream().forEach()와 Collection.forEach()의 차이점 완벽 비교

Java에서 컬렉션을 순회하는 방법은 다양하지만, 그중 가장 많이 사용되는 두 가지가 바로 Collection.forEach()Collection.stream().forEach()입니다. 두 메서드 모두 컬렉션의 요소를 반복 처리한다는 공통점이 있지만, 내부 동작 방식과 특성에는 중요한 차이가 존재합니다.

Collection.forEach()의 동작 방식

Collection.forEach()는 컬렉션 자체의 Iterator(반복자)를 사용하여 요소를 순회합니다. 대부분의 컬렉션은 반복 도중 구조적 변경(structural modification)을 허용하지 않으며, 순회 중에 요소를 추가하거나 삭제하면 즉시 ConcurrentModificationException이 발생합니다.

또한 동기화된(synchronized) 컬렉션을 순회할 경우, Collection.forEach()는 해당 컬렉션의 세그먼트(segment)에 락(lock)을 걸고 모든 호출이 끝날 때까지 이를 유지합니다. 이러한 특성 덕분에 멀티스레드 환경에서 보다 안전하게 동작할 수 있습니다.

Collection.stream().forEach()의 동작 방식

Collection.stream().forEach() 역시 컬렉션을 순회하는 데 사용되지만, 먼저 컬렉션을 스트림(Stream)으로 변환한 후 그 스트림을 대상으로 순회를 수행합니다. 따라서 처리 순서(processing order)는 명확하게 정의되어 있지 않습니다.

순회 중 구조적 변경이 발생하면 마찬가지로 ConcurrentModificationException이 발생하지만, 예외가 발생하는 시점은 Collection.forEach()와 달리 나중으로 미루어질 수 있다는 점이 다릅니다.

두 방식의 주요 차이점 비교

번호구분Collection.forEach()Collection.stream().forEach()
1기본 원리컬렉션 자체의 Iterator를 사용하여 순회컬렉션을 스트림으로 변환한 후 스트림을 순회
2처리 순서Iterable에 순회 순서가 지정되어 있다면 항상 해당 순서대로 실행됨처리 순서가 정의되어 있지 않음
3락(Lock)동기화된 컬렉션을 순회할 경우 락을 걸고 모든 호출 동안 유지함컬렉션에 락을 걸지 않음
4예외 발생컬렉션에 구조적 변경이 발생하면 즉시 예외를 던짐예외가 나중에 발생할 수 있음

Collection.stream().forEach() 사용 예제

import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("Ram");
        list.add("TutorialPoints");
        list.stream().forEach(System.out::println);
    }
}

Collection.forEach() 사용 예제

import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("Ram");
        list.add("TutorialPoints");
        list.forEach(System.out::println);
    }
}

정리

순서가 중요하고 동기화된 컬렉션을 다룰 때는 Collection.forEach()가 적합하며, 병렬 처리나 스트림 API의 다양한 연산(map, filter 등)을 활용하고 싶다면 Collection.stream().forEach()를 사용하는 것이 좋습니다. 상황에 맞는 적절한 순회 방식을 선택하면 코드의 안정성과 성능을 모두 향상시킬 수 있습니다.