Java

[Java]메서드 참조(Method reference)

DevStory 2022. 5. 11.

메서드 참조(Method reference)란?

Java 8에 도입된 메서드 참조는 class::methodName 구문을 사용하여 클래스 또는 객체에서 메서드를 참조할 수 있습니다.

 

람다식(Lambda Expression)의 가장 큰 장점 중 하나는 코드가 짧아진다는 것인데, 람다식에 메서드 참조를 사용하면 코드를 더 간결하고 가독성 있게 만들 수 있습니다.

// 람다식
str -> str.toString()
// 메서드 참조
String::toString

// 람다식
str -> str.length()
// 메서드 참조
String::length

// 람다식
(int x, int y) -> x.compareTo(y)
// 메서드 참조
Integer::compareTo

메서드 참조는 이중 콜론(::)을 사용하여 클래스 이름과 메서드 이름을 구분하며, 람다식과 달리 인수를 전달할 필요가 없습니다. 인수는 메서드 참조 타입에 따라 처리됩니다.


메서드 참조 유형

  • 정적 메서드에 대한 메서드 참조(Class::StaticMethodName)
  • Object 인스턴스 메서드에 대한 참조(Object::instanceMethodName)
  • 특정 타입(또는 클래스)에 대한 인스턴스 메서드에 대한 메서드 참조(Class::instanceMethodName)
  • 생성자에 대한 메서드 참조(Class::new)

Java 8은 네 가지 유형의 메서드 참조를 제공합니다. 


정적 메서드 참조

아래와 같은 함수형 인터페이스가 존재합니다.

@FunctionalInterface
public interface IAdd {
  int add(int x, int y);
}

그리고 두 개의 매개변수 합산을 반환하는 MathUtils 클래스가 있습니다.

public class MathUtils {
  public static int AddElement(int x, int y) {
    return x + y;
  }
}

다음 예제는 람다식을 사용하는 방법과 메서드 참조를 사용하는 방법을 보여줍니다.

public class Main {
  public static void main(String args[]) {
    System.out.println("Lambda Expression");
    IAdd addLambda = (x, y) -> MathUtils.AddElement(x, y);
    System.out.println(addLambda.add(10, 20));

    System.out.println("Method Reference");
    IAdd addMethodRef = MathUtils::AddElement;
    System.out.println(addMethodRef.add(20, 40));
  }
}

실행 결과

Lambda Expression
30
Method Reference
60

Object 인스턴스 메서드 참조 

MathUtils 클래스의 AddElement() 메서드를 비정적(non-static) 메서드로 변경합니다.

public class MathUtils {
  public int AddElement(int x, int y) {
    return x + y;
  }
}

다음 예제는 객체를 생성하고 객체의 메서드를 호출하는 방법을 보여줍니다.

public class Main {
  public static void main(String args[]) {
    // MathUtils 클래스의 객체를 생성합니다.
    MathUtils mu = new MathUtils();
        
    // 객체로 메서드를 호출하는 람다식입니다.    
    System.out.println("Lambda Expression");
    IAdd addLambda = (x, y) -> mu.AddElement(x, y);
    System.out.println(addLambda.add(10, 20));

    // 객체로 메서드를 호출하는 메서드 참조입니다.
    System.out.println("Method Reference");
    IAdd addMethodRef = mu::AddElement;
    System.out.println(addMethodRef.add(20, 40));
  }
}

실행 결과

Lambda Expression
30
Method Reference
60

위 예제는 다음 예제처럼 객체를 생성하지 않고 람다식 또는 메서드 참조에서 MathUtils 클래스를 인스턴스화 할 수 있습니다.

public class Main {
  public static void main(String args[]) {
    // 클래스를 인스턴스화하여 메서드를 호출하는 람다식입니다.    
    System.out.println("Lambda Expression");
    IAdd addLambda = (x, y) -> new MathUtils().AddElement(x, y);
    System.out.println(addLambda.add(10, 20));

    // 클래스를 인스턴스화하여 메서드를 호출하는 메서드 참조입니다.
    System.out.println("Method Reference");
    IAdd addMethodRef = new MathUtils()::AddElement;
    System.out.println(addMethodRef.add(20, 40));
  }
}
반응형

특정 타입(클래스)에 대한 인스턴스 메서드에 대한 메서드 참조

Arrays.sort() 메서드의 첫 번째 매개변수는 컬렉션 배열이며, 두 번째 매개변수는 Comparator 객체입니다. 오름차순으로 정렬하며 대소문자를 구분합니다.

String[] strArr = {"a", "B", "e", "c", "D"};

Arrays.sort(strArr);

System.out.println("Sorted strArr[] : " + Arrays.toString(strArr));

실행 결과

Sorted strArr[] : [B, D, a, c, e]

대소문자 구분 없이 정렬하고 싶은 경우 두 번째 매개변수인 Comparator 객체를 다음과 같이 구현합니다.

String[] strArr = {"a", "B", "e", "c", "D"};

Arrays.sort(strArr, new Comparator<String>() {
  @Override
  public int compare(String s1, String s2) {
    return s1.compareToIgnoreCase(s2);
  }
});

System.out.println("Sorted strArr[] : " + Arrays.toString(strArr));

실행 결과

Sorted strArr[] : [a, B, c, D, e]

두 번째 매개변수인 Comparator 객체는 함수형 인터페이스를 구현한 클래스와 유사합니다. 그러므로 람다식으로 변경할 수 있습니다.

Arrays.sort(strArr, (s1, s2) -> s1.compareToIgnoreCase(s2));

람다식은 메서드 참조로 변경할 수 있습니다.

Arrays.sort(strArr, String::compareToIgnoreCase);

생성자 참조

Stream의 collect() 메서드는 Supplier 인수를 허용합니다. Supplier는 매개변수가 없으며, void가 아닌 타입을 반환합니다. Supplier은 새로운 인스턴스를 반환하므로 람다식으로 호출할 수 있습니다.

List<Integer> intList = Arrays.asList(1, 2, 3, 4, 5);

String strConcat = intList.parallelStream().collect(
        () -> new StringBuilder(),
        (x, y) -> x.append(y),
        (a, b) -> a.append(b)).toString();

System.out.println(strConcat);

실행 결과

12345

() -> new StringBuilder()를 생성자 메서드 참조로 변경할 수 있으며, 두 개의 람다식도 메서드 참조로 변경할 수 있습니다.

String concat1 = intList.parallelStream().collect(
		StringBuilder::new,
		StringBuilder::append,
		StringBuilder::append).toString();

정리

  • Java 8에 도입된 메서드 참조는 람다식을 더 간결하게 해주는 문법입니다.
  • 메서드 참조는 모든 메서드에서 사용할 수 없으며, 정적 메서드 참조, Object 인스턴스 메서드 참조, 특정 타입(클래스)에 대한 인스턴스 메서드에 대한 메서드 참조, 생성자 참조에서 사용할 수 있습니다.
반응형

댓글