자바8 람다식: 자바(Java): 람다식 (Lambda Expression) 기초 (Java 8 이상)
콜론 두개 (::
– 이중 콜론 연산자)의 정식 명칭은 메소드 참조 표현식(method reference expression)이며, 결론부터 말하자면 람다식에서 파라미터를 중복해서 쓰기 싫을 때 사용합니다.
말 그대로 람다 표현식(expression)에서만 사용 가능하고, 사용 방법은 [인스턴스]::[메소드명(또는 new)]
으로 사용하는데, 예제를 통해 보는 것이 이해가 빠릅니다. 스태틱 메소드인 경우 인스턴스 대신 클래스 이름으로 사용할 수 있습니다.
예1) 리스트를 순회하면서 println을 하고자 할 때
import java.util.Arrays; import java.util.List; public class DoubleColonTest { public static void main(String[] args) { List<String> names = Arrays.asList("김갑순", "김갑돌"); // x를 건네고 받는 과정에서 x를 두 번 적게 된다. names.forEach(x -> System.out.println(x)); // 아예 x들을 빼버리고 아래와 같이 작성할 수 있다. names.forEach(System.out::println); } }
forEach
의 첫 번째 구문은 람다식이 x
를 파라미터로 넘기고 println(x)
이 그 파라미터를 받는 과정에서 x
를 두 번 사용하게 됩니다. 람다식이 건네는 파라미터와 받는 쪽의 파라미터가 동일할 때, 두 번째 구문처럼 System.out::println
으로 줄여쓸 수 있습니다.
사용 방법이 [인스턴스]::[메소드명(또는 new)]
라고 했는데, 여기서는 System.out이 인스턴스 부분이며, 그 인스턴스의 메소드 중 하나인 println이 메소드명으로 사용되었습니다.
참고로 System.out은 PrintStream 인스턴스를 반환합니다.(API 문서)
예2) Stream의 map()을 사용해 새로운 스트림을 생성하고자 할 때
import java.util.Arrays; import java.util.List; public class DoubleColonTest { public String addNim(String s) { return s + "님"; } public static void main(String[] args) { List<String> names = Arrays.asList("김갑순", "김갑돌");; DoubleColonTest dct = new DoubleColonTest(); names.stream().map(x -> dct.addNim(x)).forEach(System.out::println); // 적용 전 names.stream().map(dct::addNim).forEach(System.out::println); // 적용 후 } }
x -> dct.addNim(x)
을 dct:addNim
로 바꿀 수 있습니다.
만약 addNim()
이 스태틱 메소드인 경우 다음과 같이 사용 가능합니다.
names.stream().map(DoubleColonTest::addNim).forEach(System.out::println);
예3) 생성자가 파라미터 한 개로 이루어진 DTO의 배열을 생성하고자 할 때
public class Dog { private String name; private String species; // ...setter // ...getter @Override public String toString() { return "Dog{" + "name='" + name + '\'' + ", species='" + species + '\'' + '}'; } }
import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; public class DoubleColonTest { public static String addNim(String s) { return s + "님"; } public static void main(String[] args) { List<String> names = Arrays.asList("김갑순", "김갑돌"); List<Dog> dogs1 = names.stream() .map(x -> new Dog(x)) // 적용 전 .collect(Collectors.toList()); List<Dog> dogs2 = names.stream() .map(Dog::new) // 적용 후 .collect(Collectors.toList()); dogs2.forEach(x -> x.setSpecies("이탈리안 그레이 하운드")); System.out.println(dogs1); System.out.println(dogs2); } }
x -> new Dog(x);
도 위와 같이 Dog::new
로 축약할 수 있습니다. 이것은 생성자 참조 표현식이라고도 합니다.
게터를 참조 표현식으로 변환: 스트림을 해시맵으로 그룹화하는 예제
... .stream() .collect(Collectors.groupingBy(Dog::getSpecies, HashMap::new, toList())); // x -> x.getSpecies() 가 Dog::getSpecies 와 동일
x -> x.getSpecies()
라는 람다식이 필요한 경우 Dog::getSpecies
로 줄여쓸 수 있습니다.
예4) 함수형 인터페이스를 구현할 때 파라미터의 종류와 개수가 같으면 사용 가능
@FunctionalInterface public interface StringToDog { public String convert(String name, String species, int price); }
public class Dog { private String name; private String species; private int price; public static String introduce(String name, String species, int price) { return name + " : " + species + " : " + price; } // ............ }
import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; public class DoubleColonTest { public static void main(String[] args) { // 파라미터의 개수와 타입이 같다면 메소드 참고 표현식이 적용된다. StringToDog stringToDog1 = (name, species, price) -> Dog.introduce(name, species, price); StringToDog stringToDog2 = Dog::introduce; System.out.println(stringToDog1.convert("개똥이", "믹스", 100)); System.out.println(stringToDog2.convert("누렁이", "믹스", 1000)); } }
함수형 인터페이스를 구현할 때 람다식을 사용하는데 파라미터의 개수, 종류와 표현식에서 사용된 메소드의 파라미터 개수, 종류가 같다면 위와 같이 축약할 수 있습니다.
1개의 댓글
자바(Java) 8: 자바스크립트 람다 예제로 알아보는 Stream 사용법 - BGSMM · 2020년 7월 22일 6:36 오후
[…] 자바(Java) 8: 람다식에서 콜론 두개 (:: – 이중 콜론 연산자, 메소드 참조 … […]