안녕하세요 🤚
오늘은 모던 자바인 액션 책에 있는 스트림API 활용하는 실전 문제를 직접 풀어보며
Stream API에 대한 이해도를 높여보고자 합니다.
위 과정은 모던 자바 인 액션 에 있는 챕터에 실전문제중 하나 이며, 자세한 내용은 책을 참고해주시면 감사하겠습니다.
문제를 보기전에 아래 코드는 사전에 작성을 해둬야하는 코드 입니다
public class Trader {
private final String name;
private final String city;
public Trader (String name, String city) {
this.name = name;
this.city = city;
}
public String getName () {
return name;
}
public String getCity () {
return city;
}
@Override
public String toString () {
return "Trader{" +
"name='" + name + '\'' +
", city='" + city + '\'' +
'}';
}
}
public class Transaction {
private final Trader trader;
private final int year;
private final int value;
public Transaction (Trader trader, int year, int value) {
this.trader = trader;
this.year = year;
this.value = value;
}
public Trader getTrader () {
return trader;
}
public int getYear () {
return year;
}
public int getValue () {
return value;
}
@Override
public String toString () {
return "Transaction{" +
"trader=" + trader +
", year=" + year +
", value=" + value +
'}';
}
}
import java.util.Arrays;
import java.util.List;
public class Test {
public static void main (String[] args) {
Trader raoul = new Trader("Raoul", "Cambridge");
Trader mario = new Trader("Mario", "Milan");
Trader alan = new Trader("Alan", "Cambridge");
Trader brian = new Trader("Brian", "Cambridge");
List<Transaction> transactions = Arrays.asList(
new Transaction(brian,2011,300),
new Transaction(raoul,2012,1000),
new Transaction(raoul,2011,400),
new Transaction(mario,2012,710),
new Transaction(mario, 2012, 700),
new Transaction(alan,2012,950)
);
}
}
이제 사전 작업이 끝났으니 직접 문제를 풀어보겠습니다.
1) 2011년에 일어난 모든 트랜잭션을 찾아 값을 오름차순으로 정리하시오
<내 코드>
List<Transaction> list = transactions.stream()
.filter(t -> t.getYear() == 2011)
.sorted()
.toList();
<정답 코드>
List<Transaction> list = transactions.stream()
.filter(t -> t.getYear() == 2011)
.sorted(Comparator.comparing(Transaction::getValue))
.toList();
sorted 안에 정렬은 어떤식으로 넣어야 할지 방법을 몰랐다가, 위 문제를 통해 깨닫게 되었습니다.
2) 거래가자 근무하는 모든 도시를 중복 없이 나열하시오
<내 코드 == 정답 코드>
List<Transaction> list = transactions.stream()
.map(t -> t.getTrader().getCity())
.distinct()
.toList();
하지만 위 처럼 distinct() 메소드를 사용해서 함수를 풀어가도 되구 다른 방법으로는
Set<String> list = transactions.stream()
.map(t -> t.getTrader().getCity())
.collect(toSet());
위 코드처럼 Set 컬렉션을 사용해서도 가능하다.
3) 케임브리지에서 근무하는 모든 거래자를 찾아서 이름순으로 정렬하시오
<내 코드>
List<Trader> cambridge = transactions.stream()
.map(t -> t.getTrader())
.filter(t -> t.getCity().equals("Cambridge"))
.distinct()
.sorted()
.toList();
<정답 코드>
List<Trader> cambridge = transactions.stream()
.map(Transaction::getTrader) // 트랜잭션의 모든 거래자 추출
.filter(t -> t.getCity().equals("Cambridge"))
.distinct()
.sorted(Comparator.comparing(Trader::getName))
.toList();
이번에도 sorted 정렬안에 어떤식으로 정렬을 넣어야 할지 몰라서 틀려버렸다ㅠㅠ
4) 모든 거래자의 이름을 알파벳순으로 정렬해서 반환하시오
<내 코드>
String reduce = transactions.stream()
.map(t -> t.getTrader().getName())// 모든 거래자명을 문자열 스트림으로 추출
.distinct()
.sorted(Comparator.comparing( // ??))
<정답 코드>
String reduce = transactions.stream()
.map(t -> t.getTrader().getName())
.distinct() // 중복 제거
.sorted() // // 이름을 알파벳 순으로 정렬
.reduce("", (n1, n2) -> n1 + n2);
위 코드보다 조금더 효율이 좋은 코드가 있다.
String reduce = transactions.stream()
.map(t -> t.getTrader().getName())
.distinct()
.sorted()
.collect(joining());
5) 밀라노에 거래자가 있는가?
<내 코드 == 정답 코드>
boolean milan = transactions.stream()
.anyMatch(t -> t.getTrader().getCity().equals("Milan"));
6) 케임브리지에 거주하는 거래자의 모든 트랜잭션 값을 출력하시오
<내 코드>
transactions.stream()
.filter(t -> t.getTrader().getCity().equals("Cambridge"))
.map(Transaction::getValue)
.forEach(s -> System.out.println(s));
<정답 코드>
transactions.stream()
.filter(t -> "Cambridge".equals(t.getTrader().getCity()))
.map(Transaction::getValue)
.forEach(System.out::println);
내 코드랑 살짝 다르긴한데 결국에 출력하면 같은 값을 호출할 것으로 추정된다.
7) 전체 트랜잭션 중 최댓값은 얼마인가?
<내 코드>
Optional<Integer> max = transactions.stream()
.map(Transaction::getValue)
.max(// 최댓값 비교하는 로직을 넣어야함..);
<정답 코드>
Optional<Integer> max = transactions.stream()
.map(Transaction::getValue)
.reduce(Integer::max);
reduce 를 통해서 결과 스트림의 최댓값을 계산해야 했다..
8) 전체 트랜잭션 중 최솟값은 얼마인가?
<내 코드>
transactions.stream()
.map(Transaction::getValue)
.min(// 최솟값 비교 로직..)
<정답 코드>
Optional<Transaction> min = transactions.stream()
.reduce((t1, t2) -> t1.getValue() < t2.getValue() ? t1 : t2);
당연히 최솟값을 찾는거니 min 함수를 쓸 줄 알았는데, reduce를 통해 구현을 했으며, 삼항연산자를 통해서 최솟값을 비교하면서 찾는 로직이였다.
이렇게 퀴즈는 끝났습니다.
아직 위 메소드들을 내부 구현과 어떻게 로직이 구성되어 있는지를 파악하지 못하여 문제를 푸는데 많은 어려움을 겪었습니다.
위 문제들을 해결하면서, 스트림API 에 대한 이해도가 향상되었으며, 제가 아직 많이 부족하다는 걸 다시 깨닫게 되었으며
실무 코드에서도 스트림 코드를 녹여내기 위해 피나는 노력을 해야 겠다고 생각이 들었습니다.
읽어주셔서 감사합니다👍🏽
ref : 모던자바인액션 5장 실전 연습