언어(Language)/Java

[Java] 자바 메서드 레퍼런스(Method Reference) 개념 정리 및 활용

잇트루 2022. 9. 25. 02:00
반응형

메서드 레퍼런스란? (메서드 참조 : Method Reference)

메서드 레퍼런스는 람다식에서 불필요한 매개변수를 제거할 때 주로 사용한다.

즉, 람다식으로 더욱 간단해진 익명 객체를 보다 더 간단하게 사용할 수 있도록 하는 것이다.

 

람다식은 기본으로 내장된 람다식을 단순히 호출만 하는 경우가 많다.

(num1, num2) -> Math.max(num1, num2);

이와 같이 람다식을 활용하여 자바 라이브러리에서 제공하는 클래스 메서드를 활용하는 것이다.

이러한 경우, 입력값과 출력 값의 반환 타입을 쉽게 유추할 수 있기 때문에 입력값과 출력 값을 적는 것이 크게 중요하지 않게 되었다.

 

메서드 레퍼런스를 이용하면 이를 더욱 간결하게 처리할 수 있다.

// 클래스이름 :: 메서드이름
Math :: max; // 메서드 레퍼런스

메서드 레퍼런스는 람다식과 마찬가지로 인터페이스의 익명 구현 객체로 생성된다.

인터페이스의 추상 메서드가 어떤 매개변수를 가지고, 반환 타입이 무엇인지에 따라 달라진다.

 

따라서, 두 개의 int 타입을 매개변수로 받아 int 타입으로 반환하는 IntBinaryOperator 인터페이스와 메서드 레퍼런스를 활용할 수 있다.

IntBinaryOperator result = Math :: max;

메서드 레퍼런스는 정적 메서드, 인스턴스 메서드, 생성자 세 가지를 참조할 수 있다.

 

정적 메서드 레퍼런스

정적 메서드를 참조할 경우에는 클래스 이름 뒤에 :: 기호를 사용하여 정적 메서드 이름을 작성하여 사용할 수 있다.

클래스이름 :: 정적메서드이름

 

다음은 정적 메서드 참조 예제이다.

public class Calculator {
    public static int staticMethod(int x, int y) {
        return x + y;
    }
}
import java.util.function.IntBinaryOperator;

public class MethodReferences {
    public static void main(String[] args) throws Exception {
        IntBinaryOperator operator;
        // 정적 메서드 참조
        operator = Calculator::staticMethod;
        System.out.println(operator.applyAsInt(5, 10));
    }
}
// 출력
// 15

 

인스턴스 메서드 레퍼런스

인스턴스 메서드를 참조할 경우에는 객체를 생성한 뒤, 참조 변수 뒤에 :: 기호를 사용하여 인스턴스 메서드 이름을 작성하여 사용할 수 있다.

참조변수 :: 인스턴스메서드이름

 

다음은 인스턴스 메서드 참조 예제이다.

public class Calculator {
    public int instanceMethod(int x, int y) {
        return x + y;
    }
}
import java.util.function.IntBinaryOperator;

public class MethodReferences {
  public static void main(String[] args) throws Exception {
    IntBinaryOperator operator;
		// 인스턴스 메서드 참조
		Calculator calculator = new Calculator();
		operator = calculator::instanceMethod;
		System.out.println(operator.applyAsInt(5, 10));
	}
}
// 출력
// 15

 

생성자 레퍼런스

메서드 레퍼런스는 생성자 참조도 가능하다. 생성자를 참조한다는 것은 객체 생성을 의미한다.

메서드 호출로 구성된 람다식을 메서드 참조로 대치할 수 있듯이, 단순히 객체를 생성하고 리턴하도록 구성된 람다식은 생성자 참조로 대치가 가능하다.

 

람다식에서 객체를 생성하고 리턴하는 방식에는 다음과 같다.

(a, b) -> {return new 클래스이름(a, b);};

 

이를 생성자 레퍼런스는, 클래스 이름 뒤에 :: 기호를 붙이고 new 연산자를 기술하여 사용할 수 있다.

클래스이름 :: new

 

만약, 생성자가 오버로딩되어 여러 개가 존재할 경우, 컴파일러는 함수형 인터페이스의 추상 메서드와 동일한 매개 변수 타입과 개수를 가지고 있는 생성자를 찾아서 실행한다.

만약, 매개 변수 타입과 개수가 동일하지 않으면 컴파일 에러가 발생한다.

 

다음은 생성자 레퍼런스를 활용한 예제이다.

public class Member {
    private String name;
    private String id;

    // 매개변수가 없는 생성자
    public Member() {
        // 생성자 호출시 출력 문구
        System.out.println("Member() 생성자");
    }

    // 매개변수가 1개인 생성자
    public Member(String id) {
        // 생성자 호출시 출력 문구
        System.out.println("Member(String id) 생성자");
        this.id = id;
    }

    // 매개변수가 2개인 생성자
    public Member(String name, String id) {
        // 생성자 호출시 출력 문구
        System.out.println("Member(String name, String id) 생성자");
        this.id = id;
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public String getId() {
        return id;
    }
}
import java.util.function.BiFunction;
import java.util.function.Function;

class ConstructorReferenceEx {
    public static void main(String[] args) {
        // Function 함수형 인터페이스를 통한 생성자 레퍼런스
        Function<String, Member> function1 = Member::new;
        // Function 함수형 인터페이스의 apply() 메서드 사용
        Member member1 = function1.apply("id");

        // BiFunction 함수형 인터페이스를 통한 생성자 레퍼런스
        BiFunction<String, String, Member> function2 = Member::new;
        // BiFunction 함수형 인터페이스의 apply() 메서드 사용
        Member member2 = function2.apply("id", "name");
    }
}

// 출력
// Member(String id) 생성자
// Member(String name, String id) 생성자

다음과 같이 생성자 레퍼런스를 두 가지 방법으로 사용했지만, 입력된 매개변수에 따라 호출된 Member 생성자는 서로 다른 것이 호출되었음을 알 수 있다.

반응형