Stream(1)
- 람다를 활용하여 데이터 처리 연산을 지원하도록 컬렉션, 배열, I/O 자원 등에 대해 저장되어 있는 요소들을 추출하여 반복적인 처리를 가능하게 하는 기능
Collection vs Stream
- 스트림은 컬렉션과 마찬가지로 연속된 값 집합의 인터페이스를 제공한다.
① Collection
- 컬렉션은 현재 자료구조가 포함하는 모든 값을 메모리에 저장한 후 계산이 가능하다.
Ex) 다운로드된 동영상 - 컬렉션은 외부 반복(ex.for-each문 등)을 통해 반복을 제어한다.
② Stream
- 스트림은 게으른 연산(Lazy)을 진행하여 요청할 때만 값을 계산한다.
Ex) 전체 중 일정 구간만 제공되는 스트리밍 동영상 - 스트림은 한 번 사용 후 소멸되며 재사용도 불가능하다.
- 스트림은 내부 반복을 사용한다.
- 내부에서 자동으로 반복을 처리하므로 반복자를 사용할 필요가 없다.
- 동기화 처리 없이 병렬성 처리가 가능하다.
특징
- 원본 데이터를 변경하지 않는다.
- 데이터를 읽기만 할 뿐 변경하지 않는다.
- 필요한 경우 연산 결과를 컬렉션이나 배열에 담아 반환할 수 있다. - 일회용이다.
- 요소들을 모두 읽은 후 객체가 닫혀서 다시 사용할 수 없으며 필요한 경우 스트림을 다시 생성해야 한다. - 작업을 내부 반복으로 처리한다.
- 병렬처리가 가능하다.
- 장점
- Stream API에서 제공되는 함수들을 이용하여 코드가 간결해지고 가독성이 좋아진다. - 단점
- 단순 반복문(for-each)의 경우에는 for문 또는 컬렉션의 forEach 함수를 사용하는 것이 속도가 빠르다.
연산
- 중간 연산
- 단말 연산을 스트림 파이프라인에 실행하기 전까지 아무 연산도 수행하지 않는다.
- 리턴값이 없다.
Ex) filter, map, limit, sorted, distinct - 최종 연산
- 스트림 파이프라인에서 결과를 도출한다.
Ex) forEach, collect, count - 게으른 연산(Lazy)
- 스트림은 filter-map 기반의 API를 사용하여 지연 연산을하여 성능을 최적화한다.
- 이로 인해 최종 연산이 없으면 중간 연산이 실행되지 않는다.
예제
① 스트림 API는 다양한 데이터 소스에서 생성할 수 있다.
// 베열 스트림
String[] stringArr = new String[]{"hello", "world", "!"};
Stream<String> streamArrString = Arrays.stream(stringArr);
Stream<String> streamArrStringPart = Arrays.stream(stringArr, 1, 3);
// 컬렉션 스트림
List<String> listString = new ArrayList<>();
Stream<String> streamListString = listString.stream();
Stream<String> parallelStreamListString = listString.parallelStream(); // 병렬 처리 스트림
// 비어있는 스트림
// 메소드 이용 스트림
Stream<String> streamBuilder = Stream.<String>builder().add("A").add("B").build();
Stream<String> streamGenerate = Stream.generate(() -> "wow").limit(5);
Stream<Integer> streamIterate = Stream.iterate(50, n -> n + 5).limit(5);
List<String> streamBuilderList = streamBuilder.collect(Collectors.toList());
// 기본 타입형 스트림
IntStream intStream = IntStream.range(1, 6);
LongStream longStream = LongStream.rangeClosed(1, 5);
Stream<Integer> boxedStreamInt = IntStream.range(1, 6).boxed();
List<Integer> intStreamList = intStream.boxed().collect(Collectors.toList());
List<Integer> boxedStreamIntList = boxedStreamInt.collect(Collectors.toList());
// 난수 스트림
DoubleStream doubleStream = new Random().doubles(3);
List<Double> doubleStreamList = doubleStream.boxed().collect(Collectors.toList());
// 문자열 스트림
IntStream charStream = "Hello".chars();
Stream<String> stringStream = Pattern.compile(", ").splitAsStream("A, B, C");
List<Integer> charStreamList = charStream.boxed().collect(Collectors.toList());
List<String> stringStreamList = stringStream.collect(Collectors.toList());
// 파일 스트림
Stream<String> lineStream = Files.lines(Paths.get("D:/test.txt"), Charset.forName("UTF-8"));
List<String> lineStreamList = lineStream.collect(Collectors.toList());
// 병렬 스트림
Stream<String> parallelStringStream = Stream.<String>builder().add("A").add("B").build().parallel();
List<Integer> listInteger = new ArrayList<>();
Stream<Integer> parallelStreamlistInteger = listInteger.parallelStream();
IntStream parallelIntStream = IntStream.range(1, 6).parallel();
IntStream sequentialIntStream = parallelIntStream.sequential(); // 시퀀셜 모드로 변경
// 스트림 연결
Stream<String> concatStream = Stream.concat(stringStream, lineStream);
List<String> concatStreamList = concatStream.collect(Collectors.toList());
System.out.println(concatStreamList);
② 중개 연산
- 스트림을 전달받아 스트림으로 반환하므로 연속으로 사용할 수 있다.
- Stream 필터링 : filter(), distinct()
- Stream 변환 : map(), flatMap()
- Stream 제한 : limit(), skip()
- Stream 정렬 : sorted()
- Stream 연산 결과 확인 : peek()
List<String> cars = Arrays.asList("Jeep", "BMW", "Kia", "Hyundai", "Bentley");
// Filtering
Stream<String> filteredCars = cars.stream().filter(car -> car.startsWith("B"));
List<String> filteredCarsList = filteredCars.collect(Collectors.toList());
// Mapping
Stream<String> mappedStream = cars.stream().map(car -> car.toUpperCase());
List<String> mappedCarsList = mappedStream.collect(Collectors.toList());
List<List<String>> flatStream = Arrays.asList(Arrays.asList("A"), Arrays.asList("B"));
List<String> flatList = flatStream.stream().flatMap(Collection::stream).collect(Collectors.toList());
// Sorting
Stream<String> sortedStream = cars.stream().sorted(); // 오름차순
List<String> sortedCarsList = sortedStream.collect(Collectors.toList());
Stream<String> sortedReverseStream = cars.stream().sorted(Comparator.reverseOrder()); // 내림차순
List<String> sortedReverseCarsList = sortedReverseStream.collect(Collectors.toList());
Stream<String> sortedLengthStream = cars.stream().sorted(Comparator.comparingInt(String::length)); // 문자열 개수 오름차순
List<String> sortedLengthCarsList = sortedLengthStream.collect(Collectors.toList());
// Iterating
int sum = IntStream.of(1, 2, 3, 4, 5).peek(System.out::println).sum();
③ 최종 연산
- 앞서 중개 연산을 통해 만들어진 스트림에 있는 요소들에 대해 이들을 소모하여 결과를 표시한다.
즉, 지연(Lazy)되었던 모든 중개 연산들이 최종 연산 시에 모두 수행된다.
따라서 최종 연산 시 모든 요소를 소모한 스트림은 더 이상 사용 불가능하다.
- 요소의 출력 : forEach()
- 요소의 소모 : reduce()
- 요소의 검색 : findFirst(), findAny()
- 요소의 검사 : anyMatch(), allMatch(), noneMatch()
- 요소의 통계 : count(), min(), max()
- 요소의 연산 : sum(), average()
- 요소의 수집 : collect()
// Calculating
int count = (int) cars.stream().count();
// Reduction
Integer reducedParams = Stream.of(1, 2, 3, 4, 5).reduce(10, Integer::sum, (a, b) -> { System.out.println("called"); return a + b; });
// Collecting
List<String> collectingList = cars.stream().collect(Collectors.toList());
String joiningString = cars.stream().collect(Collectors.joining(", ", "[", "]"));
Double averageDouble = Stream.of(1, 2, 3, 4, 5).collect(Collectors.averagingInt(n -> n));
int sumDouble = Stream.of(1, 2, 3, 4, 5).collect(Collectors.summingInt(n -> n));
DoubleSummaryStatistics statistics = Stream.of(1, 2, 3, 4, 5).collect(Collectors.summarizingDouble(n -> n));
// Matching
boolean isExist = cars.stream().anyMatch(car -> car.startsWith("B"));
// Iterating
cars.stream().forEach(System.out::println);
▷ 출처
https://innovationm.co/concept-of-stream-api-java1-8/
https://velog.io/@mooh2jj/Java-stream-Collector-%EC%99%9C-%EC%93%B0%EB%8A%94-%EA%B1%B0%EC%95%BC
728x90
'Java' 카테고리의 다른 글
Spring Framework의 주요 특징 (1) | 2024.07.23 |
---|---|
Stream(2) (0) | 2024.07.19 |
[Spring] @RequestBody vs @RequestParam (0) | 2024.07.10 |
[Spring] @Controller VS @RestController (0) | 2024.07.09 |
재귀 알고리즘 (0) | 2024.07.04 |