관련소스코드

 

이전글

20200421 [java8] Java8InAction 읽기 & 기록 [ch01 ~ ch03]

20200430 [java8] Java8InAction 읽기 & 기록 [ch04 ~ ch05]

Chapter06 : 스트림으로 데이터 수집

 

자바 8에서의 스트림이란 데이터 집합을 처리하는 게으른 반복자

 

다양한 요소를 누적시키는 방식을 구분토록 하자.

  • Collection (컬렉션)
  • Collector (컬렉터)
  • collect

컬렉터란 무엇인가? 

collect() 메소드로 내부의 인자 타입을 Collector 인터페이스로 구현토록 전달하였다. Collector 란 스트림의 요소를 어떤 식으로 도출할 지 지정한다. Collector 의 요소는 다양하게 있다.

 

컬렉터 클래스의 정적 팩토리 메소드 (Collectors.{factory-method} 형식)

(직접 해당 메소드를 이용해 스트림 예제를 작성해보면 어떻게 쓰이는지 파악이 가능하다.)

팩토리 메소드 반환형식 설명
toList List<T> 스트림의 모든 항목을 리스트로 수집
toSet Set<T> 스트림의 모든 항목을 중복이 없는 집합으로 수집
toCollection Collection<T> 스트림의 모든 항목을 공급자가 제공하는 컬렉션으로 수집
counting Long 스트림의 항목 수 계산
summingInt Integer 스트림의 항목에서 (정수) 프로퍼티 값을 더함
averageInt Double 스트림의 항목에서 (정수) 프로퍼티 값의 평균값을 계산
summarizingInt IntSummaryStatistics 스트림 내의 항목의 최댓값, 최솟값, 합계, 평균, 등의 (정수) 정보 통계를 수집
joining String 스트림의 각 항목에 toString() 메소드를 호출하여, 결과 문자열들을 연결
maxBy Optional<T> 주어진 비교자를 이용해서 스트림의 최댓값 요소를 Optional 로 감싼 값을 반환. 스트림에 요소가 없을 때는 Optional.empty() 를 반환.
minBy Optional<T> 주어진 비교자를 이용해서 스트림의 최솟값 요소를 Optional 로 감싼 값을 반환. 스트림에 요소가 없을 때는 Optional.empty() 를 반환.
reducing 리듀싱 연산 형식에서 결졍 -
collectionAndThen 변환함수가 형식을 반환 다른 컬렉터를 감싸고 그 결과에 변환 함수를 적용
groupingBy Map<K, List<T>> 하나의 프로퍼티 값을 기준으로 스트림의 항목을 그룹화하며 기준 프로퍼티 값을 결과 맵의 키로 사용
partitioningBy Map<Boolean, List<T>> 프레디케이트를 스트림의 각 항목에 적용한 결과로 항목을 분할

Dish.java

public class Dish {
    private final String name;
    private final boolean vegetarian;
    private final int calories;
    private final Type type;

    public Dish(String name, boolean vegetarian, int calories, Type type){
        this.name = name;
        this.vegetarian = vegetarian;
        this.calories = calories;
        this.type = type;
    }

    public String getName(){
        return this.name;
    }

    public boolean isVegetarian(){
        return this.vegetarian;
    }

    public int getCalories(){
        return this.calories;
    }

    public Type getType(){
        return this.type;
    }

    public enum Type{
        MEAT, FISH, OTHER
    }
}
List<Dish> menu = Arrays.asList(
        new Dish("pork", false, 800, Dish.Type.MEAT),
        new Dish("beef", false, 700, Dish.Type.MEAT),
        new Dish("chicken", false, 400, Dish.Type.MEAT),
        new Dish("french fries", true, 530, Dish.Type.OTHER),
        new Dish("rice", true, 350, Dish.Type.OTHER),
        new Dish("season fruit", true, 120, Dish.Type.OTHER),
        new Dish("pizza", true, 550, Dish.Type.OTHER),
        new Dish("prawns", false, 300, Dish.Type.FISH),
        new Dish("salmon", false, 450, Dish.Type.FISH));

menu 에 있는 목록에서 칼로리에 대해서 정보 통계 내기

// Integer 전용의 합계, 평균, 최대 및 최소값, 요소수 전체를 반환하는 메소드가 있음
IntSummaryStatistics menuStatistics = menu.stream().collect(summarizingInt(Dish::getCalories));
System.out.println("menuStatistics : " + menuStatistics);

// 출력
menuStatistics : IntSummaryStatistics{count=9, sum=4200, min=120, average=466.666667, max=800}

