모던 자바인 액션 ch4 - 스트림 소개

김진욱·2022년 9월 15일
0

java

목록 보기
3/13
post-thumbnail

스트림

스트림이란 무엇인가?

스트림이란 '데이터 처리 연산을 지원하도록 소스에서 추출된 연속된 요소'로 정의할 수 있다.

스트림은 자바 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());

스트림의 특징

  1. 람다식으로 사용한다.

    위의 java8의 코드를 보면 메서드 참조와 람다식을 사용하였다. 스트림에서는 람다를 많이 활용한다.

  2. 스트림은 작업을 내부 반복으로 처리한다.

    스트림을 이용하면 내부 반복을 메서드 내부에 숨길 수 있다.

  3. 스트림의 연산에는 중간 연산최종 연산이 존재한다.

    중간 연산은 연산 결과를 스트림으로 반환하기 때문에 중간 연산을 연속해서 연결할 수 있다.

    최종 연산은 스트림의 요소를 소모하면서 연산을 수행하므로 단 한번만 연산이 가능하다.

  4. 병렬화
    스트림은 데이터를 다룰 때 병렬 처리가 쉽다. 병렬 스트림은 내부적으로 fork&join 프레임웍을 이용해서 자동적으로 연산을 병렬로 수행한다. parallel()이라는 메서드를 호출해 병렬로 연산을 실행하면 된다.

외부 반복과 내부 반복

  • 사용자가 직접 요소를 반복하는 것을 외부 반복(external iteration), 스트림은 반복을 알아서 처리하고 결과 스트림값을 어딘가에 저장해주는 내부 반복(internal iteration)을 사용한다.
  • 외부반복
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)
스트림의 요소를 수집한다. 주로 요소를 그룹화하거나 분할한 결과를 컬렉션에 담아 반환하는데 사용된다.

0개의 댓글

관련 채용 정보