본문 바로가기
카테고리 없음

모던 자바 인 액션 스터디 3. 스트림 활용

by 손너잘 2021. 3. 7.

손너잘

5장 문제.손너잘은 집을 사기 위해 열심히 저금을 하고 있다. 이번 우테코은행에서는 손너잘과 같은 사람들을 위해 적금 시스템을 만들었다.
적금은 4년 만기 이며 매달 돈을 내면 이자를 매달 복리로 계산하여 준다. 이자울는 10%이다.
아래와 같이 손너잘이 저금한 금액이 들어왔을 때 최종적으로 손너잘이 받을 금액을 산출하시오.

 

단 복리계산은 다음과 같이 한다.

1년, 1월에 74만원을 입금한 손너잘은 이자 10퍼를 더한 7.4만원을 2월달에 받고 2월에 80만원을 입금하였으므로 그 시점 자산은 74 + 80 + 7.4 인 171.4만원이 된다. 이 금엑에 또 10퍼의 이자를 받고 3월달에 합쳐지고.....

 

또한 4년 마지막 달의 이율은 계산하지 않는다.

 

이해가 안되면 댓글 부탁 드립니다.

 

입력은 행은 '년' 이며 열은 매달 저금한 금액이다.

int[][] savings = new int[][] {
        {74, 80, 59, 68, 74, 80, 59, 68, 74, 80, 59, 68},
        {45, 34, 22, 54, 63, 22, 64, 34, 13, 34, 75, 33},
        {23, 34, 66, 64, 74, 43, 11, 56, 46, 34, 57, 43},
        {13, 44, 56, 7, 45, 45, 6, 45, 53, 66, 77, 5},
};

나의 답

더보기

flatmap과 reduce을 사용할 일이 잘 없지만, 막상 쓰려면 유용하게 쓰여서 출제해봄.

double reduce = Arrays.stream(savings)
        .flatMapToInt(Arrays::stream)
        .mapToDouble(i -> i)
        .reduce(0, (i, j) -> i + i * 0.1 + j);

System.out.println(reduce);

나봄

5장 문제
우테코에서 로또 과제를 하고 있던 나봄.
로또 번호 생성을 Stream.generate() 을 이용해 생성하고 싶었다.
Stream.generate() 을 이용해 로또 번호가 담겨있는 List<Integer> 를 만들어 주세요!
요구사항 :

  • 로또 번호는 1~45 사이이다.
  • 로또 번호는 중복되면 안된다.
  • List의 사이즈는 6 개이다.

나의 답

더보기
List<Integer> collect = new Random()
                    .ints(1, 46)
                    .filter(i -> 1 <= i && i <= 45)
                    .distinct()
                    .limit(6)
                    .boxed()
                    .collect(toList());

웨지

5장 문제
햄버거 문제 이어서 나갑니당!
아니 매니저님 그냥 말로만 하시면 어떡해요 그래도 햄버거 메뉴 소스는 주셔야 할거 아니에요... 드디어 햄버거 목록을 받았습니다! 해당 소스를 이용해서 매니저가 요구했던 조건에 맞는 결과를 검출해주세요!

다시보는 요구사항
일단 메뉴를 전부 줄게, 다 적어나봐..
1. 다이어트 메뉴를 만들어야해, 500칼로리가 안 되는 메뉴들만 뽑아봐
2. 그중 가격이 가장 비싼걸 찾아야 하거든?
3. 3개까지만.
4. 그 메뉴들의 가격 목록을 만들어줘

---

