Contents
The Java8(메소드 레퍼런스)
   Jul 5, 2022     5 min read

메소드 레퍼런스

람다가 하는 일이 기존 메서드 또는 생성자를 호출하는 거라면, 메소드 레퍼런스를 사용해서 매우 간결하게 표현할 수 있다.

메소드 참조 정리

스태릭 메소드 참조타입::스태틱 메소드
특정 객체의 인스턴스 메소드 참조객체 레퍼런스::인스턴스 메소드
임의 객체의 인스턴스 메소드 참조타입::인스턴스 메소드
생성자 참조타입::new
  • 메소드 또는 생성자의 매개변수로 람다의 입력값을 받는다.
  • 리턴값 또는 생성한 객체를 람다의 리턴값이다.

Wrapping Up Method References

출처 : dev.java에서 제공하는 메소드 참조 정리

여기서 제공하는 표가 조금 더 이해하기가 쉽게 나와 있는 거같아서 가져옴

NameSyntaxLambda equivalent
staticRefType::staticMethod(args) → RefType.staticMethod(args)
boundexpr::instanceMethod(args) →expr.instanceMethod(args)
unboundRefType::instanceMethod(arg0, arg1) → arg0.instanceMethod(rest)
constructorClassName::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 hi**는 구현체이고 Type은 **Greeting**이고 Greeting class에 **static method**를 참조하고 있다.

| 스태릭 메소드 참조 | 타입::스태틱 메소드 | | — | — |

특정 객체의 인스턴스 메소드 참조

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. 입력값이 없고 결과값이 있음
    2. 입력값이 있고 결과값이 있음

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() 을 호출한다. 주의해야한다 !

참고 : 백기선 - The Java8