48
Stream API 자바카페 김흥래

3. stream api

  • Upload
    -

  • View
    1.095

  • Download
    2

Embed Size (px)

Citation preview

Page 1: 3. stream api

Stream API

자바카페김흥래

Page 2: 3. stream api

스트림• 컬렉션은 자바에서 가장 많이 사용하는 기능이다 . (Collections Framework)• 대부분의 어플리케이션은 컬렉션을 만들고 컬렉션 데이터를 처리하는 과정을 반복한다 .• Java8 에서는 컬렉션 데이터를 처리하기 위한

Stream API 가 추가되었다 .

Page 3: 3. stream api

스트림• 스트림은 컬렉션 데이터를 처리하는 코드를 선언형으로 구현할 수 있다 .• 제어문 (for, while, if) 을 이용하여 컬렉션 데이터가 어떻게 동작을 해야 하는지 일일이 코딩 할 필요없이 ‘어떤 동작을 수행하라’는 형태의 선언만으로 컬렉션 데이터를 가공할 수 있다 .

• SQL 과 비슷한 형태이다 .– Select * from user where age > 10;– 위와 같이 단순한 선언문만으로 디스크의 정보를 가공하여 가져올 수 있다 .– 프로그래머가 직업 제어문을 이용하여 row 나 column 데이터를 어떻게 가공할 지 코딩하지 않는다 . – 연산 과정은 전적으로 DB Optimizer 에게 위임하고 결과에만 관심이 있다 .

Page 4: 3. stream api

스트림• Stream API 는 filter, sort, map, collect 같은 빌딩 블록 연산을 제공한다 .

• 여러 블록 연산을 연결하여 파이프라인을 구현하는 것이 가능하다 . (Di-vide & Conquer)

• 고수준의 블록 연산을 제공하여 특정 스레드 모델에 제한되지 않고 멀티코어 아키텍처를 투명하게 활용할 수 있다 .

• 병렬처리시 스레드와 락을 고민하지 않아도 된다 .

• 스트림이란 데이터 처리 연산을 지원하도록 소스에서 추출된 연속된 요소

Page 5: 3. stream api
Page 6: 3. stream api

스트림 vs 컬렉션• 컬렉션과 스트림 모두 연속된 요소 형식의 값을 저장하는 자료구조의 인터페이스를 제공한다 .

• 둘다 순서에 따라 순차적으로 요소에 접근한다 .

• 컬렉션과 스트림의 가장 큰 차이는 데이터를 언제 계산하느냐 이다 .– 컬렉션 : 요소를 접근하면서 계산식을 만날때마다 계산이 일어난다 .– 스트림 : 최종연산을 요청할 때만 계산한다 .

Page 7: 3. stream api

데이터 접근 측면• 컬렉션– 자료구조이므로 데이터에 접근 , 읽기 , 변경 , 저장 같은 연산이 주요 관심사이다 . ( 직접 데이터 핸들링 )– 데이터에 접근하는 방법을 직접 작성해야 한다 .

• 스트림– Filter, sorted, map 처럼 계산식 ( 람다 ) 을 표현하는 것이 주요 관심사이다 . ( 계산식을 JVM 으로 던진다 .)– 데이터에 접근하는 방법이 추상화 되어 있다 .

Page 8: 3. stream api

데이터 계산 측면• 컬렉션

– 작업을 위해서 Iterator 로 모든 요소를 순환해야 한다 .– 메모리에 모든 요소가 올라간다 . (OOM)– 모든 요소가 메모리에 올라가 있는 상태에서 요소를 누적시키며 결과를 계산한다 .– 메모리 사용량 연산속도

• 스트림– 계산식 ( 알고리즘 or 람다 ) 을 미리 적어두고 계산시에 람다로 JVM 에 넘긴다 .– 내부에서 요소를 어떻게 메모리에 올리는 지는 관심사가 아니다 . (블랙박스 )– 계산 요청시 결과가 바로 리턴된다 .– 메모리 사용량 연산속도

Page 9: 3. stream api

스트림 연산• 스트림은 2 가지로 연산이 구분된다 .– Filter, map, limit 는 서로 연결되어 파이프라인을 형성한다 .– Collect 로 마지막 파이프라인을 수행후 완료한다 .

• 중간연산 (Intermediate Operation)• 최종연산 (Terminal Operation)

Page 10: 3. stream api

filter map limit collect

중간연산 최종연산

Menu.stream().filter(d -> d.getCalories() > 300) .map(Dish::getName) .limit(3) .collect(toList());

중간연산은 파이프라인으로 연결되어 선언식이 최종연산으로 전달된다 .중간연산 정보를 스트림으로 입력받아 최종연산에서 한번에 처리한다 .

단말 연산을 스트림 파이프라인에 실행하기 전까지는 아무 연산도 수행하지 않는다 . (Lazy)모든 중간연산을 합친 다음 최종연산에서 한번에 처리한다 .

Page 11: 3. stream api

필터링과 슬라이싱• 스트림의 요소를 선택하는 방법을 블록 연산으로 제공• 주요 API

// Predicate 와 일치하는 데이터만 Stream 으로 반환Stream<T> filter(Predicate<? super T> predicate);

