JAVA Stream API
JAVA stream 과 stream API는 다릅니다.
java stream 은 java 에서 다루는, 입출력 흐름입니다.
우리가 코드에서 stream으로 사용하는 것이, Stream API입니다.
// 컬렉션에서 스트림 생성
Stream<Integer> stream = list.stream();
Stream API란, 컬렉션 또는 배열 인스턴스에 저장된 데이터를 가지고, 중간연산과 최종연산을 진행하기 좋은 구조로 배치시키는 복사본이라고 할 수 있습니다.
Stream API 특징
- 스트림은 외부 반복을 통해 작업하는 컬렉션과 다르게, 내부 반복을 통해 작업을 수행합니다.
- 스트림은 재사용이 가능한 컬렉션과 다르게 단 1번만 사용할 수 있습니다.
- 스트림은 원본 데이터를 변경하지 않고, 복사해서 사용됩니다.
- 스트림 연산은, 필터-맵(filter-map) 기반의 API를 사용하여 지연(Lazy) 연산을 통해 성능을 최적합니다.
- 스트림은 parallelStream() 메소드를 통한 병렬처리를 지원합니다.
Stream API 사용 예시
1. Stream API 생성 (feat stream.of)
(1) List to Stream
-> Collection 인터페이스에 정의되어있는, Stream() 메소드를 사용합니다.
-> 배열 등, 여러 데이터를 가지는 집합들에 의해 사용가능합니다.
public class prog {
public static void main(String[] args){
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(4);
list.add(2);
list.add(3);
list.add(1);
// 컬렉션에서 스트림 생성
Stream<Integer> stream = list.stream();
// forEach() 메소드를 이용한 스트림 요소의 순차 접근
stream.forEach(System.out::println);
}
}
(2) Steam.of()
-> Stream.of() 메소드를 이용해 Stream 객체를 바로 생성할 수 있습니다.
// 가변 매개변수에서 스트림 생성
Stream<Double> stream = Stream.of(4.2, 2.5, 3.1, 1.9);
stream.forEach(System.out::println);
2. Stream API 중개 연산 (Stream to Stream)
- 스트림을 전달받아, 연산 후 다시 스트림으로 반환하는 연산입니다.
- 스트림의 중개 연산은 필터-맵(filter-map) 기반의 API를 사용함으로 지연(lazy) 연산을 통해 성능을 최적화할 수 있습니다.
스트림 API에서 사용할 수 있는 대표적인 중개 연산과 그에 따른 메소드는 다음과 같습니다.
- 스트림 필터링 : filter(), distinct()
- 스트림 변환 : map(), flatMap()
- 스트림 제한 : limit(), skip()
- 스트림 정렬 : sorted()
- 스트림 연산 결과 확인 : peek()
[Stream 중개 연산 예시]
final List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
System.out.println(
list.stream()
.filter(i -> i<6)
.filter(i -> i%2==0)
.map(i -> i*10)
.collect(Collectors.toList())
);
//결과
[20, 40]
출처: https://dororongju.tistory.com/137 [웹 개발 메모장]
[Stream 중개 연산 메소드]
메소드 | 설명 |
Stream<T> filter(Predicate<? super T> predicate) | 해당 스트림에서 주어진 조건(predicate)에 맞는 요소만으로 구성된 새로운 스트림을 반환함. |
<R> Stream<R> map(Functoin<? super T, ? extends R> mapper) | 해당 스트림의 요소들을 주어진 함수에 인수로 전달하여, 그 반환값으로 이루어진 새로운 스트림을 반환함. |
<R> Stream<R> flatMap(Functoin<? super T, ? extends Stream<? extends R>> mapper) | 해당 스트림의 요소가 배열일 경우, 배열의 각 요소를 주어진 함수에 인수로 전달하여, 그 반환값으로 이루어진 새로운 스트림을 반환함. |
Stream<T> distinct() | 해당 스트림에서 중복된 요소가 제거된 새로운 스트림을 반환함. 내부적으로 Object 클래스의 equals() 메소드를 사용함. |
Stream<T> limit(long maxSize) | 해당 스트림에서 전달된 개수만큼의 요소만으로 이루어진 새로운 스트림을 반환함. |
Stream<T> peek(Consumer<? super T> action) | 결과 스트림으로부터 각 요소를 소모하여 추가로 명시된 동작(action)을 수행하여 새로운 스트림을 생성하여 반환함. |
Stream<T> skip(long n) | 해당 스트림의 첫 번째 요소부터 전달된 개수만큼의 요소를 제외한 나머지 요소만으로 이루어진 새로운 스트림을 반환함. |
Stream<T> sorted() Stream<T> sorted(Comparator<? super T> comparator) |
해당 스트림을 주어진 비교자(comparator)를 이용하여 정렬함. 비교자를 전달하지 않으면 영문사전 순(natural order)으로 정렬함. |
3. 스트림 최종연산
중개연산되어 반환된 스트림은, 마지막으로 최종연산을 수행하여 각 요소를 소모해 결과를 도출할 수 있습니다.
스트림 API에서 사용할 수 있는 대표적인 최종 연산과 그에 따른 메소드는 다음과 같습니다.
- 요소의 출력 : forEach()
- 요소의 소모 : reduce()
- 요소의 검색 : findFirst(), findAny()
- 요소의 검사 : anyMatch(), allMatch(), noneMatch()
- 요소의 통계 : count(), min(), max()
- 요소의 연산 : sum(), average()
- 요소의 수집 : collect()
[사용 예시]
1. Stream forEach
Stream<String> stream = Stream.of("넷", "둘", "셋", "하나");
stream.forEach(System.out::println);
/*실행 결과
넷
둘
셋
하나
*/
2. stream anymatch() / stream allmatch()
해당 스트림의 요소 중에서 특정 조건을 만족하는 요소가 있는지, 아니면 모두 만족하거나 모두 만족하지 않는지를 다음 메소드를 사용하여 확인할 수 있습니다.
- anyMatch() : 해당 스트림의 일부 요소가 특정 조건을 만족할 경우에 true를 반환함.
- allMatch() : 해당 스트림의 모든 요소가 특정 조건을 만족할 경우에 true를 반환함.
IntStream stream1 = IntStream.of(30, 90, 70, 10);
IntStream stream2 = IntStream.of(30, 90, 70, 10);
System.out.println(stream1.anyMatch(n -> n > 80));
System.out.println(stream2.allMatch(n -> n > 80));
/*실행 결과
true
false*/
3. 요소의 통계 : count(), min(), max() / 요소 연산 : sum(), average()
IntStream stream1 = IntStream.of(30, 90, 70, 10);
IntStream stream2 = IntStream.of(30, 90, 70, 10);
System.out.println(stream1.count());
System.out.println(stream2.max().getAsInt());
/*실행 결과
4
90*/
4. 요소 수집 (List, Collector 반환)
스트림 요소의 수집 용도별 사용할 수 있는 Collectors 메소드는 다음과 같습니다.
- 스트림을 배열이나 컬렉션으로 변환 : toArray(), toCollection(), toList(), toSet(), toMap()
- 요소의 통계와 연산 메소드와 같은 동작을 수행 : counting(), maxBy(), minBy(), summingInt(), averagingInt() 등
- 요소의 소모와 같은 동작을 수행 : reducing(), joining()
- 요소의 그룹화와 분할 : groupingBy(), partitioningBy()
Stream<String> stream = Stream.of("넷", "둘", "하나", "셋");
List<String> list = stream.collect(Collectors.toList());
Iterator<String> iter = list.iterator();
while(iter.hasNext()) {
System.out.print(iter.next() + " ");
}
//넷 둘 하나 셋
대표적인 최종 연산 메소드
메소드 | 설명 |
void forEach(Consumer<? super T> action) | 스트림의 각 요소에 대해 해당 요소를 소모하여 명시된 동작을 수행함. |
Optional<T> reduce(BinaryOperator<T> accumulator) T reduce(T identity, BinaryOperator<T> accumulator) |
처음 두 요소를 가지고 연산을 수행한 뒤, 그 결과와 다음 요소를 가지고 또다시 연산을 수행함. 이런 식으로 해당 스트림의 모든 요소를 소모하여 연산을 수행하고, 그 결과를 반환함. |
Optional<T> findFirst() Optional<T> findAny() |
해당 스트림에서 첫 번째 요소를 참조하는 Optional 객체를 반환함. (findAny() 메소드는 병렬 스트림일 때 사용함) |
boolean anyMatch(Predicate<? super T> predicate) | 해당 스트림의 일부 요소가 특정 조건을 만족할 경우에 true를 반환함. |
boolean allMatch(Predicate<? super T> predicate) | 해당 스트림의 모든 요소가 특정 조건을 만족할 경우에 true를 반환함. |
boolean noneMatch(Predicate<? super T> predicate) | 해당 스트림의 모든 요소가 특정 조건을 만족하지 않을 경우에 true를 반환함. |
long count() | 해당 스트림의 요소의 개수를 반환함. |
Optional<T> max(Comparator<? super T> comparator) | 해당 스트림의 요소 중에서 가장 큰 값을 가지는 요소를 참조하는 Optional 객체를 반환함. |
Optional<T> min(Comparator<? super T> comparator) | 해당 스트림의 요소 중에서 가장 작은 값을 가지는 요소를 참조하는 Optional 객체를 반환함. |
T sum() | 해당 스트림의 모든 요소에 대해 합을 구하여 반환함. |
Optional<T> average() | 해당 스트림의 모든 요소에 대해 평균값을 구하여 반환함. |
<R,A> R collect(Collector<? super T,A,R> collector) | 인수로 전달되는 Collectors 객체에 구현된 방법대로 스트림의 요소를 수집함. |
4. Stream 통계 연산
https://madplay.github.io/post/java-streams-terminal-operations
*참고
TCP School.- Stream API
'Java > Java 문법' 카테고리의 다른 글
[Java] 스트림에서 오토박싱 (박싱, 언방식)이 일어나는 이유 (0) | 2022.09.16 |
---|---|
[JAVA] record 불변 객체 타입 (feat Lombok @Value) (0) | 2022.06.02 |
private final VS private static final 왜 쓸까 (0) | 2022.03.10 |
ArrayList<Dto> Map value 값으로 정렬 (0) | 2022.01.16 |
[JAVA] 자바 문자열 다루기 (0) | 2022.01.07 |