이전 글에서는 람다에 대해서 알아보았었다.
이번 글에서는 내가 평상시 stream을 사용할 때 별 생각 없이 사용했었던 문법인 메서드 참조
에 대해서 알아보고자 한다.
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
// 람다 표현식을 사용한 경우
names.stream()
.forEach(name -> System.out.println(name));
// 메서드 참조를 사용한 경우
names.stream()
.forEach(System.out::println);
}
}
위는 예시 stream 코드인데, 메서드 참조는 람다식을 사용할 일이 많은 stream에서 많이 찾아볼 수 있다.
Stream에서 메서드 참조를 사용할 수 있는 이유는 자바 8에서 도입된 함수형 프로그래밍의 특징 중 하나인 ‘메서드를 값으로 취급할 수 있다.’
라는 개념 때문이다.
자바에서는 메서드를 객체로 다룰 수 있기에 이러한 메서드 참조가 가능한 것이다.
본론에서 더 자세히 다뤄보자.
public class Test {
public int add(int x, int y){
return x+y;
}
}
(x, y) → Test.add(x, y)
test::add
이는 메소드 참조(Method Reference)인데, 말 그대로 실행하려는 메서드를 참조해서 매개 변수의 정보 및 리턴 타입을 알아내서 람다식에서 굳이 선언이 불필요한 부분을 생략하는 것을 말한다.
위 예시 람다 코드에서 불필요한 부분(중복)은 (x, y)
이며 이를 생략할 수 있다는 의미이다.
어떤 메서드를 참조하여서 실행하는지에 따라서 메서드 참조도 종류가 나뉘어지게 된다.
// 람다 표현식
(x, y) → Test.add(x, y)
// 메서드 참조
Test::add
정적 메서드를 참조할 때 메서드 참조 ::
기호 앞에 클래스 명을 그대로 기재하는 것이 특징이다.
Test test = new Test();
// 람다 표현식
(x, y) → test.add(x, y)
// 메서드 참조
test::add
인스턴스의 메서드를 참조할 때, 메서드 참조 ::
기호 앞 부분에 상단에 선언했던 인스턴스 변수를 기입하는 것이 특징이다.
String str = new String();
// 람다 표현식
(String str) -> str.length;
// 메서드 참조
String::length;
매개변수의 메서드를 참조할 때, 메서드 참조 ::
기호 앞 부분에 정적 메서드 참조와 같이 매개변수의 클래스 타입명을 기재하는 것이 특징이다.
public class Test {
private int x;
private int y;
public Test(int x, int y){
this.x = x;
this.y = y;
}
}
// 람다 표현식
(x, y) -> new Test(x, y);
// 메서드 참조
Test::new;
생성자도 일종의 메서드이기에 메서드 참조가 가능하며, 리턴값이 단순히 객체를 생성하는 것이기에 적용이 가능하다.
대신 생성자는 고유 메서드 명이 없기 때문에 new
로 표시한다.
만약 이 때 생성자 오버로딩을 통해 매개 변수 개수를 따라서 인스턴스화를 구현하려고 할 때, 람다식을 각기 다른 함수형 인터페이스에 대입하여 실행시켜야 한다.