[Java 8] Stream API

홍정완·2022년 6월 14일
0

Java

목록 보기
7/25
post-thumbnail

Java8에 추가된 Stream API는 다량의 데이터 처리나 손쉬운 병렬 처리를 위해 만들어졌다.




Stream


  • 스트림이 처리하는 데이터 소스를 변경하지 않는다.(원본 데이터를 훼손하지 않는다.)

  • 데이터를 담고 있는 저장소(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
* */



중개 오퍼레이션(intermediate operation)


  • Stream을 여러 방식으로 변환한다.

  • Stream을 리턴한다.

  • Stateless / Stateful 오퍼레이션으로 더 상세하게 구분할 수도 있다.

    • Stateless : filter, map, faltMap, limit, skip

    • Stateful : distinct, sorted



종료 오퍼레이션(terminal operation)


  • Stream을 리턴하지 않는다.

  • 중개 연산 과정에서 변화된 소스 데이터에 종료 연산

    • 이 과정이 수행되어야 중개 연산도 수행
  • collect, allMatch, count, forEach, min, max, ...




Stream API


  • Filter(Predicate)

    • 예) 5글자 이상인 데이터만 새로운 스트림으로

  • Map(Function) 또는 FlatMap(Function)

    • 예) 요소들을 특정 조건에 해당하는 값으로 변환

  • generate(Supplier) 또는 Iterate(T seed, UnaryOperator)

    • 예) 10부터 1씩 증가하는 무제한 숫자 스트림

  • limit(long) 또는 skip(long)

    • 예) 최대 5개의 요소가 담긴 스트림을 리턴한다.

  • anyMatch(), allMatch(), nonMatch()

    • 예) "a"로 시작하는 문자열이 있는지 확인한다. (true 또는 false를 리턴)

  • count()

    • 예) 10보다 큰 수의 개수를 센다.

  • reduce(identity, BiFunction), collect(), sum(), max()

    • 예) 모든 데이터를 하나의 List 또는 Set에 옮겨 담기



Stream API 예제


데이터 준비

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);
profile
습관이 전부다.

0개의 댓글