메소드 레퍼런스
람다가 하는 일이 기존 메서드 또는 생성자를 호출하는 거라면, 메소드 레퍼런스를 사용해서 매우 간결하게 표현할 수 있다.
메소드 참조 정리
스태릭 메소드 참조 | 타입::스태틱 메소드 |
---|---|
특정 객체의 인스턴스 메소드 참조 | 객체 레퍼런스::인스턴스 메소드 |
임의 객체의 인스턴스 메소드 참조 | 타입::인스턴스 메소드 |
생성자 참조 | 타입::new |
- 메소드 또는 생성자의 매개변수로 람다의 입력값을 받는다.
- 리턴값 또는 생성한 객체를 람다의 리턴값이다.
Wrapping Up Method References
출처 : dev.java에서 제공하는 메소드 참조 정리
여기서 제공하는 표가 조금 더 이해하기가 쉽게 나와 있는 거같아서 가져옴
Name | Syntax | Lambda equivalent |
---|---|---|
static | RefType::staticMethod | (args) → RefType.staticMethod(args) |
bound | expr::instanceMethod | (args) →expr.instanceMethod(args) |
unbound | RefType::instanceMethod | (arg0, arg1) → arg0.instanceMethod(rest) |
constructor | ClassName::new | (args) → new ClassName(args) |
int로 받아서 문자열로 내보내는 것
class Greeting{
private String name;
//Default 생성자
public Greeting(){
}
//생성자 메소드 (매개변수가 있음)
public Greeting(String name){
this.name = name;
}
//인스턴스 메소드
public String hello(String name){
return "hello " + name;
}
//static 메소드
pubilc static String hi(String name){
return "h1 " + name;
}
}
public class App{
public static void main(String[] args){
Function<Integer, String> inToString = (i) -> "number";
}
}
구현을 하는게 아니라 기존에 존재하는 메서드들이 있으면 그 메소드를 참조하는 것이다.
메소드 자체를 Function Interface의 구현체로 쓰는 것이다.
static Method 참조
- 입력값과 결과값의 Type이 같은 경우
- Function<Type, Type> → 두개의 타입을 써야함
- UnaryOperator
→ 타입을 한번만 쓰면됨
UnaryOperator는 입력값과 결과값이 Type이 같은 경우에 자주 쓴다.
- 아래의 두개 코드의 기능은 같다.
public class App{
public static void main(String[] args){
UnaryOperator<String> hi = (s) -> "hi" + s;
}
}
(s) -> "hi" + s
이 부분에서 하는 일이 Greeting 아래의 메소드랑 같은 행위를한다.
public class Greeting{
pubilc static String hi(String name){
return "hi " + name;
}
}
그렇다면 메소드 레퍼런스로 표현하게 된다면 ??
메소드 레퍼런스로 표현
- 하지만 메소드 레퍼런스로 표현할 경우 코드의 길이가 무척 짧아짐.
public class App{
public static void main(String[] args){
UnaryOperator<String> hi = Greeting::hi;
}
}
**UnaryOperator
| 스태릭 메소드 참조 | 타입::스태틱 메소드 | | — | — |
특정 객체의 인스턴스 메소드 참조
public class App{
public static void main(String[] args){
Greeting greeting = new Greeting();
UnaryOperator<String> hello = greeting::hello;
}
}
- Greeting에 (인스턴스메소드)hello메소드를 참조했다.
class Greeting{
private String name;
//인스턴스 메소드
public String hello(String name){
return "hello " + name;
}
}
UnaryOperator<String> hello = greeting::hello;
- 참조는 했지만 호출은 아니다. 이 코드를 쓴다고해서 아무런 일이 발생하지 않는다.
System.out.println(hello.apply("Dante"));
- apply를 해야지 호출이 이루어지고 Greeting에 hello()에 전달이 되고 가져와서 출력를 하는것이다.
생성자 참조
- 생성자
- 입력값이 없고 결과값이 있음
- 입력값이 있고 결과값이 있음
1. 입력값이 없고 결과값이 있음 → Supplier< >
public class App{
public static void main(String[] ages){
Supplier<Greeting> newGreeting = Greeting::new;
Greeting greeting = newGreeting.get(); // 객체가 만들어진다.
}
}
생성자를 호출할 때 return 값은 ? 그 객체의 타입(Greeting)이다.
입력값이 없는데 결과값이 있는 것 (함수형 인터페이스 : Supplier<>)
Supplier<Greeting> newGreeting = Greeting::new;
가져올 Type은 Greeting , 메소드 레퍼런스로 Greeting을 만드는 방법 new 해서 만들어 낸다.
하지만 이 자체로 인스턴스를 만든 것이 아니다. 실제로 Supplier이지 Greeting이 아니다.
그래서 …
- get()을 통해서 객체를 생성 한다.
Greeting greeting = newGreeting.get();
2. 입력값이 있고 결과값이 있음 → Funtion< >
public class Greeting{
public Greeting(String name) {
this.name = name;
}
}
입력 값은 String, return 값은 Greeting이다. → Function 인터페이스가 적합하다
public class App{
public static void main(String[] args){
Function<String, Greeting> DanteGreeting = Greeting::new;
}
}
- 위에 있는 입력값이 없고 결과값이 있는 것(Supplier)랑 비슷해 보인다. 하지만 다르다. 여기서 new는 레퍼런스는 같아보이지만, 서로 다른 생성자를 참조하고 있다.
여기서의 new 는 매개변수가 있는 Greeting(String name) 이지만, Supplier의 new는 Greeting() 을 호출한다. 주의해야한다 !