For문 vs Stream API
for, foreach
- 구체적인 로직이 외부에 노출되는 외부 반복의 형태입니다.
- for문은 java 1, foreach문은 java 5부터 등장했습니다.
- foreach문은 컴파일 시 for문으로 변환됩니다.
stream
- 구체적인 로직이 외부에 노출되지 않는 내부 반복의 형태입니다.
- 함수형 프로그래밍 패러다임이 도입된 java 8부터 등장했습니다.
차이
- 익숙함의 차이에서 오는 가독성의 호불호가 있습니다.
- stream을 사용할 경우 함수 객체로 표현이 되고 for문은 코드블록으로 표현된다.
- stream을 사용할 경우 stream 내부에서 지역변수를 수정할 수 없다.
- stream을 사용할 경우 for문의 continue, break을 사용할 수 없다.
- 디버깅 난이도의 차이가 있습니다.
- for 에러 발생 위치가 바로 노출됩니다.
- stream 지연 연산을 통해 실행되기에 에러 발생 시 위치를 추적해야 합니다.
- 병렬 처리 구현의 차이가 있습니다.
- for 구체적인 로직을 나누어 구현하고 합쳐야 합니다.
- stream parallelStream()으로 쉽게 처리됩니다.
왜 for문이 Stream보다 빠를까?
1. for문은 단순 인덱스 기반이다.
for문은 단순 인덱스 기반으로 도는 반복문으로 메모리 접근이기 때문에 Stream에 비해 빠르고 오버헤드도 없다.
stream의 경우는 JVM이 이것저것 처리해줘야하는 것들이 많아 실행 시 느릴 수 밖에 없다.
2. for문은 컴파일러가 최적화를 시킨다.
stream은 java 8부터 지원한 것이고 for문은 그보다 훨씬 오래전부터 계속 사용해왔다.
그만큼 사용되는 컴파일러는 오래 사용된 for문에 대한 처리가 되어 있어 for문의 경우 미리 최적화를 시킬 수 있지만,
stream의 경우 신생(?)인 만큼 정보가 없어 for문과 같은 정교한 최적화를 수행할 수 없다.
그렇다면 왜 Stream을 사용하는건가?
1. 가독성이 좋아진다.
이것도 개발자 역량에 따라 다르지만 stream을 사용하면 확실히 stream api에 포함되어 있는 여러 함수 들을 이용해 코드가 간결해진다.
물론 이것도 stream에 익숙하지 않은 사람은 그 의미를 일일이 해독하느라 코드를 읽는 시간디 더 걸릴 수 있지만,
stream을 한 두 번 보다보면 가독성이 좋다는 것이 느껴진다.
물론 이것도 무조건적인 장점은 아니다. 어떤 기능을 개발하느냐에 따라 for문이 가독성이 좋을 수 있고(특히 for문 안에서 중첩 반복 또는 조건문을 사용하는 경우) stream이 오히려 가독성이 안 좋을 수 있다.
2. 코드로 작성해야하는 로직을 stream에서 제공해주는 함수로 간단하게 해결 가능하다.
이것은 특히 filter, reduce 등과 같이 단순 forEach가 아닌 함수들을 사용할 경우 유용하다.
데이터가 많지 않을 경우 stream을 사용해도 (for문보다 성능이 떨어지지만) 속도가 느리지 않다.
그러니 코드로 일일이 기능을 구현해야하는 것들을 stream api에서 제공한다면 당연히 stream을 사용하든 것이 좋다.
스트림 API에서 중간 연산과 최종 연산의 차이점은 무엇이며, 언제 어떻게 사용해야 하나요?
- 중간 연산 (Intermediate Operations): 중간 연산은 스트림의 요소에 대한 변환 및 필터링을 수행하는 연산입니다. 이러한 연산은 스트림을 수정하지 않고 새로운 스트림을 반환합니다. 예를 들어,
filter(),map(),distinct()등이 중간 연산입니다. - 최종 연산 (Terminal Operations): 최종 연산은 스트림의 요소를 소비하거나 결과를 생성하는 연산입니다. 최종 연산을 사용하면 스트림이 닫히고 더 이상 스트림을 사용할 수 없게 됩니다. 예를 들어,
collect(),forEach(),count()등이 최종 연산입니다.
중간 연산과 최종 연산의 차이는 중간 연산은 스트림 파이프라인을 구성할 수 있지만 결과를 생성하지 않으며, 최종 연산은 스트림을 소비하고 결과를 생성합니다. 따라서 중간 연산으로 필터링 및 매핑을 수행한 후 최종 연산으로 결과를 얻습니다.