무작정 개발.Vlog

[Java8] Stream API에 대해

by 무작정 개발
반응형

이번에는 Java 8에 추가된 기능 중 Stream에 대해 정리할 것이다.

 

 

1. Stream이란?

Stream이란 Collection(컬렉션)과 같은 연속된 데이터를 처리하는 오퍼레이션의 모음, Stream 그 자체로는 데이터가 아닙니다.

 

Java Stream
컴베이어 벨트 - 출처 : 맨 하단에 기재

Stream은 컨베이어 벨트와 비슷합니다.

컨베이어 벨트에 떡 조각(데이터)들을 흘려보내면서 반죽을 하고, 앙금을 쌓고(map), 불량품은 빼고(filter) 포장을 해서(collect) 내보냅니다.

 

(1) Stream의 특징

  • 데이터를 담고 있는 자정소(Collection)이 아닙니다.
  • Functional in nature 
    • Stream은 처리하는 데이터 소스를 변경하지 않습니다. 즉, A라는 데이터를 수정한다고 해서 원본 데이터가 수정되는 것이 아니라는 의미입니다.
public static void main(String[] args) {
    List<String> names = new ArrayList<>();
    names.add("hyunwoo");

    Stream<String> stringStream = names.stream().map(String::toUpperCase);
    names.forEach(System.out::println);
}
/*
[실행 결과]
hyunwoo
*/
  • Stream으로 처리하는 데이터는 오직 단 1번만 처리합니다.
    • 컨베이어 벨트에서 데이터들이 1번 지나간 뒤 다시 돌아오지 않습니다.
  • 데이터가 무제한 일 수도 있습니다.
    • 실시간으로 계속 데이터를 받아 온다면 Short Circuit 메서드를 사용해서 제한이 가능합니다.
  • 중개 오퍼레이션은 근본적으로 lazy(게으름)합니다.
    • 여러 중개 오퍼레이션들을 메서드 체이닝을 하더라도 그 시점에서 코드가 수행되지는 않습니다. 모든 중개 오퍼레이션의 실행 시기는 종료 오퍼레이션의 호출 시점입니다. 그렇기에 중개 오퍼레이션의 반환 타입은 또 다른 Stream입니다.
public static void main(String[] args) {
    List<String> names = new ArrayList<>();
    names.add("hyunwoo");
    names.add("blog");
    names.add("26age");
    names.add("무작정개발");

    Stream<String> stringStream = names.stream().map(s->{
        System.out.println(s);
        return s.toUpperCase();
    });
    names.forEach(System.out::println);
}

1. names.stream().map(s->{....});

-> stream의 중개 오퍼레이터를 사용하는 순간에는 코드가 수행되지 않습니다. 그렇게 때문에 중개 오퍼레이션 map 안에 있는 출력문이 수행되지 않고, 수행시키기 위해서는 스트림 파이프라인(Stream PipeLine)을 정의해야 합니다.

 

  • 쉽게 병렬 처리(multi-threading)를 할 수 있습니다.
    • for문(반복문)을 stream을 통해 구현하면 간결하게 작성할 수 있습니다.
    • parallelStream()을 이용하면 JVM이 병렬적으로 오퍼레이션을 처리해 줍니다.
public static void main(String[] args) {
    List<String> names = new ArrayList<>();
    names.add("hyunwoo");
    names.add("blog");
    names.add("26age");
    names.add("무작정개발");

    List<String> collect = names.parallelStream().map(s->{
        System.out.println(s + " " + Thread.currentThread().getName());
        return s.toUpperCase();
    }).collect(Collectors.toList());

    collect.forEach(System.out::println);
}

-> 여기서 주의할 점은 parallelStream을 사용해서 병렬 처리를 한다고 성능이 무조건 좋아지는 것은 아닙니다.

오히려 느려질 수도 있기에 대부분의 경우에는 stream을 쓰는 것이 좋고, 대용량 데이터를 다룰 때 성능 테스트 후 parrllelStream()을 사용하면 됩니다.

 


2. Stream API의 중개, 종료 오퍼레이션

 

(1) 스트림 파이프라인 (Stream PipeLine)

스트림(Stream)이라는 컨베이어 벨트에 0개 혹은 다수의 중개 오퍼레이터(intermediate operation)와 1개의 종료 오퍼레이션(terminal operation)으로 구성합니다. 이 Stream은 반드시 하나의 종료 오퍼레이션이 있어야 하고, 만약에 종료 오퍼레이션이 없다면, Stream은 존재하지만 코드가 수행되지 않습니다.

-> 스트림(Stream)의 데이터 소스는 오직 터미널 오퍼레이션(종료 오퍼레이션)을 실행할 때에만 처리합니다.

 

 

(2) 중개 오퍼레이션 (Intermediate Operation)

  • Stream을 리턴합니다.
  • Stateless / Stateful 오퍼레이션으로 더 상세하게 구분 가능
    • 대부분 Stateless이지만 distinct나 sorted처럼 이전 소스 데이터를 참조해야 하는 오퍼레이션은 Stateful 오퍼레이션입니다.
  • filter, map, limit, skip, sorted 등

 

(3) 종료 오퍼레이션 (Terminal Operation)

  • Stream을 리턴하지 않는다.
  • collect, allmatch, count, forEach, min, max 등
public static void main(String[] args) {
        List<String> names = new ArrayList<>();
        names.add("hyunwoo");
        names.add("blog");
        names.add("26age");
        names.add("무작정개발");

        List<String> collect = names.stream().map(s -> {
            System.out.println(s);
            return s.toUpperCase();
        }).collect(Collectors.toList());
        collect.forEach(System.out::println);
    }

 


Reference

Catsbi's DLog

 

Stream

1. Stream 소개

catsbi.oopy.io

인프런-더 자바, Java8_백기선

 

더 자바, Java 8 - 인프런 | 강의

자바 8에 추가된 기능들은 자바가 제공하는 API는 물론이고 스프링 같은 제 3의 라이브러리 및 프레임워크에서도 널리 사용되고 있습니다. 이 시대의 자바 개발자라면 반드시 알아야 합니다. 이

www.inflearn.com

 

반응형

블로그의 정보

무작정 개발

무작정 개발

활동하기