본문 바로가기
Programming/Java

[자바/Java] 메소드 레퍼런스(Method Reference)

by 코딩하는 랄로 2023. 10. 14.
728x90

메소드 레퍼런스(Method Reference)란

메소드 레퍼런스란, 람다식에서의 클래스의 메소드 호출을 간단하게 표현을 하는 방법이다. 람다 표현식이 메소드 호출 1회로 끝나는 경우, 메소드 레퍼런스를 이용하여 코드를 더욱 간결하게 작성할 수 있는 것이다.

 

예시로 아래의 코드를 보면,

@FunctionalInterface
public interface class Test {
    void print(T t);
}

public class Main {
    public static void main(String[] args) {
    
        //메소드 레퍼런스 X
        Test<String> t1 = (str) -> System.out.println(str);
        t1.print("hello");
        
        //메소드 레퍼런스 O
        Test<String> t2 = System::println;
        t2.print("hello");
        
    }
}

 

t1 람다식이 System의 println 메소드를 1회 호출로 끝나기 때문에 t2와 같이 메소드 래퍼런스를 사용하여 간략하게 표현할 수 있다. 두 가지 표현식 모두 같은 의미를 가지고 있다.

 

위의 예시에서 보았듯이 메소드 래퍼런스는 [클래스명]::[메소드명]으로 표현하고, 상당 부분 생략된 간결한 표현이기 때문에 메소드의 인자와 리턴 타입에 대해서 정확히 인지하고 있어야 한다.

 

메소드 레퍼런스는 패턴에 따라 아래와 같이 분류할 수 있다.

 

  • static 메소드 레퍼런스
  • 매개변수의 인스턴스 메소드 레퍼런스
  • 생성자 메소드 레퍼런스
  • 외부 인스턴스 메소드 레퍼런스

 

 

static 메소드 레퍼런스

static 메소드 레퍼런스는 static  method를 메소드 레퍼런스로 사용하는 것을 말한다.

public class Main {

    @FunctionalInteface
    interface Exceutable {
        void doSomething(String text);
    }
    
    public static class Printer {
        static void printSomething(String text) {
            System.out.println(text);
        }
    }
    
    public static void main(String[] args) {
    
        Executable e1 = Printer::printSomething; //(str) -> Printer.printSomethin(str);
        e1.doSomething("hello");
       
     }
 }

 

 

 

Instance 메소드 레퍼런스

매개변수의 타입이 명확할 때, 해당 타입 클래스의 메소드를 메소드 레퍼런스로 사용하는 것이다.

public class Main {
    
    public static class Car {
       String carName;
       public Car(String carName) {
           this.carName = carName;
       }
    
        public void printCar() {
            System.out.println(this.carName);
        }
    }
    
    public static void main(String[] args) {
    
        List<Car> carList = Arrays.asList(new Car("genesis"), new Car("avante"));
        
        //forEach를 하였을 경우, 매개변수의 타입은 무조건 Car이다!!
        //매개변수가 명확하므로, Car 클래스의 메소드를 메소드 레퍼런스로 사용가능
        carList.stream().forEach(Car::printCar());
        
        //결과
        //genesis
        //avante
       
     }
 }

 

 

 

생성자 메소드 레퍼런스

이름 그대로 생성자를 메소드 레퍼런스로 표현하는 것이다.

public class Main {
    @FunctionalInteface
    public interface CreateCar {
        Car create(String carName);
    }
    
    public static class Car {
       String carName;
       public Car(String carName) {
           this.carName = carName;
       }
       public void printCar() {
           System.out.println(this.carName);
       }
    }
    
    public static void main(String[] args) {
    
        ArrayList<Car> carList = new ArrayList<>();
        //생성자 메소드 레퍼런스
        CreateCar cc = Car::new; // str -> new Car(str);
        
        carList.add(cc.create("genesis"));
        carList.add(cc.create("avante"));
        
        carList.stream().forEach(Car::printCar); //인스턴스 메소드 레퍼런스
       
     }
 }

 

 

 

외부 인스턴스 메소드 레퍼런스

일반적인 인스턴스 메소드 레퍼런스는 해당 타입의 클래스 내에 있는 메소드를 메소드 레퍼런스로서 사용하였다. 이와 반대로 외부 인스턴스의 메소드 또한 람다표현식에서 메소드 레퍼런스로 표현할 수 있다.

 

람다 표현식에서 외부의 있는 인스턴스의 메소드를 참조하는 것을 람다 캡쳐링(또는 외부 캡쳐링)이라고 한다.

public class Main {
    @FunctionalInteface
    public interface Test {
        boolean test(String str);
    }
    
    public static void main(String[] args) {
    
        String s1 = "hello";
        
        Test t1 = str -> s1.eauals(str); //외부 캡쳐링 : 람다 내부에서 외부 인스턴스 참조
        Test t2 = s1::equals;
        
        System.out.println(t1.test("hi"));
        System.out.println(t2.test("hello"));
       
     }
 }

 

위의 예시에서, 람다 표현식에서 외부에 String 클래스의 객체인 s1의 equals 메소드를 참조하는 것을 확인 할 수 있다. 

 

728x90