메서드 레퍼런스
계속해서 람다와 관련된 포스팅을 하고 있습니다.
람다는 익명 클래스를 어느정도 대체를 해줄 수 있는 것처럼 보이며, 간단한 처리는 대부분 람다를 이용하게 되지 않을까요?
(예를들어 안드로이드에서 이벤트 처리 시, 익명클래스의 대체가.. ㅡㅡ^ )
람다와 람다를 왜 써야하는지 보려면 이 곳으로...
오늘은 람다표현식과 더불어, 간결성과 더불어, 가독성까지 챙길 수 있는 메서드 레퍼런스에 대하여 포스팅하려 합니다.
JAVA 8 IN ACTION 에 따르면, 메서드 레퍼런스는 특정 메서드만을 호출하는 람다의 축양형 이라고 볼 수 있다고 합니다.
즉 람다를 통해 어떻게 어떤식의 메서드를 사용하라가 아닌, 메서드의 이름만을 참조하여 처리한다고 볼 수 있습니다. (그래서 레퍼런스라고 하나 봅니다... ㅎㅎ)
예를 들어, 이런 것을 볼 수 있을 것 같습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 | class Apple { private int weight; public int compareTo(Apple apple){ if (weight >= apple.getWeight()) return 0; else if (weight <= apple.getWeight()) return 1; else return -1; } } inventory.sort((Apple a, Apple b) -> a.compareTo(b)); inventory.sort(Apple::compareTo); // -> 메서드 레퍼런스 | cs |
저는 이 것을 보면서 처음에 이해가 안됐던 부분이 파라미터는 어떻게 넣을 것이냐라는 것이었습니다.
람다의 경우 파라미터 영역이 따로 명시되어 있지만 메서드 레퍼런스는 (Apple::compareTo) 다음과 같이 명시가 되어있지 않습니다.
그러나 이 것은 sort 매개변수 넣을 당시, 람다표현식에 대한 형식검사를 함을 알 수 있습니다. sort의 파라미터로 람다 표현식을 사용 시, 람다 디스크립터를 맞춰야 한다는 것은 지난 포스팅 때 언급을 했었습니다.
즉 이런한 점을 이용해, 람다 디스크립터에 맞춰 메서드 레퍼런스를 사용해주면 됨을 알게 되었습니다.
JAVA8 IN ACTION 에서는 메서드 레퍼런스를 만드는 법은 크게 세가지로 보고 있습니다.
1. 정적 메서드 레퍼런스 (정적 메서드 - static 메서드라 생각합시다.)
예를들어 Integer 클래스의 parseInt 메서드는 정적 메서드로, String 객체를 Integer 형태로 변경해줍니다. 해당 메서드는 다음과 같이 인수로써 가질 수 있습니다.
1 2 3 | Function<String, Integer> parse = Integer::parseInt; int a = parse.apply("5"); | cs |
2. 다양한 형식의 인스턴스 메서드 레퍼런스 (일반 메서드라 생각합시다.)
클래스에 정의 된 일반 메서드를 인수로 가질 수 있음을 말합니다. 아래는 List의 메소드인 size() 를 인수로 가지는 예제입니다.
1 2 3 4 5 6 7 8 9 10 | List<String> strList = new ArrayList<String>() { { add("A"); add("B"); add("C"); } }; Function<List, Integer> size = List::size; // 일반 메서드의 메서드 레퍼런스 System.out.println(size.apply(strList)); // 3 | cs |
3. 기존 객체의 인스턴스 메서드 레퍼런스
인스턴스 객체를 이용하여, 메서드 레퍼런스를 사용할 수 있습니다.
예를들면 이런식으로 사용이 가능해보입니다.
1 2 3 4 5 6 7 8 9 10 | List<String> strList = new ArrayList<String>() { { add("A"); add("B"); add("C"); } }; Consumer<String> consume = strList::add; consume.accept("E"); | cs |
메소드레퍼런스를 사용하려는 대상 메소드가 다형성에 의해 가려질 때 사용할 듯 합니다.
4. 생성자 레퍼런스
new 키워드를 사용하여, 생성자의 레퍼런스를 만들 수 있습니다. 아래와 같이 작성이 가능합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public class Apple { private String color; private int weight; public Apple(){} public Apple(String color, Integer weight){ this.color = color; this.weight = weight; } } Supplier<Apple> creator = Apple::new; // 기본 생성자에 대한 메서드 레퍼런스 Apple apple = creator.get(); // color 와 weight 를 받아 Apple을 만드는 생성자의 메서드 레퍼런스 BiFunction<String, Integer, Apple> creator2 = Apple::new; Apple apple2 = creator2.apply("green", 100); | cs |
위와 같이 다양한 시그니처 생성자에 대하여 메서드 레퍼런스를 사용할 수 있습니다.
이러한 메서드 레퍼런스를 람다표현식을 직접 사용하지 않고 사용하는 이유는 복잡한 람다식을 일일이 명시하는 것보다 가독성이 좋기 때문입니다.
즉 람다식이 복잡하다면, 차라리 메소드로 정의하여 처리하는 것이 좋아보입니다.
|
'개발이야기 > 함수형 프로그래밍' 카테고리의 다른 글
Stream API (0) | 2016.08.03 |
---|---|
람다 조합 (0) | 2016.08.02 |
람다의 실제 형식 (0) | 2016.07.28 |
클로저와 람다 (2) | 2016.07.28 |
원시타입을 위한 함수형 인터페이스 (0) | 2016.07.28 |