java

[Java] 메서드 참조

inhooo00 2025. 5. 20. 00:04

📍매개변수를 받아서, 그 매개변수로 같은 메서드를 호출해야할 때

public static void main(String[] args) {
          BinaryOperator<Integer> add1 = (x, y) -> add(x, y);
          BinaryOperator<Integer> add2 = (x, y) -> add(x, y);
          Integer result1 = add1.apply(1, 2);
          System.out.println("result1 = " + result1);
          Integer result2 = add2.apply(1, 2);
          System.out.println("result2 = " + result2);
      }
      static int add(int x, int y) {
          return x + y;
}

지금처럼 함수를 전달해야하는 상황에서 로직을 보자. add1, add2는 단순하게 매개변수를 받고, 그 매개변수로 add 메서드를 호출하는 로직이다. 이럴 때 메서드 참조를 사용할 수 있다.

public static void main(String[] args) {
          BinaryOperator<Integer> add1 = MethodRefStartV3::add; // (x, y) ->
  add(x, y)
          BinaryOperator<Integer> add2 = MethodRefStartV3::add; // (x, y) ->
add(x, y)
          Integer result1 = add1.apply(1, 2);
          System.out.println("result1 = " + result1);
          Integer result2 = add2.apply(1, 2);
          System.out.println("result2 = " + result2);
     
 }
      static int add(int x, int y) {
          return x + y;
}

여기서는 메서드 참조(Method Reference) 문법인 `클래스명::메서드명` 을 사용하여 `(x, y) -> add(x, y)` 라 는 람다를 더욱 간단하게 표현했다. 이는 내부적으로 (x, y) -> add(x, y)와 동일하게 작동한다.

 

메서드 참조의 장점

  • 메서드 참조를 사용하면 코드가 더욱 간결해지고, 가독성이 향상된다.
  •  더 이상 매개변수를 명시적으로 작성할 필요가 없다. 컴파일러가 자동으로 매개변수를 매칭한다.
  • 별도의 로직 분리와 함께 재사용성 역시 높아진다.

 

 

📍메서드 참조의 유형과 특징

1. 정적 메서드 참조

  • 설명: 이름 그대로 정적(static) 메서드를 참조

  • 문법: 클래스명::메서드명

  • : Math::max , Integer::parseInt 

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

  • 설명: 이름 그대로 특정 객체의 인스턴스 메서드를 참조

  • 문법: 객체명::인스턴스메서드명

  • person::introduce , person::getName 

3. 생성자 참조

  • 설명: 이름 그대로 생성자를 참조한다.

  • 문법: 클래스명::new

  • : Person::new

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

  • 설명: 첫 번째 매개변수(또는 해당 람다가 받을 대상)가 그 메서드를 호출하는 객체가 된다.
  • 문법: 클래스명::인스턴스 메서드명

  • : Person::introduce , 같은 람다: (Person p) -> p.introduce()

메서드 참조에서 ()를 사용하지 않는 이유

메서드 참조의 문법을 잘 보면 뒤에 메서드명 뒤에 `()` 가 없다.
예를 들어서 `Person::greeting()` 이 아니라, `Person::greeting` 으로 표현한다.
`()` 는 메서드를 즉시 호출한다는 의미를 가진다. 여기서 `()` 가 없는 것은 메서드 참조를 하는 시점에는 메서드를 호출하는 게 아니라 단순히
메서드의 이름으로 해당 메서드를 참조만 한다는 뜻이다.
해당 메서드의 실제 호출 시점은 함수형 인터페이스를 통해서 이후에 이루어진다.

 

메서드 참조에서 매개변수를 생략하는 이유

함수형 인터페이스의 시그니처(매개변수와 반환 타입)가 이미 정해져 있고, 컴파일러가 그 시그니처를 바탕으로 메서드 참조와 연결해 주기 때문에 명시적으로 매개변수를 작성하지 않아도 자동으로 추론되어 호출된다.
예를 들어, Function<String, String> 이라는 함수형 인터페이스가 입력: `String`
출력: `String` 이라는 시그니처를 갖고 있기 때문에, Person::greetingWithName 를 보면 컴파일러가 "이 Function<String, String> 을 만족시키려면 greetingWithName(String name) 을 호출하면 되겠구 나"하고 자동으로 판단해 매개변수를 전달한다.
이렇게 매개변수를 포함한 메서드 호출도 메서드 참조를 사용하면 더욱 간편해진다.

 

 

 

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

1, 2, 3번 예시는 직관적이다. 단순히 객체의 메서드를 호출하면 끝나는 람다식이다. 하지만 임의 객체의 인스턴스 메서드 참조가 정확히 무엇일까?

public static void main(String[] args) {
	Function<Person, String> fun2 = Person::introduce; // 타입::인스턴스메서드 
	System.out.println("person1.introduce = " + fun2.apply(person1));
	System.out.println("person2.introduce = " + fun2.apply(person2)); 
	System.out.println("person3.introduce = " + fun2.apply(person3));
}

이 람다는 Person 타입을 매개변수로 받는다. 그리고 매개변수로 넘겨받은 person 인스턴스의 introduce() 인스턴스 메서드를 호출한다.

그리고 앞선 3가지 경우와의 가장 중요한 차이점 = 임의 객체의 인스턴스 메서드 참조는 선언 시점에 호출할 인스턴스를 지정하지 않는다. 대신에 호출 대상을 매개변수로 선언해두고, 실행 시점에 호출할 인스턴스를 받는다. 실행 시점이 되어야 어떤 객체가 호출되는지 알 수 있으므로 "임의 객체의 인스턴스 메서드 참조"라 한다.