menu 에 있는 목록에서 가장 높은 칼로리를 가진 Dish 를 Dish.Type 에 맞게 분류

/** (4.3) 4.2 의 결과를 다른 형식으로 적용시키기 **/
final Map<Dish.Type, Dish> mostCaloricByTypeOne = menu.stream()
		.collect(groupingBy(Dish::getType,
        		collectingAndThen(maxBy(comparingInt(Dish::getCalories)), Optional::get)));

 

책을 읽다보니, 커스텀 컬렉터를 구현하는 부분이 있는데 가독성과 재사용성이 떨어져서 사용을 권하지 않는다. 이후에 책을 보면서 Collector 인터페이스에서 선언해놓은 메소드의 반환타입들만 조금 더 알아보려고 한다.

 

Supplier example

private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public static void main(String[] args) {

    /**
     * 아무런 인수도 받지 않고, 반환을 한다.
     */

    final Supplier<LocalDateTime> supplierTime = () -> LocalDateTime.now();
    System.out.println(supplierTime.get());         // 현재시간

    final Supplier<LocalDateTime> supplierFormatTime = () -> LocalDateTime.parse(LocalDateTime.now().format(formatter), formatter);
    System.out.println(supplierFormatTime.get());   // 포맷팅 된 현재시간

    final Supplier<String> nameOfMeSupplier = () -> "PARK";
    System.out.println(nameOfMeSupplier.get());     // PARK
}

BiConsumer example

/**
 * 두 개의 인수를 받고 아무것도 리턴하지 않는다.
 */

final BiConsumer<Integer, Integer> printAddTwoNumber = (x, y) -> System.out.println(x + y);
printAddTwoNumber.accept(2, 5); // 7

final BiConsumer<Integer, Integer> printMulTwoNumber = (x, y) -> System.out.println(x * y);
printMulTwoNumber.accept(2, 5); // 10

System.out.println("=========");
final BiConsumer<Integer, Integer> printAndThen = printAddTwoNumber.andThen(printMulTwoNumber);
printAndThen.accept(2, 5);      // 7, 10

Function example

/**
 * 제네릭 T 를 받아
 * 제네릴 R 을 리턴한다. 서로 다른 타입 무방
 * 하나를 받고 하나를 리턴
 */

final Function<String, Integer> nameToNameLengthFunc = (name) -> name.length();
System.out.println(nameToNameLengthFunc.apply("JAVA8"));            // 5
System.out.println(nameToNameLengthFunc.apply("JAVA8In"));          // 7
System.out.println(nameToNameLengthFunc.apply("JAVA8InAction"));    // 13

/**
 * Chaning Function 이 가능하다.
 * **/
final Function<Integer, Integer> addFunc = (x) -> x + 1;
final Function<Integer, Integer> subFunc = (x) -> x - 1;
final Function<Integer, Integer> expFunc = (x) -> x * x;

final Function<Integer, Integer> newAddFunc = addFunc.andThen(addFunc);
final Function<Integer, Integer> newSubFunc = subFunc.andThen(subFunc);

System.out.println("Function Method Chaining");
System.out.println(newAddFunc.apply(5));    // 7
System.out.println(newSubFunc.apply(5));    // 3

final Function<Integer, Integer> addAndThenExpFunc = addFunc.andThen(expFunc);
System.out.println(addAndThenExpFunc.apply(7));     // 64

final Function<Integer, Integer> expFuncThenAddFunc = expFunc.andThen(addFunc);
System.out.println(expFuncThenAddFunc.apply(7));    // 50

BinaryOperator

/**
 * [BinaryOperator]
 * 동일한 타입의 인수 두 개를 받아서 하나의 동일한 타입으로 리턴한다.
 *
 * [BiFunction]
 * 아무 타입의 인수 두 개를 받아서 하나의 아무 타입으로 리턴한다.
 */

final BiFunction<Integer, Integer, Integer> addAndReturnValueFunc = (x, y) -> x + y;
System.out.println(addAndReturnValueFunc.apply(5, 10));     // 15

final BinaryOperator<Integer> addAndReturnValueFunc2 = (x, y) -> x + y;
System.out.println(addAndReturnValueFunc2.apply(10, 20));   // 30

참고자료

https://mkyong.com/java8/java-8-supplier-examples/

https://mkyong.com/java8/java-8-function-examples/

https://mkyong.com/java8/java-8-biconsumer-examples/

https://mkyong.com/java8/java-8-binaryoperator-examples/

Posted by doubler
,