45. 스트림은 주의해서 사용하라

신명철·2022년 3월 12일
0

Effective Java

목록 보기
43/80

스트림

스트림 API 는 다량의 데이터 처리 작업을 돕고자 자바 8에 추가되었다. 이 API 가 제공하는 추상 개념 중 핵심은 다음 두 가지다.

  • 스트림은 데이터 원소의 유한 혹은 무한 시퀀스를 의미
  • 스트림 파이프라인은 이 원소들로 수행하는 연산단계를 표현하는 개념

스트림 안의 데이터 원소들은 객체 참조나 기본 타입 값이며 기본 타입 값은 int, long, doulble 세 가지를 지원한다. 대표적으로 컬렉션, 배열, 파일, 정규표현식 패턴 매처, 난수 생성기, 다른 스트림이 있다.

스트림 파이프라인

스트림 파이프라인은 소스 스트림에서 시작해서 종단 연산으로 끝난다. 그 사이에 하나 이상의 중간 연산이 있을 수 있다. 각 중간 연산은 스트림을 어떠한 방식으로 변환한다. 중간 연산들은 모두 한 스트림을 다른 스트림으로 변환하는데 변환된 스트림의 원소 타입은 변환 전 스트림의 원소 타입과 같을 수도 다를 수도 있다. 종단 연산은 막 중간 연산이 내놓은 스트림에 최후 연산을 가한다.

스트림 파이프라인은 지연평가(Lazy Evaluation)된다. 평가는 종단 연산이 호출될 때 이루어진다. 즉 종단 연산이 없다면 스트림 파이프라인은 아무 일도 하지 않는 명령어인 no-op 과 같다는 뜻이다. 종단 연산에 쓰이지 않은 데이터 원소는 계산에 쓰이지 않는다.

코드 블럭과 람다

public static void main(String[] args) {
    Stream<String> words = Arrays.stream(new String[]{"abc", "bca" , "bbb", "bvc"});
    words.collect(groupingBy(word -> alphabetize(word))).values().stream().forEach(g -> System.out.println(g.size() + " : " + g));
}

private static String alphabetize(String s) {
    char[] a = s.toCharArray();
    Arrays.sort(a);
    return new String(a);
}

위 코드는 스트림 변수를 알파벳 아나그램으로 만들어 그룹을 지어 출력한다. 스트림 파이프라인은 되풀이되는 계산을 함수 객체로 표현한다. 반면 반복 코드에서는 코드 블럭을 사용해 표현한다.

코드 블럭

  • 코드 블럭에서는 범위 안에서 지역 변수들을 읽고 수정할 수 있다. 하지만, 람다에서는 final 이거나 사실상 final 인 변수만을 읽을 수 읽고 수정도 불가능하다.
  • 코드 블럭에서는 return, break, continue 를 통해 반복문의 제어가 가능하지만 람다는 불가능하다.
  • 코드 블럭에서는 메서드 선언에 명시된 검사 예외를 던질 수 있지만 람다는 불가능하다.

스트림

  • 원소들의 시퀀스를 일관되게 반환한다.
  • 원소들의 시퀀스를 필터링한다.
  • 원소들의 시퀀스를 하나의 연산을 사용해 결합한다.
  • 원소들의 시퀀스를 컬렉션에 모은다.
  • 원소들의 시퀀스에서 특정 조건을 만족하는 원소를 찾는다.

스트림이 적합하지 않은 경우

한 데이터가 파이프라인의 여러 단계를 통과할 때 이 데이터의 각 단계에서의 값들에 동시에 접근하기 어렵다. 스트림 파이프라인은 한 값을 다른 값에 매핑하고 나면 원래의 값을 잃는 구조이기 때문이다.

profile
내 머릿속 지우개

0개의 댓글