스트림이란?
- 스트림은 컬렉션이나 배열과 같은 데이터를 표준화된 방법으로 다루기 위한 것이다.
- 데이터를 스트림으로 변환하여 여러번의 중간 연산을 하고, 최종 연산을 통해 다룰 수 있다.
- 스트림의 동작 순서는 다음과 같다.
- 스트림 생성
- 중간 연산(반복 가능)
- 최종 연산
list.stream() // 스트림으로 만들고 -> 1번 과정
.distinct() // 중복을 제거하고, -> 2번 과정
.limit(2) // 일정 개수로 제한하고, -> 2번 과정
.sorted() // 오름차순 정렬하고, -> 2번 과정
.forEach(System.out::println) //각각의 값을 출력한다. -> 3번 과정
이 때 중간 연산의 경우 반복이 가능하다.
📚특징
- 스트림은 일회성이다. 재사용이 필요하면 .stream()을 통해 다시 생성해줘야 한다.
- 컬렉션이 아니다.
- 최종 연산 전까지 중간 연산이 수행되지 않는다. 즉, 지연 연산이다.
- 병렬 처리에 용이하다.
- 기본형 스트림으로 IntStream, LongStream, DoubleStream 등이 있다.
- Stream<Integer>와 같은 타입도 있지만, IntStream을 사용하면 .sum(), .average() 등과 같은 유용한 메서드를 제공한다.
스트림 사용하기
위에서 정리했듯이 스트림은 3가지 순서로 사용할 수 있는데,
- 스트림 생성
- 중간 연산
- 최종 연산
을 하나하나 정리해보자.
스트림 생성
- Collection 의 경우 .stream()을 이용해서 손쉽게 스트림으로 변환할 수 있다.
Stream<Integer> stream = list.stream()
- 객체 배열로부터 스트림을 생성하는 방법은 다음과 같다.
Stream.of("a", "b", "c");
Stream.of(new String[]{"a", "b", "c"});
Arrays.stream(new String[]{"a", "b", "c"});
Arrays.stream(new String[]{"a", "b", "c"}, startIndex, EndIndex+1);
중간 연산
- 중간 연산으로 쓰이는 메서드는 다음과 같다.
.distinct() //중복 제거
.filter(Predicate<T> predicate) //조건에 안 맞는 요소는 제외
.limit(long maxSize) //maxSize 이후의 요소는 잘래냄
.skip(long n) //앞에서부터 n개 건너뛰기
.sorted() // 정렬기능, 디폴트는 오름차순
.sorted(Comparator<T> comparator) //조건에 맞게 요소 정렬. 추가 정렬 기준을 제공할 때는 thenComparing()사용
//스트림의 요소를 변환할 때 사용하며, 람다식을 이용하여 활용할 수 있다. ex) map(File::getName), map(s->s.subString(3))
.map(Function<T> mapper)
//요소에 작업수행. 보통 중간 작업결과 확인으로 사용. peek(s->System.out.println(s))
.peek(Consumer<T> action)
//스트림의 스트림을 스트림으로 변환
//ex) Stream<String> strStrm=strArrStrm.flatMap(Arrays::stream)
.flatMap()
최종 연산
void forEach(Consumer<? super T> action) //각 요소에 지정된 작업 수행
void forEachOrdered(Consumer<? super T> action) //병렬 스트림의 경우 순서를 유지하며 수행
long count() //스트림의 요소 개수 반환
Optional<T> max(Comparator<? super T> comparator) //스트림의 최대값 반환
Optional<T> min(Comparator<? super T> comparator) //스트림의 최소값 반환
Optional<T> findAny() //아무거나 하나 반환. 벙렬 스트림에 사용
Optional<T> findFirst() //첫 번째 요소 반환. 순차 스트림에 사용
boolean allMatch(Predicate<T> p) //모든 조건을 만족?
boolean anyMatch(Predicate<T> p) //조건을 하나라도 만족?
boolean noneMatch(Predicate<T> p) //모든 조건을 만족하지 않음?
Object[] toArray() //모든 요소를 배열로 반환
A[] toArray(IntFunction<A[]> generator) //특정 타입의 배열로 반환
//스트림의 요소를 하나씩 줄여가면서 계산
//아래에서 자세히 보자
Optional<T> reduce(BinaryOperator<T> accumulator)
//데이터를 변형 등의 처리를 하고 원하는 자료형으로 변환해 준다.
collect( ~ )
활용
.map()
람다를 이용하여 새로운 스트림으로 변환 할 수 있다.
ex) Person 에서 getName() 메서드를 이용해 이름들의 새로운 스트림으로 만들기
ex) String 타입의 요소를 특정 문자열을 잘라서 새로운 스트림으로 만들기
list.stream().map(Person::getName)
list.stream().map(s -> s.subString(3))
.filter()
필터로 원하는 값만을 얻어올 수 있다.
람다식의 리턴값은 boolean이며, true일 경우에만 다음 단계로 진행된다.
list.stream()
.filter(c -> c. getName().startWith("전"))
.forEach(c -> System.out.println(c.getId));
.limit(2)
- 개수를 제한하여 새로운 스트림을 생성한다.
. skip(2)
- 앞에서 2개를 제외한 나머지를 스트림으로 생성한다.
Stream.iterate(10, i->i+1)
.skip(10) //
.limit(10)
.forEach(System.out::println)
anyMatch(), allMatch(), nonMatch()
특정 문자열이 있는지 확인한다.
boolean result = Classes.stream()
.anyMatch(b->b.getTitle().contains("k"));
findFirst(), findAny()
- findFirst()는 stream에서 가장 앞에 있는 요소를 반환한다.
- findAny()는 가장 먼저 찾은 요소를 반환한다. (맨 뒤에 있는 요소가 반환될 수도 있다.)
reduce()
- 스트림의 요소를 하나씩 줄여가며 누적 연산을 수행한다.
- reduce(초기값, (누적 변수, 요소) → 수행문)
Integer result = Stream.of(1,2,3,4,5,6,7,8,9,10)
.reduce((total, y) -> total + y);
//초기값을 정할 경우
Integer result = Stream.of(1,2,3,4,5,6,7,8,9,10)
.reduce(10,(total,n) -> total +n);
collect()
- 스트림의 요소를 자료형으로 바꿀 때 사용한다.
list.stream().collect(Collectors.toSet());
list.stream().collect(Collectors.toList());
list.stream().collect(Collectors.joining());
list.stream().collect(Collectors.joining(", "));'📙Language > ☕Java' 카테고리의 다른 글
| [Java] url 변수 동적으로 받도록 개선하기 (0) | 2023.05.18 |
|---|---|
| [트러블 슈팅] url 패턴이 같을 경우에 Controller 메서드 구별하기 (0) | 2023.05.17 |
| [JDBC] 동적으로 파라미터 바인딩 하기 (0) | 2023.04.26 |
| [JDBC] Connection과 PreparedStatement, 그리고 ResultSet (0) | 2023.04.24 |
| [Java] Jackson Databind 이용하기 (0) | 2023.03.02 |