// Stream 데이터 중복제거 (hashcode & equals)Stream<T> distinct();

// Stream 데이터 축소 (Cut)Stream<T> limit(long maxSize);

// Stream 데이터 건너뛰기Stream<T> skip(long n);

Page 12: 3. stream api
Page 13: 3. stream api
Page 14: 3. stream api
Page 15: 3. stream api

매핑• 스트림의 특정 객체에서 원하는 데이터만 선택하는 작업을 블록 연산으로 제공• 주요 API

// 데이터의 람다식 결과가 새로운 Stream 으로 제공<R> Stream<R> map(Function<? super T, ? extends R> mapper);

// 람다식 결과가 새로운 Stream 으로 제공되는 것은 동일// 만약 결과가 여러개의 스트림 (Stream<Object[]>) 일때 하나의 스트림으로 변환 <R> Stream<R>

flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);

Page 16: 3. stream api
Page 17: 3. stream api
Page 18: 3. stream api
Page 19: 3. stream api
Page 20: 3. stream api

검색과 매칭• 특정 속성이 데이터 집합에 존재하는지 여부를 검색하는 기능을 블록 연산으로 제공• 주요 API

// Predicate 가 하나라도 일치하는지 검사boolean anyMatch(Predicate<? super T> predicate);

// Predicate 가 모두 일치하는지 검사boolean allMatch(Predicate<? super T> predicate);

// Predicate 가 모두 불일치하는지 검사boolean noneMatch(Predicate<? super T> predicate);

// Stream 에서 아무 데이터나 Optional 로 리턴Optional<T> findAny();

// Stream 에서 첫번째 데이터를 Optional 로 리턴 ( 병렬 실행시 성능이슈 )Optional<T> findFirst();

Page 21: 3. stream api
Page 22: 3. stream api
Page 23: 3. stream api
Page 24: 3. stream api

리듀싱• 스트림의 요소를 누적하여 어떠한 연산을 하는 기능을 블록 연산으로 제공• 주요 API

// 초기값 T 를 기준으로 연산을 누적시켜 결과를 제공T reduce(T identity, BinaryOperator<T> accumulator);

// 초기값 없이 연산을 누적시켜 Optional 로 리턴 (Max, Min)Optional<T> reduce(BinaryOperator<T> accumulator);long count();

Page 25: 3. stream api
Page 26: 3. stream api

Quiz

Page 27: 3. stream api
Page 28: 3. stream api
Page 29: 3. stream api
Page 30: 3. stream api
Page 31: 3. stream api
Page 32: 3. stream api
Page 33: 3. stream api
Page 34: 3. stream api
Page 35: 3. stream api
Page 36: 3. stream api
Page 37: 3. stream api
Page 38: 3. stream api
Page 39: 3. stream api
Page 40: 3. stream api
Page 41: 3. stream api

기본형 특화 스트림• Java8에서 3가지 기본형 (Primitive) 특화 스트림을 제공한다 .

– IntStream– DoubleStream– LongStream

• 기존 스트림을 특화 스트림으로 변화IntStream mapToInt(ToIntFunction<? super T> mapper);DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper);LongStream mapToLong(ToLongFunction<? super T> mapper);

• 특화 스트림을 객체 스트림으로 복원Stream<Integer> boxed();Stream<Double> boxed();Stream<Long> boxed();

• 특정범위의 숫자를 스트림으로 생성// 시작값과 종료값 미포함public static IntStream range(int startInclusive, int endExclusive) {}// 시작값과 종료값 포함public static IntStream rangeClosed(int startInclusive, int endInclusive) {}

Page 42: 3. stream api

AutoBoxing 비용

캐스팅 비용이 겁나 비싸다 !!!

Page 43: 3. stream api
Page 44: 3. stream api
Page 45: 3. stream api

스트림 만들기• 스트림을 일반적으로 컬렉션에서 생성하지만 직접 스트림을 생성하는 것도 가능하다 .

• 주요 API// 문자열로 스트림 생성public static<T> Stream<T> of(T t) {}

// 배열로 스트림 생성public static <T> Stream<T> stream(T[] array) {}

// 무한스트림 생성 (초기값이 존재 , 내부에서 연산이 누적된다 .)public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f) {}

// 무한스트림 생성 (초기값이 미존재 , 외부에서 연산을 가져온다 .) public static<T> Stream<T> generate(Supplier<T> s) {}

Page 46: 3. stream api
Page 47: 3. stream api

스트림 만들기• 무한스트림 생성시 주의점

– 성능을 고려하여 항상 limit() 연산자와 함께 사용해야 한다 .– Generate 를 사용할 경우 병렬코드에 주의해야 한다 .

• Stream.iterator– 단항연산자 타입을 인수로 받는다 .– 기준값을 가지고 있으므로 내부에서 누적시키면서 연산하므로 병렬 코드에 안전하다 .

• Stream.generate– 공급자 타입을 인수로 받는다 .– 특정 객체가 누적 연산을 하도록 위임하므로 병렬 코드에 안전 여부를 반드시 확인해야 한다 .

( 공급된 객체가 반드시 불변객체여야 한다 .)

Page 48: 3. stream api