자바 스트림의 7가지 활용 팁

스트림(Stream)은 여러 해 전 도입되었지만, Java 개발자들은 여전히 이 강력한 도구를 완전히 활용하지 못하고 있습니다. 이 글에서는 다음 프로젝트에 참고할 수 있는 유용한 스트림 활용 팁을 소개합니다.

아래 예제에서는 다음 클래스들을 사용할 것입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Getter
class Company {
private String name;
private Address address;
private List<Person> personList;
}

@Getter
class Person {
private Long id;
private String name;
}

@Getter
class Address {
private String street;
private City city;
}

@Getter
class City {
private String name;
private State state;
}

@Getter
class State {
private String name;
}

1. 메서드 참조를 사용하여 map 단순화하기

다음 코드는 회사들의 주소에서 도시 이름을 가져옵니다.

1
2
3
4
5
public List<String> getCityNames(List<Company> companyList){
return companyList.stream()
.map(company -> company.getAddress().getCity().getName())
.toList();
}

이를 더 가독성 있게 다음과 같이 변경할 수 있습니다.

1
2
3
4
5
6
7
public List<String> getCityNames(List<Company> companyList){
return companyList.stream()
.map(Company::getAddress)
.map(Address::getCity)
.map(City::getName)
.toList();
}

2. Null 체크하기

위 코드를 null 체크와 함께 작성하면 다음과 같습니다.

1
2
3
4
5
6
7
8
9
10
public List<String> getCityNames(List<Company> companyList){
return companyList.stream()
.map(Company::getAddress)
.filter(Objects::nonNull)
.map(Address::getCity)
.filter(Objects::nonNull)
.map(City::getName)
.filter(Objects::nonNull)
.toList();
}

3. 스트림을 단일 스트림으로 변환하기

다음 코드는 모든 회사로부터 사람 목록을 가져옵니다.

1
2
3
4
5
6
7
8
9
10
11
12
public List<Person> getAllPerson(List<Company> companyList){
// Person의 리스트를 가진 리스트를 만듭니다.
List<List<Person>> partialResult = companyList.stream()
.map(Company::getPersonList)
.toList();

// 각 Person 리스트를 결과에 추가합니다.
List<Person> result = new ArrayList<>();
partialResult.forEach(result::addAll);

return result;
}

위와 동일한 작업을 다음과 같이 할 수 있습니다.

1
2
3
4
5
6
public List<Person> getAllPerson(List<Company> companyList){
return companyList.stream()
.map(Company::getPersonList) // Stream<List<Person>>을 반환합니다.
.flatMap(List::stream) // Stream<Person>으로 변환합니다.
.toList();
}

4. 속성별 그룹화하기

다음 코드는 각 도시에 있는 회사 목록을 Map으로 반환합니다

1
2
3
4
public Map<City, List<Company>> getCompaniesByCity(List<Company> companyList){
return companyList.stream()
.collect(Collectors.groupingBy(company -> company.getAddress().getCity()));
}

5. 스트림에 특정 항목이 있는지 확인하기

다음 코드는 특정 도시에 회사가 있는지 확인합니다.

1
2
3
4
5
6
7
public boolean hasCompanyInCity(List<Company> companyList, String cityName){
return companyList.stream()
.map(Company::getAddress)
.map(Address::getCity)
.map(City::getName)
.anyMatch(cityName::equals);
}

특정 도시에 회사가 없는지를 확인하려면 noneMatch를 사용할 수 있습니다.

1
2
3
4
5
6
7
public boolean hasNoCompanyInCity(List<Company> companyList, String cityName){
return companyList.stream()
.map(Company::getAddress)
.map(Address::getCity)
.map(City::getName)
.noneMatch(cityName::equals);
}

6. 로깅하기

각 도시 이름을 반환할 때 로그를 기록하려면 peek 메서드를 사용할 수 있습니다.

1
2
3
4
5
6
7
8
public List<String> getCityNames(List<Company> companyList){
return companyList.stream()
.map(Company::getAddress)
.map(Address::getCity)
.map(City::getName)
.peek(cityName -> log.info(cityName))
.toList();
}

7. 고유한 도시 이름 가져오기

distinct를 사용해 스트림에서 중복된 도시 이름을 제거할 수 있습니다.

1
2
3
4
5
6
7
8
public List<String> getUniqueCityNames(List<Company> companyList){
return companyList.stream()
.map(Company::getAddress)
.map(Address::getCity)
.map(City::getName)
.distinct()
.toList();
}

결론

이 방법들을 통해 스트림을 보다 효과적으로 사용하고 코드의 가독성과 성능을 높일 수 있습니다.

Share