✍️ 메서드 레퍼런스
만약 람다 표현식이 하는 일이 기존에 있는 메서드 또는 생성자를 호출하는 거라면, 메서드 레퍼런스를 사용해서 매우 간결하게 표현할 수 있다.
참조하려는 메서드의 형태에 따라 그 방식이 서로 다르다.
스태틱 메서드의 참조 방식
- 타입::스태틱 메서드
특정 객체의 인스턴스 메서드 참조 방식
- 객체 레퍼런스::인스턴스 메서드
생성자 참조 방식
- 타입::new
임의 객체의 인스턴스 메서드 참조 방식
- 타입::인스턴스 메서드
🍊 메서드 레퍼런스 예제
Person 클래스엔 서로 다른 형태의 메서드들이 존재한다.
인자가 없는 생성자, 인자를 하나 받는 생성자, non-static public 메서드, static 메서드
public class Person {
private String name;
// 인자가 없는 생성자
public Person() {
}
// name을 받는 생성자
public Person(String name) {
this.name = name;
}
// name에게 hello 인사하는 메서드
public String hello(String name) {
return "Hello " + name;
}
// name에게 hi 인사하는 static 메서드
public static String hi(String name) {
return "Hi " + name;
}
}
스태틱 메서드 참조
타입::스태틱 메서드
public static void main(String[] args) {
{
Function<String, String> hi = name -> "Hi " + name;
System.out.println(hi.apply("John"));
}
{
Function<String, String> hi = Person::hi;
System.out.println(hi.apply("John"));
}
}
// Hi John
// Hi John
특정 객체의 인스턴스 메서드 참조
객체 레퍼런스::인스턴스 메서드
public static void main(String[] args) {
{
Function<String, String> hello = name -> "Hello " + name;
System.out.println(hello.apply("John"));
}
{
Person person = new Person();
Function<String, String> hello = person::hello;
System.out.println(hello.apply("John"));
}
}
// Hello John
// Hello John
생성자 참조
타입::new
인자가 없는 생성자
public static void main(String[] args) {
{
Supplier<Person> personCtor = () -> new Person();
Person person = personCtor.get();
System.out.println(person.name);
}
{
Supplier<Person> personCtor = Person::new;
Person person = personCtor.get();
System.out.println(person.name);
}
}
// default
// default
인자가 있는 생성자
public static void main(String[] args) {
{
Function<String, Person> personCtor = (name) -> new Person(name);
Person person = personCtor.apply("Kang");
System.out.println(person.name);
}
{
Function<String, Person> personCtor = Person::new;
Person person = personCtor.apply("Kang");
System.out.println(person.name);
}
}
// Kang
// Kang
재밌는 점은 인자가 없는 생성자, 인자가 있는 생성자 모두 Person::new를 사용한다.
코드상으론 동일하지만 서로 다른 생성자를 사용한다.
임의 객체의 인스턴스 메서드 참조
타입::인스턴스 메서드
마지막으로 임의 객체의 인스턴스 메서드 참조 방식을 알아볼 텐데 다소 설명이 필요한 부분이 있어서 마지막 파트에서 정리하려 한다.
배열을 정렬함에 있어서 sort 메서드를 사용할 수 있는데, 두 번째 인자로 Comparator를 받는다.
아래처럼 익명 구현 객체를 이용해서 구현할 수도 있다.
String[] names = {"John", "Peter", "Kang"};
Arrays.sort(names, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
// TODO Auto-generated method stub
return 0;
}
});
자바 8부턴 Comparator가 함수형 인터페이스로 바뀌게 되면서 익명 구현 객체 대신 람다 표현식을 사용할 수 있게 됐고 람다 표현식을 사용할 수 있으니 메서드 레퍼런스도 사용할 수 있다.
어쨌든, 다시 본론으로 와서 메서드 레퍼런스를 사용하면 다음과 같이 코드를 작성할 수 있다.
String[] names = {"John", "Peter", "Kang"};
Arrays.sort(names, String::compareToIgnoreCase); // 대소문자 구분없이 String 비교
그런데 조금 이상한 부분이 있다. Comparator의 추상 메서드인 compare는 두 개의 인자를 받는데, compareToIgnoreCase는 한 개의 인자만 받는다. 어째서 가능한 걸까?
public int compareToIgnoreCase(String str) {
return CASE_INSENSITIVE_ORDER.compare(this, str);
}
임의 객체의 인스턴스 메서드를 참조하는 방식엔 약간의 특이점이 존재할 수밖에 없는데, 말 그대로 "임의" 객체의 인스턴스 메서드를 참조하므로 특정 객체를 외부에서 받아와야 한다.
예를 들어
메서드 레퍼런스로 다음과 같이 코드를 작성하면 String::compareToIgnoreCase는 두 개의 인자를 받는데, 첫 번째 인자가 메서드를 호출할 객체가 되고 두 번째 인자는 호출한 메서드에 넘겨질 매개변수가 된다.
쉽게 말하면 String::compareToIgnoreCase는 (x, y) -> x.compareToIgnoreCase(y)와 동일하다.
'Java > Java 8' 카테고리의 다른 글
[Java8] Chapter 3-1. Stream API (1) (0) | 2022.02.18 |
---|---|
[Java8] Chapter 2-1. 인터페이스 default, static 메서드 (0) | 2022.02.17 |
[Java8] Chapter 1-3. 람다 표현식과 변수 캡쳐 (0) | 2022.02.08 |
[Java8] Chapter 1-2. Java에서 제공하는 함수형 인터페이스 (0) | 2022.02.07 |
[Java8] Chapter 1-1. 함수형 인터페이스와 람다 표현식 (0) | 2022.02.02 |