더 자바, Java 8
Stream
카테고리 : 더 자바, Java 8
Stream
Stream 소개
Stream
- sequence of elements supporting sequential and parallel aggregate operations
- 순차적 및 병렬 집계 작업을 지원하는 요소 시퀀스
- 데이터를 담고 있는 저장소(컬렉션)이 아니다.
- Funtional in nature, 스트림이 처리하는 데이터 소스를 변경하지 않는다.
- Funtional in nature : Funtional 하다 , 소스를 변경하지 않는다 라는 의미
- 스트림으로 처리하는 데이터는 오직 한번만 처리한다.
- 무제한일 수도 있다.(Short Circuit 메소드를 사용해서 제한할 수 있다.)
- Short Circuit : 단축시키는 , 제한할 수 있다.
- 중개 오퍼레이션은 근본적으로 lazy 하다.
- 손쉽게 병렬 처리할 수 있다.
- parallelStream()
- 무조건 빨라지는게 아니다.
- 오히려 context switch 를 하기 때문에 속도가 느려질 수 있다.
- 데이터가 방대하게 클 경우에 유용하다.
- parallelStream()
List<String> test = new ArrayList<>();
test.add("test1");
test.add("test2");
test.add("test3");
test.add("test4");
List<String> collect = test.parallelStream().map((s) -> {
System.out.println(s + " " + Thread.currentThread().getName());
return s.toUpperCase();
}).collect(Collectors.toList());
collect.forEach(System.out::println);
스트림 파이프라인
- 0 또는 다수의 중개 오퍼레이션(intermediate operation)과 한개의 종료 오퍼레이션(terminal operation)으로 구성한다.
- 스트림의 데이터 소스는 오직 터미널 오퍼레이션을 실행할 때에만 처리한다.
중개 오퍼레이션
- Stream 을 리턴한다.
- Stateless / Stateful 오퍼레이션으로 더 상세하게 구분할 수도 있다.
- 대부분은 Stateless 지만 distinct 나 sort 처럼 이전 소스 데이터를 참조해야 하는 오퍼레이션은 Stateful 오퍼레이션이다
- filter, map, limit, skip, sorted, …
종료 오퍼레이션
- Stream 을 리턴하지 않는다.
- collect, allMatch, count, forEach, min, max, …
참고
- https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html
- https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html
Stream API
걸러내기
- Filter(Predicate)
- 예) 이름이 3글자 이상인 데이터만 새로운 스트림으로
List<String> test = new ArrayList<>();
test.add("가가가");
test.add("나나나");
test.add("다다다");
test.add("마마마마");
Stream<String> stringStream = test.stream().filter(s -> s.length() > 3);
System.out.println("spring 으로 시작하는 수업");
// TODO
springClasses.stream().filter(sc -> sc.getTitle().startsWith("spring")).forEach(sc -> System.out.println(sc.getTitle()));
System.out.println("close 되지 않은 수업");
// TODO
springClasses.stream().filter(Predicate.not(OnlineClass::isClosed)).forEach(sc -> System.out.println(sc.getTitle()));
변경하기
- Map(Function) 또는 FlatMap(Function)
- 예) 각각의 Post 인스턴스에서 String title 만 새로운 스트림으로
- 예) List<Stream
>을 String 의 스트림으로
List<Post> posts = new ArrayList<>();
posts.add(new Post("첫번째 게시글", "첫번째 게시글의 내용"));
posts.add(new Post("두번째 게시글", "두번째 게시글의 내용"));
posts.add(new Post("세번째 게시글", "세번째 게시글의 내용"));
posts.add(new Post("네번째 게시글", "네번째 게시글의 내용"));
posts.add(new Post("다섯번째 게시글", "다섯번째 게시글의 내용"));
posts.add(new Post("여섯번째 게시글", "여섯번째 게시글의 내용"));
posts.add(new Post("일곱번째 게시글", "일곱번째 게시글의 내용"));
posts.add(new Post("여덟번째 게시글", "여덟번째 게시글의 내용"));
posts.stream().map(Post::getTitle).forEach(System.out::println);
System.out.println("-------------------------------");
posts.stream().flatMap(post -> post.getTitle().stream()).forEach(System.out::println);
System.out.println("수업 이름만 모아서 스트림 만들기");
// TODO
Stream<String> stringStream = springClasses.stream().map(OnlineClass::getTitle);
System.out.println("두 수업 목록에 들어있는 모든 수업 아이디 출력");
// TODO
sumEvents.stream().flatMap(Collection::stream).forEach(oc -> System.out.println(oc.getId()));
생성하기
- generate(Supplier) 또는 Interate(T seed, UnaryOperator)
- 예) 10 부터 1 씩 증가하는 무제한 숫자 스트림
- 예) 랜덤 int 무제한 스트림
Stream.iterate(10, i -> i + 1).forEach(System.out::println);
제한하기
- limit(long) 또는 skip(long)
- 예) 최대 5개의 요소가 담긴 스트림을 리턴한다.
- 예) 앞에서 3 개를 뺀 나머지 스트림을 리턴한다.
Stream.iterate(10, i -> i + 1).limit(5).forEach(System.out::println);
Stream.iterate(10, i -> i + 1).skip(3).forEach(System.out::println);
Stream.iterate(10, i -> i + 1).skip(3).limit(5).forEach(System.out::println);
스트림에 있는 데이터가 특정 조건을 만족하는지 확인
- allMatch(), allMatch(), nonMatch()
- 예) k 로 시작하는 문자열이 있는지 확인한다. (true 또는 false 를 리턴한다.)
- 예) 스트림에 있는 모든 값이 10 보다 작은지 확인한다.
boolean allMatch = Stream.of("k", "j", "i", "h", "g").allMatch(s -> s.startsWith("k"));
boolean anyMatch = Stream.of("k", "j", "i", "h", "g").anyMatch(s -> s.startsWith("k"));
boolean noneMatch = Stream.of("k", "j", "i", "h", "g").noneMatch(s -> s.startsWith("k"));
System.out.println(allMatch);
System.out.println(anyMatch);
System.out.println(noneMatch);
boolean allLessThan10 = Stream.of(1, 2, 3, 4, 5).allMatch(i -> i < 10);
boolean allLessThan10 = Stream.of(1, 2, 3, 4, 5).noneMatch(i -> i < 10);
개수 세기
- count()
- 예) 10 보다 큰 수의 개수를 센다.
long count = Stream.of(1, 2, 3, 4, 5, 11, 12).filter(n -> n > 10).count(); System.out.println(count);
스트림을 데이터 하나로 뭉치기
- reduce(indentity, BjFunction), collect(), sum(), max()
- 예) 모든 숫자 합 구하기
- 예) 모든 데이터를 하나의 List 또는 Set에 옭겨 담기
int sum = Stream.of(1, 2, 3, 4, 5).reduce(0, (a, b) -> a + b);
System.out.println(sum);
List<Integer> list = Stream.of(1, 2, 3, 4, 5).collect(Collectors.toList());
System.out.println(list);
Set<Integer> set = Stream.of(1, 2, 3, 4, 5).collect(Collectors.toSet());
System.out.println(set);
Optional<Integer> max = Stream.of(1, 2, 3, 4, 5).max((a, b) -> a.compareTo(b));
System.out.println(max.get());
Optional<Integer> max = Stream.of(1, 2, 3, 4, 5).max(Integer::compareTo);
System.out.println(max.get());
int sum = Stream.of(1, 2, 3, 4, 5).reduce(0, (a, b) -> a + b);
System.out.println(sum);
System.out.println("스프링 수업 중에 제목에 spring이 들어간 것만 모아서 List로 만들기");
// TODO
springClasses.stream().map(sc -> sc.getTitle()).filter(s -> s.contains("spring")).collect(Collectors.toList());