스트림
스트림이란 '데이터 처리 연산을 지원하도록 소스에서 추출된 연속된 요소'로 정의할 수 있다.
스트림은 자바 8 API에 새로 추가된 기능이다. 스트림을 이용하면 배열이나 컬렉션뿐만 아니라 파일에 저장된 데이터도 모두 같은 방식으로 다룰 수 있다.
java7
List<Dish> lowCaloricDishes = new ArrayList<>();
for (Dish dish : menu) {
if (dish.getCalories() < 400) {
lowCaloricDishes.add(dish);
}
}
Collections.sort(lowCaloricDishes, new Comparator<Dish>() {
@Override
public int compare(Dish dish1, Dish dish2) {
return Integer.compare(dish1.getCalories(), dish2.getCalories());
}
});
List<String> lowCaloricDishesName = new ArrayList<>();
for (Dish dish : lowCaloricDishes) {
lowCaloricDishesName.add(dish.getName());
}
Java8
List<String> lowCaloricDishesName =
menu.stream()
.filter(dish -> dish.getCalories() < 400)
.sorted(Comparator.comparing(Dish::getCalories))
.map(Dish::getName)
.collect(Collectors.toList());
스트림의 특징
람다식으로 사용한다.
위의 java8의 코드를 보면 메서드 참조와 람다식을 사용하였다. 스트림에서는 람다를 많이 활용한다.
스트림은 작업을 내부 반복으로 처리한다.
스트림을 이용하면 내부 반복을 메서드 내부에 숨길 수 있다.
스트림의 연산에는 중간 연산과 최종 연산이 존재한다.
중간 연산은 연산 결과를 스트림으로 반환하기 때문에 중간 연산을 연속해서 연결할 수 있다.
최종 연산은 스트림의 요소를 소모하면서 연산을 수행하므로 단 한번만 연산이 가능하다.
병렬화
스트림은 데이터를 다룰 때 병렬 처리가 쉽다. 병렬 스트림은 내부적으로 fork&join 프레임웍을 이용해서 자동적으로 연산을 병렬로 수행한다. parallel()
이라는 메서드를 호출해 병렬로 연산을 실행하면 된다.
List<String> names = new ArrayList<>();
for (Dish dish : menu) {
names.add(dish.getName());
}
List<String> names = menu.stream()
.map(Dish::getName)
.collect(Collectors.toList());
내부 반복을 사용하면 작업을 투명하게 병렬적으로 처리하거나 최적화된 다양한 순서로 처리가 가능하다. 외부 반복에서는 병렬성을 스스로 관리(synchronized 사용)해야 한다.
중간연산은 연산결과를 스트림으로 반환하기 때문에 중간 연산을 연속해서 연결할 수 있다. 중간 연산의 중요한 특징은 단말 연산(최종 연산)을 스트림 파이프라인에 실행하기 전까지는 아무 연산도 수행하지 않는다는 것이다. 최종 연산이 수행되어야 비로소 스트림의 요소들이 중간 연산을 거쳐 최종 연산에서 소모된다.
중간 연산 | 설명 |
---|---|
Stream distinct() | 중복을제거 |
Stream filter(Predicate predicate) | 조건에 안 맞는 요소 제외 |
Stream limit(long maxSize) | 스트림의 일부를 잘라낸다 |
Stream skip(long n) | 스트림의 일부를 건너뛴다 |
Stream peek(Consumer action) | 스트림의 요소에 작업수행 |
Stream sorted() Stream sorted(Comprator comparator) | 스트림의 요소를 정렬한다 |
Stream map(Function<T,R> mapper) DoubleStream mapToDouble(ToDoubleFunction mapper) IntStream mapToInt(ToIntFunction mapper) LongStream mapToLong(ToLongFunction mapper) Stream flatMap(Function<T, Stream> mapper) DoubleStream flatMapToDouble(Function<T, DoubleStream> m) IntStream flatMapToInt(Function<T, IntStream> m) LongStream flatMapToLong(Function<T, LongStream> m) | 스트림의 요소를 변환한다. |
최종연산은 스트림 파이프라인에 결과를 도출한다. 최종연산은 스트림의 요소를 소모하면서 연산을 수행하므로 단 한번만 연산이 가능하다.
최종 연산 | 설명 |
---|---|
void forEach(Consumer<? super T> action) void forEachOrdered(Consumer<? super T> action) | 각 요소에 지정된 작업 수행 |
long count() | 스트림의 요소의 개수 반환 |
Optional max(Comparator<? super T> comprator) Optional min(Comparator<? super T>) comprator) | 스트림의 최대값/최소값을 반환 |
Optional findAny() //아무거나 하나 Optional findFirst() //첫 번째 요소 | 스트림의 요소 하나를 반환 |
boolean allMatch(Predicate p) //모두 만족하는지 boolean anyMatch(Predicate p) //하나라도 만족하는지 boolean noneMatch(Predicate<> p) //모두 만족하지 않는지 | 주어진 조건을 모든 요소가 만족시키는지, 만족시키지 않는지 확인 |
Object[] toArray() A[] toArray(IntFunction<A[]> generator) | 스트림의 모든 요소를 배열로 반환 |
Optional reduce(BinaryOperator accumulator) T reduce(T identity, BinaryOperator accumulator) U reduce(U identity, BiFunction<U, T, U> accumulator, BinaryOperator combiner) | 스트림의 요소를 하나씩 줄여가면서(리듀싱) 계산한다. |
R collect(Collector<T, A, R> collector) R collect(Supplier supplier, BiConsumer<R, T> accumulator, BiConsumer<R, R> combiner) | 스트림의 요소를 수집한다. 주로 요소를 그룹화하거나 분할한 결과를 컬렉션에 담아 반환하는데 사용된다. |