Java
Programming Language
Backend
☕️[Java] Java Stream이란 무엇일까요?
-
Java Stream은 Java 8에서 도입된 데이터 처리 API로, 컬렉션(Collection), 배열(Array), 파일 등의 데이터 소스를 효율적으로 처리할 수 있게 해주는 기능입니다.
- Stream을 사용하면 데이터의 필터링, 변환, 정렬, 집계 등의 작업을 함수형 스타일로 간결하게 작성할 수 있습니다.
1️⃣ Stream의 주요 특징.
1️⃣ 선언형 프로그래밍 스타일.
- 기존의 반복문을 사용한 명령형(Imperative) 코드와 달리, Stream은 선언형(Declarative) 스타일을 사용하여 더 간결하고 읽기 쉬운 코드를 작성할 수 있게 합니다.
2️⃣ 함수형 프로그래밍.
- Stream은 함수형 프로그래밍을 지원하여, 람다 표현식(Lambda Expression)과 메서드 참조(Method Reference)를 사용하여 간결한 코드를 작성할 수 있습니다.
3️⃣ 데이터의 흐름.
- Stream은 데이터 소스로부터 데이터 흐름을 처리하며, 데이터를 직접 저장하지 않습니다.
- 즉, 컬렉션이나 배열에 데이터를 저장하는 것이 아니라, 데이터를 처리하는 역속적인 작업을 제공합니다.
4️⃣ 지연 연산(Lazy Evaluation)
- Stream은 지연 연산(Lazy Evaluation)을 사용하여 필요한 경우에만 데이터를 처리합니다.
- 중간 연산이 지연되어 최종 연산이 호출될 때만 실제로 데이터 처리가 이루어집니다.
5️⃣ 병렬 처리.
- Stream API는 쉽게 병렬 처리를 수행할 수 있는 메서드를 제공하여, 멀티코어 시스템에서 성능을 최적화할 수 있습니다.
-
parallelStream()
메서드를 사용하면 병렬 처리를 활성화할 수 있습니다.
2️⃣ Stream의 기본 구성.
- Stream은 크게 중간 연산과 최종 연산으로 구성됩니다.
👉 중간 연산.
- 필터링, 변환, 정렬 등과 같이 데이터의 흐름을 처리하는 작업을 수행하지만, 최종 연산이 호출되기 전까지는 실행되지 않습니다.(예:
filter
, map
, sorted
)
👉 최종 연산.
- 스트림의 데이터를 결과로 수집하거나 출력하는 연산으로, 최종 연산이 호출되면 스트림이 처리되고 종료됩니다.(예:
collect
, forEach
, reduce
)
3️⃣ Stream 사용 예시.
1️⃣ 컬렉션에서 Stream 사용.
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class StreamExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("Jhon", "Jane", "Jack", "Doe");
// 필터링과 변환
List<String> filteredNames = names.stream()
.filter(name -> name.startWith("J")) // "J"로 시작하는 이름만 필터링
.map(String::toUpperCase) // 대문자로 변환
.collect(Collectors.toList()); // 결과를 리스트로 수집
System.out.println(filteredNames) // 출력: [JHON, JANE, JACK]
}
}
4️⃣ Stream의 기본 연산.
👉 중간 연산.
1️⃣ filter(Predicate)
- 조건에 맞는 요소만 걸러냅니다.
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> evenNumbers = numbers.stream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList()); // [2, 4]
2️⃣ map(Function)
- 각 요소를 변환합니다.(예: 문자열을 대문자로 변환, 객체의 특정 필드를 추출)
List<String> words = Arrays.asList("apple", "banana", "cherry");
List<Integer> lengths = words.stream()
.map(String::length)
.collect(Collectors.toList()); // [5, 6, 7]
3️⃣ sorted()
- 요소를 정렬합니다. 기본적으로 오름차순 정렬하며, 커스텀 Comparator를 사용할 수도 있습니다.
List<Integer> sortedNumbers = numbers.stream()
.sorted
.collect(Collectors.toList()); // [1, 2, 3, 4, 5]
4️⃣ distinct()
- 중복된 요소를 제거합니다.
List<Integer> distinctNumbers = Arrays.asList(1, 2, 2, 3, 3, 3)
.stream()
.distinct()
.collect(Collectors.toList()); // [1, 2, 3]
👉 최종 연산.
1️⃣ collect(Collector)
- 스트림의 요소를 모아서 리스트, 집합 등의 컬렉션으로 변환합니다.
List<String> names = Arrays.asList("John", "Jane", "Jack");
List<String> upperNames = names.stream()
.map(String::toUpperCase)
.collect(Collectors.toList()); // [JOHN, JANE, JACK]
2️⃣ forEach(Consumer)
- 각 요소에 대해 지정된 작업을 수행합니다.
- 출력이나 로그 작업 등에 사용됩니다.
names.stream()
.forEach(System.out::println);
3️⃣ reduce(BinaryOperator)
- 스트림의 요소를 누적하여 하나의 결과로 만듭니다.
- 주로 합계, 곱, 문자열 연결 등에 사용됩니다.
int sum = Arrays.asList(1, 2, 3, 4, 5)
.stream()
.reduce(0, Integer::sum) // 15
4️⃣ count()
- 스트림의 요소 개수를 반환합니다.
long count = names.stream()
.filter(name -> name.startWith("J"))
.count(); // 3
5️⃣ 병렬 스트림
- Stream API는 병렬 처리를 쉽게 수행할 수 있도록 지원합니다.
-
paralleStream()
또는 parallel()
메서드를 사용하여 스트림을 병렬로 처리할 수 있습니다.
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
int sum = numbers.parallelStream()
.reduce(0, Integer::sum); // 병렬로 합 계산
- 병렬 스트림은 멀티 코어 시스템에서 성능을 최적화할 수 있지만, 병렬로 처리할 때는 데이터 간의 독립성이 보장되어야 합니다.
6️⃣ 요약.
- Java Stream은 데이터의 필터링, 변환. 정렬, 집계 등을 간결하고 선언적인 스타일로 작성할 수 있는 기능을 제공합니다.
- 중간 연산과 최종 연산을 조합하여 복잡한 데이터 처리를 간단하게 구현할 수 있으며, 병렬 처리를 통해 성능을 향상시킬 수도 있습니다.
- Stream API를 사용하면 기존의 반복문과 조건문을 대체할 수 있어, 코드의 가독성과 유지보수성이 크게 향상됩니다.