티스토리 뷰

자바 8에는 다양한 기술들을 살펴보려고 하는데, 그 세 번째는 메서드 레퍼런스이다.

람다가 하는 일이 기존 메서드 또는 생성자를 호출하는 거라면, 메서드 레퍼런스를 사용해서 매우 간결하게 표현할 수 있다.

메서드 레퍼런스 실습을 위해 간단한 클래스를 작성하였다.

public class Greeting {
    private String name;

    public Greeting() {
    }

    public Greeting(String name) {
        this.name = name;
    }

    public String hello(String name) {
        return "hello " + name;
    }

    public static String hi(String name) {
        return "hi " + name;
    }

    public String hello() {
        return "hello " + this.name;
    }

}

위 클래스에는 생성자와 인스턴스 메서드, 스태틱 메서드가 존재한다.

이제 위 Greeting이라는 클래스를 사용해보는 예제 코드를 살펴보자.

스태틱 메서드 참조

Greeting 클래스의 스태틱 메서드인 hi를 사용해보자.

람다 표현식을 사용한 코드와 비교해서 살펴보자.

import java.util.function.*;

public class App {
    public static void main(String[] args) {
        // 람다 표현식
        UnaryOperator<String> hiByLambda = (str) -> "hi " + str;
        UnaryOperator<String> hiByMethodReference = Greeting::hi;
        System.out.println(hiByMethodReference.apply("eric"));
    }
}

특정 객체의 인스턴스 메서드 참조

import java.util.function.*;

public class App {
    public static void main(String[] args) {
        Greeting greeting = new Greeting();
        UnaryOperator<String> hiByMethodReference = greeting::hello;
        System.out.println(hiByMethodReference.apply("eric"));
    }
}

생성자 참조

import java.util.function.*;

public class App {
    public static void main(String[] args) {

        // 빈 생성자
        Supplier<Greeting> supplier = Greeting::new;
        System.out.println(supplier.get().hi("eric"));

				// name을 받는 생성자
        Function<String, Greeting> ericGreeting = Greeting::new;
        System.out.println(ericGreeting.apply("eric").hello());
    }
}

위 생성자 참조는 getter를 통해서 파악할 수 있다.

그 전에는 파악하기 어려움.

임의 객체의 인스턴스 메서드 참조

먼저, Comparator를 익명 클래스로 구현한 코드이다.

import java.util.Arrays;
import java.util.Comparator;

public class App {
    public static void main(String[] args) {
        String[] names = {"eric", "kwon", "keesun"};
        Arrays.sort(names, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return 0;
            }
        });
    }
}

자바 8부터는 Comparator 인터페이스에 스태틱 메서드와 default 메서드가 추가되었다.

참고로, Comparator는 함수형 인터페이스이다.

⇒ Comparator를 들어가보면 FunctionalInterface 애너테이션이 붙어있음.

즉, Comparator는 함수형 인터페이스이므로 Comparator를 익명 클래스로 구현하는 대신 람다 표현식을 쓸 수 있다.

import java.util.Arrays;

public class App {
    public static void main(String[] args) {
        String[] names = {"eric", "kwon", "keesun"};
        Arrays.sort(names, (o1, o2) -> 0);
    }
}

다음은 메서드 레퍼런스를 활용한 코드를 살펴보자.

코드를 살펴보기 전에 위에서 Comparator에는 다양한 스태틱 메서드와 default 메서드가 추가되었다고 했다.

그 중 예로 사용할 메서드는 compareToIgnoreCase이다.

String을 비교하여 int값을 리턴해주는 default 메서드이다.

import java.util.Arrays;
import java.util.Comparator;

public class App {
    public static void main(String[] args) {
        String[] names = {"eric", "kwon", "keesun"};
        Arrays.sort(names, String::compareToIgnoreCase);
        System.out.println(Arrays.toString(names));
    }
}

// 출력 결과
[eric, keesun, kwon]

effective java 아이템 [43]에서는 람다보다는 메서드 레퍼런스를 사용하라고 권고한다.

람다를 사용하는 가장 큰 이유는 간결함인데 이를 더 간결하게 만드는 것이 메서드 레퍼런스이다.

 

하지만 어떤 람다에서는 매개변수의 이름 자체가 프로그래머에게 좋은 가이드가 되기도 한다.

이런 람다는 길이는 더 길지만 메서드 참조보다 읽기 쉽고 유지보수도 쉬울 수 있다.

람다로 할 수 없는 일이라면 메서드 참조로도 할 수 없다.

그렇더라도 메서드 참조를 사용하는 편이 보통은 더 짧고 간결하므로, 람다로 구현했을 때 너무 길거나 복잡하다면 메서드 참조가 좋은 대안이 되어준다.

 

대표 IDE인 Intellij에서도 대체할 것을 권고하는 편인데 권고를 무조건적으로 따라야하는 것은 아니다.

예를 들어 다음 코드가 GoshThisClassNameIsHumongous라는 클래스 안에 있다고 해보자.

service.execute(GoshThisClassNameIsHumongous::action);

이를 람다로 대체하면 다음처럼 된다.

service.execute(() -> action());

메서드 참조 쪽은 더 짧지도, 더 명확하지도 않다. 따라서 람다 쪽이 더 낫다는 결론이 나온다.

같은 선상에서 java.util.function 패키지가 제공하는 제네릭 정적 팩터리 메서드인 Function.identity()를 사용하기보다는 똑같은 기능의 람다(x → x)를 직접 사용하는 편이 코드도 짧고 명확하다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
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 30
글 보관함