class HamburgerShop {
    static class Hamburger implements Comparable<Hamburger>{
        String name;
        int price;
        int calorie;
        public Hamburger(String name, int price, int calorie) {
            this.name = name;
            this.price = price;
            this.calorie = calorie;
        }
        @Override
        public int compareTo(Hamburger that) {
            return Integer.compare(this.price, that.price);
        }
    }
    public static void main(String[] args) {
        List<Hamburger> menus = Arrays.asList(
                new Hamburger("쿼터파운더치즈", 4000, 600),
                new Hamburger("빅맥", 4600, 500),
                new Hamburger("베이컨토마토디럭스", 8000, 700),
                new Hamburger("치즈", 2800, 350),
                new Hamburger("더블치즈", 3800, 390),
                new Hamburger("1955버거", 6500, 800),
                new Hamburger("맥치킨", 2500, 410),
                new Hamburger("상하이치킨", 4500, 500),
                new Hamburger("불고기", 2000, 300),
                new Hamburger("행운", 3500, 450)
        );
        List<Integer> topThreePrice = menus.stream()
                //중간연산을 작성해 주세요~!
                .collect(Collectors.toList());
        System.out.println(topThreePrice);
    }
}

---

[4600, 3500, 3800]

나의 답

더보기
List<Integer> topThreePrice = menus.stream()
                .filter(hamburger -> hamburger.price < 500)
                .sorted(comparing(h -> h.price, reverseOrder()))
                .map(h -> h.price)
                .limit(3)
                .collect(Collectors.toList());

라이언

5장 문제
map과 flatMap의 차이를 이해한 것을 토대로 최대한 간략하게 서술하시오.

 

나의 답

더보기

flatmap은 map 과 달리 평면화된 스트림을 반환. 예를 들어, map으로 어떤 리스트 배열을 stream화 시켰다면, 반환되는 것은 stream의 stream이었을것. 이때 flatmap을 사용하면 하나의 stream으로 합쳐져서 반환된다


중간곰

5장 문제
아래 코드의 결과를 눈으로 예측해보세요~

(1번)
Stream.iterate(0, n -> n + 1)
        .skip(5)
        .limit(10) 
        .filter( n -> n % 2 == 0)
        .skip(1)
        .limit(3)
        .skip(1)
        .forEach(System.out::println);
(2번)
Stream.iterate(0, n -> (n % 2 == 0), n -> n + 1)
        .limit(10)
        .forEach(System.out::println);

나의 답

더보기
  1. 10 12
  2. 0

완태

5장 문제
아래 사칙 연산중, stream(), parallelStream() 의 결과가 다른 경우는 언제일까요?

List<Double> doubles = Arrays.asList(1.0,2.0,3.0,4.0);
//plus
doubles.stream().reduce(0.0, (a, b) -> (a+b))
doubles.parallelStream().reduce(0.0, (a, b) -> (a+b))
//minus
doubles.stream().reduce(0.0, (a, b) -> (a-b))
doubles.parallelStream().reduce(0.0, (a, b) -> (a-b))
//multiply
doubles.stream().reduce(1.0, (a, b) -> (a*b))
doubles.parallelStream().reduce(1.0, (a, b) -> (a*b))
//divide
doubles.stream().reduce(1.0, (a, b) -> (a/b))
doubles.parallelStream().reduce(1.0, (a, b) -> (a/b))

나의 답

더보기

- 와 /이다.

+와 *는 연산에 있어 값이 안전하다. 하지만 -의 경우, a-b에서 b가 -가 될 경우 +로 연산되는 경우가 발생하며 /의 경우, a/b에서 b가 0이어서 exception이 발생하는 문제가 발생할 수 있다.

 

 

웨지의 답

 

5번은 아껴먹을랬는데 같이 있으니 한번에 풀겠습니다아4번은 나봄과 같은 의견입니당!
5번같은 경우는 처음에 똑같을거 같아서 갸우뚱 하다가 집적 돌려봤는데, -  / 가 다른 결과가 나오네요.
왜그럴까? 하다가 아! 음수의 마이너스는 플러스가 되는구나, 나누기도 마찬가지로 나누기의 나누기는 곱하기가 되는구나,

(1-2) - (3-4) != -10
(1/2) / (3/4) != 1/24

실행순서에 따라 달라질 수 있음을 이해했습니당


검프

5장 ——-
카드 덱을 만들려고 한다.
현재 2개의 리스트는 준비가 되어있다. 이를 이용하여 의미있는 카드 이름을 만들고 싶다.
아래코드는 2중 for문이 들어가 메모리 걱정에 잠에 못들게 한다.
이를 flatMap을 사용하여 리팩토링 해보자 ㅎㅎ

