[Java] Stream API 활용하기

728x90

안녕하세요 🤚

오늘은 모던 자바인 액션 책에 있는 스트림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장 실전 연습

728x90