우당탕탕

Java Stream API 실전에서 많이 쓰는 패턴 직접 써보니 좋은 점과 주의할 점 본문

언어/Java

Java Stream API 실전에서 많이 쓰는 패턴 직접 써보니 좋은 점과 주의할 점

모찌모찝 2026. 5. 12. 14:30

Java Stream API를 실제 프로젝트에 적용하다 보니, 생각보다 삽질이 많았어요. 문법은 간단한데 코드가 복잡해지면 어디서 뭘 잘못했는지 찾기 어려운 경우가 많더라고요. 그래서 이번에 실전에서 자주 쓰는 패턴을 정리하면서 겪었던 문제와 해결법을 공유하려고 합니다.

이 글에선 대표적인 Stream 사용법과 실무에서 겪는 주요 이슈를 다루고, 제가 직접 쓴 코드 예시와 함께 설명해 드릴게요. 덕분에 Stream API가 훨씬 친근해졌어요.

Java Stream API 실전에서 많이 쓰는 패턴 정리 관련 이미지

Java Stream API 실전에서 많이 쓰는 패턴 정리 관련 정보

개발 환경 / 버전 정보

이번에 코드 작성에 사용한 환경은 Java 17OpenJDK입니다. 라이브러리 없이 순수 Java Stream API만 사용했어요.

이렇게 하면 됩니다: 필터링과 매핑 기본 패턴

사실 이 부분이 많은 분이 처음 겪는 헷갈림인데, filter와 map을 연속으로 쓸 때 어떤 식으로 연결하면 좋은지 알려드릴게요. 저는 리스트에서 특정 조건에 맞는 요소만 뽑고, 그걸 변환해 새 리스트로 만드는 패턴을 자주 씁니다.

// 사람 객체 리스트에서 성인이면서 이름만 뽑아서 리스트 만들기
List<String> adultNames = people.stream()
    .filter(person -> person.getAge() >= 20) // 20세 이상
    .map(Person::getName) // 이름만 뽑기
    .collect(Collectors.toList());

이렇게 하면 읽기 쉽고, 중간에 null이면 예외 나는 경우도 줄일 수 있어요. 그리고 stream을 끝낼 때 항상 collect() 혹은 forEach()를 쓰는 것도 잊지 마세요.

Java Stream API 실전에서 많이 쓰는 패턴 정리 관련 이미지

Java Stream API 실전에서 많이 쓰는 패턴 정리 관련 정보

여기서 많이 틀립니다: Optional 반환 다루기

많이들 헷갈려하시는 게 findFirst, findAny 같은 메서드에서 Optional을 어떻게 처리할지인데요, 저는 처음에 Optional을 바로 꺼내려다가 null 에러와 예외가 났었어요.

// 잘못된 사용: Optional에서 직접 값 꺼내기
String firstAdultName = people.stream()
    .filter(p -> p.getAge() >= 20)
    .map(Person::getName)
    .findFirst() // Optional<String>
    .get(); // 값 없으면 NoSuchElementException

이 에러가 왜 나는지 한참 찾았는데, Optional 값을 꺼낼 때는 꼭 orElse, orElseGet, ifPresent 등으로 안전하게 처리해야 한다는 걸 배웠어요.

// Optional 안전하게 처리하기
String firstAdultName = people.stream()
    .filter(p -> p.getAge() >= 20)
    .map(Person::getName)
    .findFirst()
    .orElse("Unknown");

심화: 병렬 처리로 성능 개선 시 고려할 점

Stream API의 parallel() 메서드는 잘 쓰면 성능 개선에 도움이 되는데, 상태를 변경하는 작업이나 동기화가 필요한 부분에선 오히려 문제를 일으켰어요. 저는 한 프로젝트에서 병렬 처리로 컬렉션을 수정하다가 ConcurrentModificationException이 났었죠.

그래서 병렬 스트림을 쓸 때는 반드시 **불변 객체**를 다루거나, 컬렉션을 수정하지 말고 결과를 새로 만들어야 한다는 점 꼭 기억했어요.

자주 물어보시는 것들

Q. Stream API를 쓰면 무조건 성능이 좋아지나요?

A. 꼭 그렇진 않아요. 특히 작은 데이터셋에서는 스트림 오버헤드가 성능 저하로 이어질 수 있어요. 또한 병렬 처리 시에는 동기화 비용도 생각해야 합니다.

Q. null 값이 있는 컬렉션에서 스트림을 안전하게 쓰는 방법이 있을까요?

A. null 자체가 들어있는 컬렉션은 피하는 게 최선인데, 불가피하다면 filter(Objects::nonNull)로 null을 걸러내고 처리하세요.

Java Stream API 실전에서 많이 쓰는 패턴 정리 관련 이미지

Java Stream API 실전에서 많이 쓰는 패턴 정리 관련 정보

정리해보면, Stream API는 코드 가독성을 크게 높여주고, 깔끔한 함수형 스타일로 짜기가 좋아요. 다만 Optional과 병렬처리 사용 시 주의가 필요하니 직접 써보면서 익히는 걸 추천합니다. 이런 경험들이 쌓이면 백엔드 개발에서 정말 든든한 무기가 될 거예요.

Comments