public class Application {
    public static void main(String[] args) {
        List<String> symbols = Arrays.asList("스페이드", "하트", "다이아몬드", "클로버");
        List<String> numbers = Arrays.asList("A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K");
        List<String> cards = new ArrayList<>();
        for (String symbol : symbols) {
            for (String number : numbers) {
                cards.add(symbol + number);
            }
        }
		System.out.println("cards = " + cards);
    }
}

나의 답

더보기
public class Application {
    public static void main(String[] args) {
        List<String> symbols = Arrays.asList("스페이드", "하트", "다이아몬드", "클로버");
        List<String> numbers = Arrays.asList("A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K");
        List<String> cards = symbols.stream()
                .flatMap(symbol -> numbers.stream()
                        .map(number -> symbol + number))
                .collect(toList());
        System.out.println("cards = " + cards);
    }
}

파즈

5장
기본형 특화 스트림은 박싱/언박싱 비용을 줄여주기 때문에 굉장히 유용하다고 볼 수 있다.
그렇다면 기본형 Optional은 어떠할 것 같은지 작성해보시오~~

 

나의 답

더보기

Optional을 사용하는 순간, 레퍼클래스이든 기본형 클래스이든 어쨌든 박싱이 발생한다. 따라서 둘의 성능차이는 없다고 생각된다.


찰리

5장 문제
아래 보기의 참, 거짓을 평가하고 거짓이라면 간단한 이유를 말씀해주세요

A. findAny, findFirst, anyMatch, allMatch, limit 는 쇼트서킷 연산이다.
B. sorted, distinct, reduce 는 연산을 하려면 모든 요소가 버퍼에 추가되어 있는 상태에서 해야하기 때문에 연산을 수행하는데 필요한 저장소의 크기는 정해져있지 않다.
C. IntStream은 객체 스트림으로 복원할 수 없다.
D. IntStream의 range메서드를 range(0, 100)  라고 호출했을때 범위는 0~99이다.
E. 스트림의 필터링 메서드인 takeWhile, dropWhile 메서드는 Java 9부터 사용할 수 있다.

 

나의 답

더보기

A. 참

B. 거짓, reduce는 바운드 연산이다. 누적되며 연산되기에 한정된 자원으로 연산 가능하다.

C. 거짓, boxed를 통해 복원 가능

D. 참

E. 참


다니

아래 코드는 종료되지 않는 무한 스트림입니다.

  1. 스트림이 조건을 충족했을 때 종료되도록 코드를 수정해주세요 ! (정답은 한 개 이상일 수 있습니다 !)
  2. 코드를 실행했을 때 어떻게 출력되는지 결과를 작성해주세요 ~!
IntStream.iterate(10, n -> n * 2)
	.filter(n -> n < 30000)
	.forEach(System.out::println);

나의 답

더보기
IntStream.iterate(10, n -> n < 30000, n -> n * 2)
	.forEach(System.out::println);

10, 20, 40, 80.. 으로 3만 아래까지 출력됨


김김

5장 문제함수형 프로그래밍에서 자주 쓰이는 fold에 매칭되는 reduce는 참으로 유용하죠. 근데 자바에서 사용할 때에는 몇가지 유념할 점이 있습니다.

Stream.of(1,2,3,4).reduce(Integer::sum);

위와 같은 형태의 문장은 단순히 10을 리턴하는 것이 아니라 Optional<Integer>의 형태로 리턴합니다.
그 이유는 무엇이고, int형 변수로 리턴하도록 하도록 코드를 수정한다면, 어떻게 바꾸어야할까요??

 

나의 답

더보기

인풋이 빈 스트림일 경우 null을 리턴할 가능성이 있다. 따럿 Optinal로 그 해결책을 클라이언트쪽으로 떠넘긴다.

int변수로 리턴시키기 위해서는 reduce의 초기값을 설정하면 된다.

reduce(0, Integer::sum);

댓글