인프런 커뮤니티 질문&답변

흰머리오목눈이님의 프로필 이미지
흰머리오목눈이

작성한 질문수

나도코딩의 자바 기본편 - 풀코스 (20시간)

퀴즈 #10

질문 드립니다!

작성

·

452

1

 안녕하세요, 강사님. 강사님 도움 덕분에 1회차 한번씩 다 돌리고 2회차 다시 정주행 하면서 복습중입니다. 이제 이 것도 거의 끝나가네요. 다 강사님 덕분입니다. 😄

궁금한 것이 생겨 문의드립니다!

ArrayList<Customer> customer = new ArrayList<>();

customer.add(new Customer(20, "챈들러"));
customer.add(new Customer(42, "레이첼"));
customer.add(new Customer(21, "모니카"));
customer.add(new Customer(18, "벤자민"));
customer.add(new Customer(5, "제임스"));

customer.stream().map(x -> x.age >= 20 ? x.name + " 5000원" : x.name + " 무료" )
        .forEach(System.out::println);

위와 같은 코드가 있을 때. 최종 연산 forEach 에서는 어떤 기준으로 cumtomer 객체의 name 값을 출력해주는지 알 수 있을까요? (따로 x.name 을 출력하라는 코드를 작성한게 없어 보이는데 name 만 한거 같아서요!)

데이터를 전체 출력해주는 거였다면

챈들러 5000원 20

레이첼 5000원 42

모니카 5000원 21

벤자민 무료 18

제임스 무료 5

이렇게 출력됐어야 할 것 같아서요. 그리고 혹시 만약 마지막 최종연산 forEach 에서 list 에 담긴 객체의 특정 필드값만 순회하면서 출력하는 방법도 있을까요?

답변 2

2

나도코딩님의 프로필 이미지
나도코딩
지식공유자

안녕하세요?
2회차 정주행이라니, 학습에 대한 열의가 정말 대단하시네요 🤩 너무나 훌륭하십니다!!

먼저 첫 번째 질문에 대한 답을 드립니다.
스트림에서 map 은 데이터를 변환(가공)할 때 사용할 수 있는데요.

customer.stream()
    .map(x -> x.age >= 20 ? x.name + " 5000원" : x.name + " 무료" )
    .forEach(System.out::println);

위 코드를 하나씩 뜯어볼게요 😉

1) customer.stream().map(원하는 형태로 변환)
customer 리스트로부터 새로운 스트림을 생성하고 원하는 형태로 변환을 시도합니다.

2) x -> 조건? 참일 때 : 거짓일 때
각 요소에 대해서 조건을 확인하여 참일 때의 값, 또는 거짓일 때의 값으로 변환합니다.
이때 조건은 x.age >= 20 입니다.
참일 때는 x.name + " 5000원" 으로 변환합니다.
거짓일 때는 x.name + " 무료" 으로 변환합니다.
(중요) 이 곳에서 x.name 이라고 명시하였으므로 최종 연산에서는 age 등 다른 값들은 무시하고 Customer 객체의 name 값에 " 5000원" 또는 " 무료" 를 붙인 내용이 출력됩니다.

3) .forEach(System.out::println);
순회하면서 변환된 내용이 println 을 통해 출력됩니다.


두 번째 질문에 대한 답변입니다.
이 질문에 대한 답변 또한 처음 답변 드린 내용과 유사하며 .map() 을 사용하시면 됩니다. 괄호 안에 들어가는 내용을 잘 확인해주세요 👍

1) name 값만 출력하시려면 이렇게 할 수 있구요.

customer.stream().map(x -> x.name).forEach(System.out::println);

2) age 값만 출력하시려면 이렇게 할 수 있답니다.

customer.stream().map(x -> x.age).forEach(System.out::println);

각각의 실행 결과는 이렇습니다.

1) name 값만 출력

챈들러
레이첼
모니카
벤자민
제임스

2) age 값만 출력

50
42
21
18
5

이해에 도움되시길 바라겠습니다 😊
감사합니다.

강사님, 답변해주신 내용 잘 봤습니다.

한번 따라쳐보니 아래와 같은 결과를 확인했습니다.

  1. 가공되는 데이터가 있을 경우, 그 데이터가 출력된다.

            customer.stream().map(x -> x.age>= 20 ? x.name + "무료" : x.age + "무료")
                    .forEach(System.out::println);
  2. 가공되는 데이터가 없을 경우, x -> 다음 명시된 객체 필드값이 순회하면서 출력된다.

  3. .map 이 여러개가 있으면 어떤게 출력될까 궁금해서 해봤는데, 한개의 스트림은 하나의 데이터만 처리 가능 한 것처럼 보이네요ㅎㅎ (두번째 map 을 적으니 에러가 나는걸 보니..)

이번에도 친절한 답변 감사합니다!

나도코딩님의 프로필 이미지
나도코딩
지식공유자

3번에서 .map() 은 여러 번 사용이 가능합니다. 아래는 한 가지 예시인데요.

customer.stream()  // Stream<Customer>
        .map(x -> x.name + " 무료") // Stream<String>
        .map(x -> x + " 입장")
        .forEach(System.out::println);

처음 스트림을 생성하고 map 을 사용할 때는 Customer 객체의 모든 필드를 온전히 사용 가능하지만 .map(x -> x.name + " 무료") 를 거치게 되면 그 결과는 '챈들러 무료' 와 같은 문자열 형태가 됩니다. Customer 객체에는 age 가 있지만 문자열 객체에는 age 가 없기 때문에 .map(x -> x.age) 를 하게 되면 에러가 발생하는 것이죠. 대신 예제와 같이 문자열 결합하는 내용을 추가한다면 얼마든지 사용 가능합니다. 즉, 앞에서 .map() 을 통해 실행된 결과 자료형에 따라 뒤의 .map() 에서 할 수 있는 작업이 달라집니다. 주석으로 입력한 Stream<Customer> 및 Stream<String> 부분을 주의 깊게 봐주세요 😊

위 코드의 실행 결과는 이렇습니다.

챈들러 무료 입장
레이첼 무료 입장
모니카 무료 입장
벤자민 무료 입장
제임스 무료 입장

다른 예제로는 이런 것도 해볼 수 있습니다. 아래는 문자열 앞뒤로 공백이 있는 과일 이름을 담고 있는 리스트입니다. 이를 두 번의 .map() 작업을 통해 한 번은 공백을 제거 (trim 메소드 적용), 한 번은 대문자로 변환(toUpperCase 메소드 적용)하여 결과를 출력합니다.

List<String> fruits = Arrays.asList(" apple  ", "   banana ", " orange");
fruits.stream()
        .map(String::trim) // 공백 제거
        .map(String::toUpperCase) // 대문자로 변환
        .forEach(System.out::println);

실행 결과는 이렇습니다.

APPLE
BANANA
ORANGE

학습에 참고 부탁드려요 😊
감사합니다.

0

좋은 질문, 답변 감사합니다!

흰머리오목눈이님의 프로필 이미지
흰머리오목눈이

작성한 질문수

질문하기