반복하는 동안 변환하기
튜토리얼 시리즈의 이전 글에서는 명령형 스타일에서 if 또는 조건문이 포함된 루프를 함수형으로 변환하는 방법을 살펴봤습니다. 이번 글에서는 데이터를 변환하는 명령형 스타일 반복을 함수형으로 변환하는 방법을 살펴보겠습니다. 또한 데이터를 변환하는 코드와 변환 전에 선택 요소를 선택하는 코드를 혼합하는 코드도 리팩터링해 보겠습니다.
명령형 루프에서 데이터를 변환할 때마다 함수형 스타일로 map() 함수를 사용할 수 있습니다. 방법을 살펴보겠습니다.
명령형에서 함수형 스타일로 전환하기
다음은 foreach를 사용하여 이름 컬렉션을 대문자로 변환하는 반복의 예입니다:
List<String> names = List.of("Jack", "Paula", "Kate", "Peter");
for(String name: names) {
System.out.println(name.toUpperCase());
}반복의 각 단계에서 name 변수는 새 값에 바인딩됩니다. 반복이 주어진 컬렉션의 한 요소에서 다음 요소로 진행됨에 따라 각 이름은 toUpperCase() 함수를 사용하여 대문자로 변환되고 결과 값이 인쇄됩니다. 이전 글에서 stream() 내부 반복을 사용하여 명령형 스타일인 foreach를 함수형으로 변환하는 방법을 이미 살펴봤습니다. 앞에서 살펴본 내용을 그대로 적용하면 forEach에 전달된 람다가 변환과 인쇄를 모두 수행하므로 결과 함수형 스타일 코드가 다소 복잡해질 수 있습니다:
List<String> names = List.of("Jack", "Paula", "Kate", "Peter");
names.forEach(name -> System.out.println(name.toUpperCase())); //Don't do this위의 함수형 스타일 코드는 명령형 스타일 코드와 동일한 결과를 생성하지만, forEach() 함수에 전달된 람다는 일관성이 없고 읽기 어렵고 변경하기 어렵습니다.
위의 명령형 스타일 코드를 함수형으로 리팩토링하기 전에 먼저 명령형 스타일을 또 다른 명령형 스타일 구현으로 리팩토링하여 각 줄의 일관성을 더 높여야 합니다(예: 다음과 같이):
List<String> names = List.of("Jack", "Paula", "Kate", "Peter");
for(String name: names) {
String nameInUpperCase = name.toUpperCase();
System.out.println(nameInUpperCase);
}이 시리즈의 이전 글에서 for가 stream()으로 바뀔 수 있고 forEach() 내에서 값의 인쇄를 수행할 수 있다는 것을 알았습니다. 이제 변환, 즉 toUpperCase() 함수에 대한 호출이 남았습니다. 이러한 변환은 stream()의 map() 연산을 사용하여 수행할 수 있습니다.
List<String> names = List.of("Jack", "Paula", "Kate", "Peter");
names.stream()
.map(name -> name.toUpperCase())
.forEach(nameInUpperCase -> System.out.println(nameInUpperCase));map() 연산은 map()에 전달된 람다 표현식 내에서 호출된 함수에 따라 데이터를 다른 값으로 변환합니다. 이 예제에서는 각 이름이 대문자 값으로 변환됩니다. 그런 다음 변환된 값은 forEach()에 전달된 람다 표현식 내에서 출력됩니다.
다음과 같이 람다 표현식 대신 메서드 참조를 사용하면 코드를 좀 더 간결하게 만들 수 있습니다:
List<String> names = List.of("Jack", "Paula", "Kate", "Peter");
names.stream()
.map(String::toUpperCase)
.forEach(System.out::println);map() 함수를 사용하여 데이터 컬렉션을 반복하면서 데이터를 변환할 수 있습니다.
변형할 요소 선택하기
반복 도중에 특정 조건에 따라 컬렉션에서 일부 값을 선택하고 해당 요소에만 변환을 적용하고 싶다고 가정해 보겠습니다. 예를 들어 길이가 4인 이름만 변환하여 인쇄하고 싶다면 어떻게 해야 할까요? 명령형 스타일에서는 다음과 같이 할 수 있습니다:
List<String> names = List.of("Jack", "Paula", "Kate", "Peter");
for(String name: names) {
if(name.length() == 4) {
System.out.println(name.toUpperCase());
}
}명령형 스타일 if는 함수형 스타일에서 filter() 함수로 리팩터링할 수 있다는 것을 이미 알고 있습니다. filter() 연산 뒤에 map()을 사용하여 다음과 같이 변환을 수행할 수 있습니다:
List<String> names = List.of("Jack", "Paula", "Kate", "Peter");
names.stream()
.filter(name -> name.length() == 4)
.map(String::toUpperCase)
.forEach(System.out::println);filter() 함수는 원하지 않는 데이터를 버리고 원하는 값만 전달합니다. map() 함수는 필터를 거친 후 표시되는 값을 변환합니다.
매핑하기
for 루프 내에서 데이터 변환이 필요한 경우 map() 함수를 사용하여 함수형으로 변환을 수행하세요. 또한 루프 본문에 if 문이 있어 일부 값을 선택적으로 변환하는 경우 map() 메서드를 사용하기 전에 stream() API를 filter() 메서드 호출과 함께 사용하세요.