티스토리 뷰

728x90
반응형

람다보다는 메서드 참조를 사용하라


  • 람다가 익명 클래스보다 나은 점 중에서 가장 큰 특징은 간결함입니다. 그런데 자바에는 람다보다도 더 간결하게 만드는 방법이 있습니다. 바로 메서드 참조(Method Reference)입니다.

💡 기본적인 코드

public class Example {

    public static void main(String[] args) {
        List<Food> foods = Arrays.asList(
                new Food("햄버거"),
                new Food("피자"),
                new Food("치킨")
        );

        for (Food food : foods) {
            System.out.println(food);
        }
    }
}

 

💡 람다식을 이용한 코드

public class Example {

    public static void main(String[] args) {
        List<Food> foods = Arrays.asList(
                new Food("햄버거"),
                new Food("피자"),
                new Food("치킨")
        );

        foods.forEach(food -> System.out.println(food));
    }
}

 

💡 람다식에서 메서드 참조를 이용한 코드

public class Example {

    public static void main(String[] args) {
        List<Food> foods = Arrays.asList(
                new Food("햄버거"),
                new Food("피자"),
                new Food("치킨")
        );

        foods.forEach(System.out::println);
    }
}

 

💡 자바 8에서 추가된 Map의 merge 메서드

  • 자바 8에서 추가된 Map의 merge 메서드는 키, 값, 함수를 인자로 받아 주어진 키가 맵안에 없으면 주어진 키-값을 그대로 저장하고, 이미 키가 있다면 세번째 인자로 받은 함수에 기존 값과 새로운 값을 전달해 나온 결과로 덮어 씌웁니다.

Map 컬렉션의 merge 메서드

💡 기본 사용예시

public class Example {

    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<>();
        map.merge("홍길동", 25, (age, newAge) -> age + newAge);
        map.merge("홍길동", 30, (age, newAge) -> age + newAge);

        map.forEach((key, val) -> {
            System.out.println(key + ", " + val); // 홍길동, 55
        });
    }
}

 

💡 메서드 참조를 사용한 예시

  • 아래 예제를 보면 메서드 참조를 사용해 더한 값을 반환하겠다고 이해하기도 조금 더 쉽습니다.
  • 또한 전달해야 할 인수가 많아질수록 메서드 참조를 사용해 코드의 양을 줄일 수 있습니다.
public class Example {

    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<>();
        map.merge("홍길동", 25, Integer::sum);
        map.merge("홍길동", 30, Integer::sum);

        map.forEach((key, val) -> {
            System.out.println(key + ", " + val); // 홍길동, 55
        });
    }
}

 

💡 무조건적인 메서드 참조 과연 좋을까?

  • 어떤 상황에서는 람다가 메서드 참조보다 간결한 경우가 있는데 대표적으 메서드와 람다가 같은 클래스에 있는 경우 그렇습니다. 
  • 아래 예제에서 logic 메서드에서 메서드 참조를 사용하고 있는데 결코 짧지 않습니다. 
public class GoshThisClassNameIsHumongous {

    public void logic() {
    	// 메서드 참조
        service.execute(GoshThisClassNameIsHumongous::action);
        
        // 람다식 사용
        service.execute(()->action());
    }

    public void action() {...}
}

 

메서드 참조 유형


💡 인스턴스 메서드를 참조하는 유형

  • 수신 객체를 특정하는 한정적 인스턴스 메서드 참조
    • 정적 참조와 비슷합니다. 즉 함수 객체가 인수와 참조되는 메서드가 받는 인수가 같습니다.
  • 수신 객체를 특정하지 않은 비한정적 인스턴스 메서드 참조
    • 함수 객체를 적용하는 시점에 수신객체를 알려줍니다. 이를 위해 수신 객체 전달용 매개변수가 매개변수 목록의 첫 번째로 추가되며, 그 뒤로 참조되는 메서드 선언에 정의된 매개변수들이 뒤따릅니다.

💡 클래스 생성자를 가리키는 메서드 참조

  • 보통 생성자 참조는 팩토리 객체로 사용됩니다.

💡 배열 생성자를 가리키는 메서드 참조

 

// 정적 (둘은 같은 역할을 한다.)
Integer::parseInt;            // 메서드 참조
str -> Integer.parseIng(str); // 람다

// 한정적 (인스턴스)
Instant.now()::isAfter;       // 메서드 참조
Instant then = Instant.now(); // 람다
t -> then.isAfter(t);

// 비한정적 (인스턴스)
String::toLowerCase;          // 메서드 참조
str -> str.toLowerCase();     // 람다

// 클래스 생성자
TreeMap<K,V>::new;            // 메서드 참조
() -> new TreeMap<K,V>();     // 람다

// 배열 생성자
int[]::new;                   // 메서드 참조
len -> new int[len];          // 람다

 

728x90
반응형