본문 바로가기
Programming/Java, Spring

자바의 method reference

by Renechoi 2023. 6. 3.

 

method reference 

 

- 기존에 이미 선언되어 있는 메서드를 지정하고 싶을 때

- :: 오퍼레이터 사용

- ClassName::staticMethodName : 객체의 static method를 지정할 때 

- ClassName::instanceMethodName : 객체의 instance method를 지정할 때

- ClassName::new : 객체의 constructor를 지정할 때 

- objectName::instanceMethodName : 선언된 객체의 instance method를 지정할 때

 

 

ClassName::staticMethodName

Function<String, Integer> strToInt = Integer::parseInt; 
int five = strToInt.apply("5");

 

objectName::instanceMethodName

String string = "hello";
Predicate<String> equalsToHello = str::eqauls;
booean isHelloEquals = equalsHello.test("world");

 

사용 예시 

 

class StringUtils {
    public static int countUpperCase(String str) {
        int count = 0;
        for (char c : str.toCharArray()) {
            if (Character.isUpperCase(c)) {
                count++;
            }
        }
        return count;
    }

    public static void printString(String str) {
        System.out.println(str);
    }
}

public class MethodReferenceExample {
    public static void main(String[] args) {
        // static 메서드 레퍼런스
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
        names.forEach(StringUtils::printString);

        // 인스턴스 메서드 레퍼런스
        String str = "HelloWorld";
        int upperCaseCount = StringUtils.countUpperCase(str);
        System.out.println("Number of uppercase letters: " + upperCaseCount);
    }
}

 

 

생성자를 메서드 레퍼런스 방식으로 구현하는 코드를 구현해보자. 

 

public class PersonMethodRef {
   public static void main(String[] args) {
      BiFunction<String, Integer, Person> personGenerator = Person::new;
      Person kim = personGenerator.apply("kim", 3);
      System.out.println("kim = " + kim);
   }
}

 

 

 

보다 OOP 스러운 예시 코드를 작성해보자. 

 

 

다음과 같은 input이 있고 이를 바탕으로 카 리스트를 만든다고 할 때, 종류별로 sorting을 하는 상황을 가정해보자.

 

String[][] inputs = new String[][] {
   {"sedan", "Sonata", "Hyundai"},
   {"van", "Sienna", "Toyota"},
   {"sedan", "Model S", "Tesla"},
   {"suv", "Sorento", "Kia"}
};

 

직관적으로 if else 분기문을 써서 sedan 이면 sedan 객체를 생성, van 이면 van 객체를 생성하는 식으로 코드를 작성할 수 있을 것이다.

 

하지만 이를 functional interface를 써서 method reference 방식으로 구현해보면 어떨까. 

 

먼저 다음과 같은 map을 만든다. 

 

Map<String, BiFunction<String, String, Car>> carTypeToConstructorMap = new HashMap<>();

 

이 map에 컨스트럭터를 던져준다. 

 

carTypeToConstructorMap.put("sedan", Sedan::new);
carTypeToConstructorMap.put("van", Sedan::new);
carTypeToConstructorMap.put("suv", Sedan::new);

 

각각의 클래스는 다음과 같이 두 개의 인자를 받기 때문에 BiFunction Functional Interface의 메서드 레퍼런스 방식으로 구현이 가능하다. 

 

public class Sedan extends Car{
   public Sedan(String name, String brand) {
      super(name, brand);
   }

   @Override
   public void drive() {
      System.out.println("Sedan.drive");
   }
}
public class Suv extends Car{
   public Suv(String name, String brand) {
      super(name, brand);
   }

   @Override
   public void drive() {
      System.out.println("Suv.drive");
   }
}

public class Van extends Car{
   public Van(String name, String brand) {
      super(name, brand);
   }

   @Override
   public void drive() {
      System.out.println("Van.drive");
   }
}

 

 

결론적으로 분기문을 사용하지 않고 다음과 같이 작성할 수 있다.

 

public static void main(String[] args) {
   Map<String, BiFunction<String, String, Car>> carTypeToConstructorMap = new HashMap<>();
   carTypeToConstructorMap.put("sedan", Sedan::new);
   carTypeToConstructorMap.put("van", Sedan::new);
   carTypeToConstructorMap.put("suv", Sedan::new);

   String[][] inputs = new String[][] {
      {"sedan", "Sonata", "Hyundai"},
      {"van", "Sienna", "Toyota"},
      {"sedan", "Model S", "Tesla"},
      {"suv", "Sorento", "Kia"}
   };

   List<Car> cars = Arrays.stream(inputs)
      .map(input -> {
         String carType = input[0];
         String name = input[1];
         String brand = input[2];
         return carTypeToConstructorMap.get(carType).apply(name, brand);
      })
      .toList();
}

만약 Functional interface를 직접 구현한다면 get 부분부터 작동되는 메서드들을 아예 인터페이스 안으로 숨겨 보다 깔끔하게 만들 수도 있을 것이다. 

 

 

 


ref. https://fastcampus.co.kr/dev_red_lsh

반응형