2023년 4월 2일
카테고리 : JAVA조회 : 542|1분 읽기
JAVA - Stream
스트림(Stream)은 병렬 또는 순차적으로 처리할 수 있는 요소 시퀀스입니다.
컬렉션, 배열, 파일, 난수 등 다양한 소스에서 생성할 수 있으며 map, reduce, filter, sort 등의 기능적 스타일 작업을 지원합니다. 스트림은 지연(Lazy)되어 필요할 때만 요소를 계산합니다.
⭐️ 스트림의 특징
- 데이터 저장 없이 처리: 원본 데이터를 변경하지 않습니다.
- 재사용 불가: 스트림 사용 후 가비지 컬렉션(GC) 대상이 됩니다.
- 단일 처리: 데이터를 한 번에 하나씩 처리합니다.
- 병렬 처리 지원: 여러 스레드를 활용한 병렬 처리가 가능합니다.
💡 스트림 vs 일반 메서드
스트림의 map과 컬렉션의 유사 메서드는 중요한 차이점이 있습니다.
- stream.map: 스트림의 중간 연산으로 스트림을 반환하며 지연되어 수행됩니다.
- 컬렉션의 메서드: 예를 들어 replaceAll은 컬렉션을 반환하고 즉시 수행됩니다.
java1List<String> list = Arrays.asList("a", "b", "c"); 2 3// 스트림의 map 4list.stream() 5 .map(String::toUpperCase) 6 .forEach(System.out::println); 7 8// 컬렉션의 replaceAll 9list.replaceAll(String::toUpperCase); 10System.out.println(list);
1️⃣ 스트림 생성 방법
-
컬렉션에서 생성java
1List<String> list = Arrays.asList("a", "b", "c"); 2Stream<String> stream = list.stream(); 3stream.forEach(System.out::println); -
배열에서 생성java
1int[] arr = {1, 2, 3, 4, 5}; 2IntStream intStream = Arrays.stream(arr); 3intStream.forEach(System.out::println); -
빌더 사용java
1Stream<String> builderStream = Stream.<String>builder() 2 .add("Apple") 3 .add("Banana") 4 .add("Melon") 5 .build(); 6builderStream.forEach(System.out::println); -
generate() 메소드java
1Stream<String> generateStream = Stream.generate(() -> "Hello") 2 .limit(5); 3generateStream.forEach(System.out::println); -
iterate() 메소드java
1Stream<Integer> iterateStream = Stream.iterate(100, n -> n + 10) 2 .limit(5); 3iterateStream.forEach(System.out::println); -
empty() 메소드java
1Stream<String> emptyStream = Stream.empty(); 2System.out.println(emptyStream.count()); // 0 -
기본 타입 스트림java
1IntStream intStream = IntStream.range(1, 10); 2intStream.forEach(System.out::println);
2️⃣ 스트림 연산
-
filterjava
1List<String> names = Arrays.asList("Jun", "James", "Chris", "Uni"); 2names.stream() 3 .filter(name -> name.startsWith("J")) 4 .forEach(System.out::println); // Jun, James -
mapjava
1List<String> fruits = Arrays.asList("apple", "banana", "melon", "grape"); 2fruits.stream() 3 .map(String::toUpperCase) 4 .forEach(System.out::println); // APPLE, BANANA, MELON, GRAPE -
sortedjava
1List<Integer> numbers = Arrays.asList(5, 3, 1, 4, 2); 2numbers.stream() 3 .sorted() 4 .forEach(System.out::println); // 1, 2, 3, 4, 5 -
집계 연산 (count, sum, average, min, max)java
1int[] scores = {80, 90, 100, 70, 85}; 2IntSummaryStatistics stats = Arrays.stream(scores).summaryStatistics(); 3System.out.println("개수: " + stats.getCount()); 4System.out.println("합계: " + stats.getSum()); 5System.out.println("평균: " + stats.getAverage()); 6System.out.println("최대: " + stats.getMax()); 7System.out.println("최소: " + stats.getMin()); -
매칭 연산 (anyMatch, allMatch, noneMatch)java
1List<String> colors = Arrays.asList("red", "blue", "green", "yellow"); 2boolean result1 = colors.stream().anyMatch(color -> color.equals("red")); // true 3boolean result2 = colors.stream().allMatch(color -> color.length() == 4); // false 4boolean result3 = colors.stream().noneMatch(color -> color.startsWith("p")); // true 5System.out.println(result1); // true 6System.out.println(result2); // false 7System.out.println(result3); // true -
reducejava
1List<String> animals = Arrays.asList("dog", "cat", "bird", "fish"); 2String result4 = animals.stream() 3 .reduce("", (a, b) -> a + b); 4System.out.println(result4); // dogcatbirdfish -
collectjava
1List<String> fruits = Arrays.asList("apple", "banana", "melon", "grape"); 2List<String> result5 = fruits.stream() 3 .filter(fruit -> fruit.length() == 5) 4 .collect(Collectors.toList()); 5result5.forEach(System.out::println); // apple, grape
⭐️ 병렬 처리 (Parallel Processing)
병렬 처리는 대용량 데이터 처리에 유용하며 스트림 API에서도 지원됩니다. parallel() 메소드를 호출하면 ForkJoin 프레임워크를 사용하여 여러 스레드가 작업을 수행합니다.
java1import java.util.Arrays; 2 3public class ParallelStreamExample { 4 public static void main(String[] args) { 5 int[] numbers = {1,2,3,4,5,6,7,8,9,10}; 6 7 long start = System.currentTimeMillis(); 8 9 long count = Arrays.stream(numbers) 10 .parallel() 11 .filter(n -> n % 2 == 0) 12 .count(); 13 14 long end = System.currentTimeMillis(); 15 System.out.println("짝수의 개수: " + count); 16 System.out.println("걸린 시간(ms): " + (end - start)); 17 } 18}
장점
- 성능 향상: 멀티 코어 CPU를 활용하여 처리 속도를 높입니다.
- 효율적 자원 사용: 여러 작업을 동시에 처리하여 자원 활용도를 높입니다.
단점
- 동기화 문제: 스레드 간 데이터 공유 시 동기화가 필요합니다.
- 오버헤드: 병렬 처리로 인한 스레드 관리 비용이 발생할 수 있습니다.
- 처리 순서: 순서가 중요한 작업에는 적합하지 않을 수 있습니다.
정리
스트림은 데이터 처리의 효율성과 가독성을 높입니다. 병렬 처리 시 동기화 문제와 오버헤드를 고려해야 합니다. 중간 연산과 최종 연산의 차이를 이해하고 상황에 맞게 스트림을 활용하는 것이 중요합니다.