Java8에 추가된 Stream API는 다량의 데이터 처리나 손쉬운 병렬 처리를 위해 만들어졌다.
스트림이 처리하는 데이터 소스를 변경하지 않는다.(원본 데이터를 훼손하지 않는다.)
데이터를 담고 있는 저장소(Collection)가 아니다.
스트림으로 처리하는 데이터는 오직 한 번만 처리된다.
무제한일 수도 있다. (Short Circuit 메서드를 사용해서 제한할 수 있다.)
근본적으로 지연 평가(Lazy Evaluation)을 사용한다.
손쉬운 병렬 처리 지원한다.(parallelStream 덕분)
중개 오퍼레이션(intermediate operation)과 한 개의 종료 오퍼레이션(terminal operation)으로 구성
스트림의 데이터 소스는 오직 터미널 오퍼네이션을 실행할 때에만 처리한다.
List<String> fruits = new ArrayList<>();
fruits.add("apple");
fruits.add("banana");
fruits.add("grape");
fruits.add("melon");
fruits.stream() // 소스 스트림
.filter(s -> s.startsWith("b"))
.forEach(System.out::println);
/* 결과 값
*
* banana
* */
Stream을 여러 방식으로 변환한다.
Stream을 리턴한다.
Stateless / Stateful 오퍼레이션으로 더 상세하게 구분할 수도 있다.
Stateless : filter, map, faltMap, limit, skip
Stateful : distinct, sorted
Stream을 리턴하지 않는다.
중개 연산 과정에서 변화된 소스 데이터에 종료 연산
collect, allMatch, count, forEach, min, max, ...
Filter(Predicate)
Map(Function) 또는 FlatMap(Function)
generate(Supplier) 또는 Iterate(T seed, UnaryOperator)
limit(long) 또는 skip(long)
anyMatch(), allMatch(), nonMatch()
count()
reduce(identity, BiFunction), collect(), sum(), max()
public class OnlineClass {
private Integer id;
private String title;
private boolean closed;
public OnlineClass(Integer id, String title, boolean closed) {
this.id = id;
this.title = title;
this.closed = closed;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public boolean isClosed() {
return closed;
}
public void setClosed(boolean closed) {
this.closed = closed;
}
}
public static void main(String[] args) {
List<OnlineClass> springClasses = new ArrayList<>();
springClasses.add(new OnlineClass(1, "spring boot", true));
springClasses.add(new OnlineClass(2, "spring data jpa", true));
springClasses.add(new OnlineClass(3, "spring mvc", false));
springClasses.add(new OnlineClass(4, "spring core", false));
springClasses.add(new OnlineClass(5, "rest api development", false));
List<OnlineClass> javaClasses = new ArrayList<>();
javaClasses.add(new OnlineClass(6, "The Java, Test", true));
javaClasses.add(new OnlineClass(7, "The Java, Code manipulation", true));
javaClasses.add(new OnlineClass(8, "The Java, 8 to 11", false));
List<List<OnlineClass>> Events = new ArrayList<>();
Events.add(springClasses);
Events.add(javaClasses);
}
System.out.println("\n\nspring으로 시작하는 수업");
springClasses.stream()
.filter((onlineClass -> onlineClass.getTitle().startsWith("spring")))
.forEach((onlineClass -> System.out.println(onlineClass.getId())));
System.out.println("\n\nclose 되지 않은 수업");
springClasses.stream()
.filter(Predicate.not(OnlineClass::isClosed))
.forEach(oc -> System.out.println(oc.getId()));
System.out.println("\n\n수업 이름만 모아서 스트림 만들기");
springClasses.stream()
.map(oc -> oc.getTitle())
.forEach(System.out::println);
System.out.println("\n\n두 수업 목록에 들어있는 모든 수업 아이디 출력");
Events.stream().flatMap(Collection::stream)
.forEach(oc -> System.out.println(oc.getId()));
System.out.println("\n\n10부터 1씩 증가하는 무제한 스트림 중에서 앞에 10개 빼고 최대 10개 까지만");
Stream.iterate(10, i -> i + 1)
.skip(10)
.limit(10)
.forEach(System.out::println);
System.out.println("\n\n자바 수업 중에 Test가 들어있는 수업이 있는지 확인");
boolean test = javaClasses.stream().anyMatch(oc -> oc.getTitle().contains("Test"));
System.out.println(test);
System.out.println("\n\n스프링 수업 중에 제목에 spring이 들어간 것만 제목만 모아서 List로 만들기");
List<String> spring = springClasses.stream()
.filter(oc -> oc.getTitle().contains("spring"))
.map(oc -> oc.getTitle())
.collect(Collectors.toList());
spring.forEach(System.out::println);