Stream API를 무조건 쓰는 게 정답일까? (함수형 프로그래밍 with Java)

이 책을 읽기 전까지 저는 단순히 for 문을 Stream으로 전환하는 것이 '현대의 자바 같은 코드'라고 착각 했었습니다. 하지만 다 읽고서 기준을 스스로 세우게 되었습니다.
"람다는 고차 함수를 위한 도구이며, 이를 데이터 처리에 최적화한 것이 Stream API이다."
서비스 로직 한복판에 람다식이 복잡하게 구성되어 있다면, 작성한 본인조차 일주일 뒤엔 해석할 수 없는 코드가 됩니다. 특히 사이드 이펙트가 필연적인 비즈니스 로직을 억지로 스트림 안에 구겨 넣는 건 코드를 간결하게 만드는 게 아니라 더욱 스파게티 코드로 만드는 길이었습니다.
책에서 강조하는 함수형 프로그래밍의 핵심은 결국 '데이터 변환'입니다.
- Good: List<ClassA> 에서 List<ClassB>로 이어지는 명확한 변환 파이프라인
- Bad: 스트림 내부에서 외부 변수를 수정하거나, DB에 쿼리를 날리는 행위
이 책은 단순히 새로운 문법을 알려주는 것이 아니라, 더 나은 코드 품질을 위해 도구를 올바르게 쓰는 법을 가르쳐 주었습니다. 책을 읽으며 정리한 핵심 내용과 적용점을 남겨봅니다.
1. 함수형 인터페이스와 기본기
람다 표현식을 사용할 때 필수적으로 알아야 할 4가지 인터페이스가 있습니다.
- Function: 입력을 받아 변환하여 반환 (매핑)
- Consumer : 입력만 받고 반환 없음 (출력, DB 저장 등 사이드 이펙트 처리)
- Supplier : 입력 없이 결과만 반환 (지연 로딩)
- Predicate : 입력을 받아 참/거짓 판별 (필터링)
자바는 람다를 기존 시스템에 통합하기 위해 단 하나의 추상 메서드만 가진 인터페이스(SAM) 구조를 택했습니다. 또한 동시성 문제를 막기 위해 람다 내부에서는 외부 변수가 변경되지 않아야 한다는(Effectively Final) 제약이 있음을 이해하게 되었습니다.
2. Stream API는 파이프라인이다
스트림은 데이터를 저장하는 저장소가 아니라, 데이터를 변환하기 위한 도구입니다. Map(변환), Filter(선택), Reduce(도출)로 이어지는 흐름은 마치 데이터 엔지니어링의 파이프라인과 비슷합니다.
중요한 점은 스트림이 '지연 평가'를 한다는 것입니다. 최종 연산이 호출되기 전까지는 실제로 동작하지 않습니다. 또한 limit나 sorted 같은 연산은 상태를 가지므로 병렬 처리 시 병목이 될 수 있다는 점도 주의해야 합니다.
3. Record와 불변성
자바 14부터 도입된 Record 는 함수형 프로그래밍에서 강조하는 불변성을 지키는 데 큰 도움을 줍니다. 단순히 코드가 줄어드는 것을 넘어, 데이터를 투명하게 보유하고 불필요한 변경을 막아줍니다.
"불변성을 적용하는 건 어렵지만, 해제하는 건 쉽다"
책에 나온 이 문장이 기억에 남습니다. 처음부터 불변으로 설계하고 꼭 필요한 경우에만 가변으로 푸는 것이 정석입니다.
4. 병렬성과 Optional에 대한 오해
병렬 스트림(parallelStream)을 쓴다고 무조건 빨라지지 않습니다. 데이터가 매우 많거나 연산 비용이 높은 경우가 아니라면, 오히려 스레드 컨텍스트 스위칭 비용 때문에 더 느려질 수 있다고 합니다. 기본은 순차 스트림입니다. Optional 또한 주의해서 써야 합니다. 반환 타입으로만 사용해야 하며, 필드나 파라미터로 쓰는 건 지양해야 합니다. 값이 없음을 명시하는 문서 Wrapper Class 역할로 사용하는 것이 가장 적절하다고 생각합니다.
코드에 어떻게 적용할까?
책을 읽고 제 코드에 바로 적용해 보고 싶은 세 가지 원칙을 세웠습니다.
- 억지로 사용하는 Stream 줄이기
로직이 포함되어 복잡해진 Stream 은 과감하게 일반 for 문으로 되돌립니다. 스트림은 오직 순수 데이터 변환에만 사용합니다. - DTO는 Record로
새로 만드는 내부 데이터 전달 객체(DTO)는 Record Class를 기본으로 사용하여 불변성을 확보합니다. - CompletableFuture 활용
Plain Java Project에서 스레드 사용시 단순 스레드 풀 사용보다는 함수형 스타일로 조합이 가능한 CompletableFuture를 우선적으로 고려해 비동기 처리를 구현합니다.
잘 모를수록 화려한 기술에 현혹되기 쉽습니다. 본질에 집중해야 한다는 것을 항상 배우는 것 같습니다.
도서 정보
- 도서명: 함수형 프로그래밍 with Java (벤 바이디히 저)
