스트림(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){ List<List<Person>> partialResult = companyList.stream() .map(Company::getPersonList) .toList();
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) .flatMap(List::stream) .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(); }
|
결론
이 방법들을 통해 스트림을 보다 효과적으로 사용하고 코드의 가독성과 성능을 높일 수 있습니다.