Programming/Java

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

코딩하는 랄로 2023. 10. 14. 23:16
반응형

메소드 레퍼런스(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 메소드를 참조하는 것을 확인 할 수 있다. 

 

반응형