Skip to content

Latest commit

 

History

History
144 lines (100 loc) · 4.29 KB

46. 스트림에서는 부작용 없는 함수를 사용하라.md

File metadata and controls

144 lines (100 loc) · 4.29 KB

46. 스트림에서는 부작용 없는 함수를 사용하라

스트림(stream) 이란?

함수형 프로그래밍에 기초한 패러다임 표현력, 속도, 병렬성을 얻을 수 있음

스트림 패러다임

변환 단계별 함수는 순수함수여야 한다

  • 순수함수
    • 입력만이 결과에 영향을 주는 함수
    • 다른 가변객체 참조 x
    • 함수 안에서 다른 상태들 변경 x

bad

public class Item46 {
    public static void main(String[] args) {
        Map<String, Long> freq = new HashMap<>();
        try (Stream<String> words = new Scanner("file").tokens()) {
            words.forEach(word -> freq.merge(word.toLowerCase(), 1L, Long::sum));
        }
    }
}
  • 스트림 코드를 가장한 반복적 코드
  • 길고, 읽기 어렵고, 유지보수 못함

forEach() 사용에 주의하자

  • 스트림의 forEach는 종단연산 중
    • 기능이 가장 적다
    • 가장 덜 스트림답다
  • 계산하는 데는 쓰지 말자!
  • 사용처
    • 스트림 계산 결과를 보고할 때
    • (가끔) 스트림 계산 결과를 기존 컬렉션에 추가

수집기(Collector)

toMap, toList, toSet 등...

사용 예시

public class Item46 {
    List<String> topTen = freq.keySet().stream()
            .sorted(comparing(freq::get).reversed())
            .limit(10)
            .collect(Collectors.toList());
}
  • comparing : 키 추출 함수를 받는 비교자 생성 메서드
  • freq::get : 입력받은 단어를 빈도표에서 찾아 그 빈도를 반환
  • 이후 비교자(comparing) 를 역순으로 정렬

맵으로 반환

1)인수 2개

toMap(Object::toString, e -> e))

  • 스트림 원소가 고유 키에 매핑

2)인수 3개

toMap(keyMapper, valueMapper, BinaryOperator<U>)

  • 3번째 인수 : 병합 함수(BinaryOperator(U))
  • 키와 연관 원소 중 하나를 골라 연관짓는 맵을 만들 떄 유용
public class Item46 {
    Map<Artist, Album> topHits = albums.collect(
            toMap(Album::aritst, a -> a, maxBy(comparing(Album::sales))));
}
  • 앨범 스트림을 맵으로 반환
    • 자신의 키 추출 함수로는 Album::artist를 사용
    • key로 추출된 음악가와 그 음악가의 베스트 앨범을 짝지음
  • U는 해당 맵의 값 타입

3)인수 4개

public class Item46 {
    //toMap(keyMapper, valueMapper, (oldVal, newVal) ->newVal);
}
  • 4번쨰 인수 : 맵 팩토리
  • 키와 연관 원소 중 하나를 골라 연관짓는 맵을 만들 떄 유용
  • 인수로 받은 비교자를 이용
  • 스트림에서 값이 가장 작은 / 가장 큰 원소를 찾아 반환
  • 인자 : 분류함수
    • 분류함수 : 입력받는 원소가 속하는 카테고리 반환
  • 반환값 : 원소들을 카테고리(해당 함수의 맵 키) 별로 모아둔 맵을 담은 수집기

1)인수 1개

Collectors.groupingBy(Product::getAmount)

  • 비슷한 거로 partitionBy()

  • 1번째 인수

    • 분류함수(classifier) : 입력하는 원소가 속한 카테고리 반환
    • 카테고리는 해당 원소의 맵키로 쓰임

2)인수 2개

  • 2번째 인수
  • 리스트 외의 값을 갖는 맵 생성

3)인수 3개

  • 3번째 인수 : 맵 팩터리(mapFactory)
  • 점층적 인수 목록 패턴에 어긋남
    • 맵, 그안 컬렉션 타입 모두 지정 가능
  • counting 메서드가 반환하는 수집기는 다운스트림 수집기 전용
  • collect(counting()) 형태로 사용 x
  • Collections에는 이런 속성의 메서드가 16개나 더 있다.
  • 원소들 연결시 구분문자를 삽입
  • prefix, suffix 인수 추가 가능