BanditBool2 / ReadingRecord

2 stars 0 forks source link

[Ch5] 5.7.3 숫자 스트림 활용: 피타고라스 #23

Closed kkambbak closed 1 year ago

kkambbak commented 1 year ago

p186~187 에서

IntStream.rangeClosed(1,100).boxed()
                .flatMap(a ->
                        IntStream.rangeClosed(a,100)
                                .filter(b -> Math.sqrt(a*a + b*b) % 1 == 0)
                                .mapToObj(b -> new int[]{a, b, (int)Math.sqrt(a*a+b*b)})
                ).forEach(i-> System.out.println(Arrays.toString(i)));

map이 아닌 mapToObj를 쓰는 이유를 잘 모르겠습니다.

chaewon-io commented 1 year ago

map()은 파라미터로 넘겨준 함수형 인터페이스를 통해 스트림의 요소를 새로운 요소의 스트림으로 변환합니다.

map()은 반환하는 형태에 따라 여러 메서드가 존재하고, mapToInt, mapToLong, mapToDouble, mapToObj가 다음에 해당됩니다. 예를 들어, IntStream의 경우 map, mapToLong, mapToDouble, mapToObj가 존재하며 map 자체가 IntStream을 반환하고 Stream의 경우 map, mapToInt, mapToLong, mapToDouble가 존재하며 map() 자체가 Stream을 반환합니다.

map()을 사용할 경우, 아래 코드와 같습니다.

IntStream.rangeClosed(a, 100)
   .filter(b -> Math.sqrt(a*a + b*b) % 1 == 0) 
   .boxed() // Stream<Integer>로 boxing
   .map(b -> new int[]{a, b, (int) Math.sqrt(a*a + b*b)});

따라서, 위 코드를 mapToObj를 이용해서 boxed()와 map() 과정을 하나로 합쳐줄 수 있어,
책에서는 map이 아닌 mapToObj를 사용한 것 같습니다.

| 참고

hanbonghun commented 1 year ago

각 메서드의 선언부를 확인해보면 이해에 도움이 될 거 같습니다.

//flatMap
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);

//Function
@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);
}

// mapToObj
<U> Stream<U> mapToObj(IntFunction<? extends U> mapper); 

//map
IntStream map(IntUnaryOperator mapper);

flatMap메서드의 파라미터는 Function<T의 슈퍼 타입중 하나, Stream의 하위 타입 중 하나> 를 구현한 객체여야 합니다. 작성하신 코드에서

IntStream.rangeClosed(1,100).boxed()
                .flatMap(a ->
                        IntStream.rangeClosed(a,100)
                                .filter(b -> Math.sqrt(a*a + b*b) % 1 == 0)
                                .mapToObj(b -> new int[]{a, b, (int)Math.sqrt(a*a+b*b)})
                ).forEach(i-> System.out.println(Arrays.toString(i)));

.flatMap 의 파라미터를 보면 a->{} 형태이고, Function타입을 구현한 객체이려면 a->{} 에서 리턴 타입이 Stream이여야 합니다. 이러한 이유로 a ->{ return 이전스트림결과.mapToObj()} 가 되어야 a->{return Function<? super T, ? extends Stream<? extends R>> } 가 되므로, flatMap의 파라미터에 부합합니다.

반면 map함수의 경우는 a->{}형태가 a->{return 이전스트림결과.map()} 이므로 a->{return Intstream} 이 되어 flatMap파라미터에 정의된 Function<? super T, ? extends Stream<? extends R>> 를 만족하지 않습니다. 따라서 mapToObj를 사용해야 합니다.