이 포스팅의 코드 및 정보들은 강의를 들으며 정리한 내용을 토대로 작성한 것입니다.
람다 표현식을 구현할 때, 기존에 이미 있는 메서드를 참조하는 것. 즉, 그 메서드 자체를 Functional Interface의 구현체로 쓰게 되는 것이다.
문자열을 하나 넣어서 문자열을 받고자 하는
먼저 실습에 앞서 클래스와 메서드를 만들어놨다.
이를 구현하기 위해 Function<String, String>
을 사용할 수 있고, 입력값과 반환값이 같은 경우에는 UnaryOperator<String>
으로 줄여서 활용할 수 있다.
UnaryOperator<String> hola = (s) -> "hola " + s;
이 람다식이 하는 일은
Greeting 클래스에서 만든 Hola라는 static 메서드와 같다.
또한, static 메서드를 람다식에서 사용할 수도 있다.
즉, UnaryOperator의 구현체로 static 메서드를 사용하겠다는 것이다.
::(콜론 두 개)를 이용해서 메서드를 호출하는 것을 메서드 레퍼런스라고 한다.
Type::staticMethodName
이런 식으로 참조하면 된다.
특정한 인스턴스의 메서드를 사용하는, 즉 클래스 안에 들어있는 인스턴스 메서드를 사용하는 방법도 있다.
생성자를 호출할 때 리턴값은 객체의 타입이다.
입력값은 없는데 결과값은 있는 것. -> Supplier 인터페이스로 알아보겠다.
이렇게 생성만 해놓고 보면 아무 일도 일어나지 않는다. 이 자체로 새로운 인스턴스를 만드는 것은 아니다.
public static void main(String[] args) {
Supplier<Greeting> newGreeting = Greeting::new;
Greeting greeting = newGreeting.get();
}
Supplier 인터페이스에 있는 get()을 통해서 인스턴스를 만들 수 있다.
public static void main(String[] args) {
Greeting greeting = new Greeting();
UnaryOperator<String> hallo = greeting::hallo;
}
이 메서드를 참조하고 있는 UnaryOperator가 만들어진 것이지, 이 자체로는 인스턴스가 생성됐다고 볼 수 없다.
hallo.apply("bruce")
이런식으로 apply()를 통해서 새 인스턴스를 만들 수 있는 것이다.
apply를 통해서 bruce라는 값이 greeting이라는 인스턴스에 있는 hallo 메서드에 전달되고, 이반환 값을 가져와서 문자열이 출력된 것을 확인할 수 있다.
public Greeting(String name) {
this.name = name;
}
이런 생성자는 입력 값은 String, 반환 값은 Greeting이 된다.
Function 인터페이스와 Supplier 인터페이스는 같은 생성자를 쓰는 것 같지만, 서로 다른 생성자를 참조한다.
Function을 먼저 알아보면
public Greeting(String name) {
this.name = name;
}
Function 인터페이스는 문자열을 받는 생성자를 참조하고 있고
apply()에 bruce
를 넣어서 이를 출력한 것을 확인할 수 있다.
public Greeting() {}
반면에 Supplier는 문자열을 받지 않는 생성자를 참조하고 있다.
아무 이름도 부여하지 않은 채 getName()으로 이름을 반환하면 당연히 null이 출력된다.
Supplier 인터페이스를 통해서는 hallo() 메서드를 이용하여 이름을 출력한 것을 확인할 수 있다.
불특정 다수인 인스턴스의 특정 인스턴스 메서드를 참조하는 방법이다.
public static void main(String[] args) {
String[] names = {"bruce", "minsu", "spring"};
Arrays.sort(names, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return 0;
}
});
}
Arrays.sort의 두 번째 파라미터가 Comparator<>() {}
인 함수형 인터페이스이기 때문에, 이 자리에다가 람다를 넣을 수 있다.
Arrays.sort(names, (o1, o2) -> 0);
람다를 넣을 수 있다는 얘기는 메서드 레퍼런스를 쓸 수 있다는 것이다. 즉, 어떤 문자열이 다른 문자열하고 비교해서 int값을 넘겨주는 메서드를 참조할 수 있다.
String 클래스의 compareToIgnoreCase()로 실습을 해보겠다.
compareToIgnoreCase()는 자기자신의 문자열과 파라미터로 받은 문자열을 비교해서 int type을 넘겨준다.
public static void main(String[] args) {
String[] names = {"bruce", "minsu", "cheolsu"};
Arrays.sort(names, String::compareToIgnoreCase);
}
bruce가 (파라미터로 넘겨질) 뒤에 오는 minsu와 compareToIgnoreCase()로 비교해서 int 값을 반환하게 된다. 마찬가지로 minsu가 cheolsu랑 비교해서 int값을 리턴하는 식으로 동작하게 될 것이다.
String::compareToIgnoreCase
에다가 준 메서드 레퍼런스는 "bruce", "minsu", "cheolsu" 처럼 임의의 인스턴스를 거쳐가면서 compareToIgnoreCase라는 인스턴스 메서드를 사용하게 되는 것이다.
Arrays.toString(names)
을 통해서 이름들이 정렬된 것을 확인할 수 있다.