본문 바로가기

Language/Java

[Java] 메소드 레퍼런스(Method reference, ::의 의미)

728x90
반응형

메소드 레퍼런스란?

lambda 표현식을 더 간단하게 표현하는 방법이다.

 

예를 들어, 다음은 람다식으로 Hello를 출력하는 코드이다. (Consumer는 어떤 객체를 입력받아 void를 출력시키는 함수형 인터페이스이다.)

Consumer<String> func = text -> System.out.println(text);
func.accept("Hello");

위의 람다식은 다음과 같이 System.out::println이라는 메소드 레퍼런스로 표현할 수 있다. 

Consumer<String> func = System.out::println;
func.accept("Hello");

 

메소드 레퍼런스는 ClassName::MethodName 형식으로 입력한다. 메소드를 호출하는 것이지만 괄호는 생략한다. 위의 예제처럼, 메소드 레퍼런스에는 많은 코드가 생략되어 있기 때문에 사용하려는 메소드의 인자와 리턴 타입을 알고 있어야 한다. 

 

메소드 레퍼런스는 사용하려는 패턴에 따라 3가지로 분류할 수 있다.

1. Static 메소드 레퍼런스

Static method를 메소드 레퍼런스로 사용하는 케이스이다. 아래 코드에서 변수 exe는 람다식으로 작성한 것이고, 변수 exe2는 메소드 레퍼런스로 작성되었다. printSomething 메소드는 인자 1개를 받아 void를 리턴하는 static 메소드이다.

interface Executable{
	void doSomething(String text);
}

public static class Printer{
	static void printSomething(String text){
		System.out.println(text);
	}
}

public static void main(String args[]){
	Executable exe = text -> Printer.printSomething(text);
	Executable exe2 = Printer::printSomething;
	exe.doSomething("do something");
	exe2.doSomething("do something");
}

 

Consumer를 사용하여 위의 코드를 리팩토링했다. 결과는 동일하다.

Consumer<String> consumer = Printer::printSomething;
consumer.accept("do something");

Consumer<클래스>는 java8부터 제공하는 함수형 인터페이스이다. 위의 예제에서 Executable과 같은 인터페이스를 매번 만들기 어렵기 때문에 자바에서 기본적으로 인터페이스를 제공하고 있다. Consumer은 String 1개를 인자로 받아 void를 리턴하는 메소드를 갖고 있는 인터페이스이다.

 

다음 예제는 Stream과 메소드 레퍼런스를 함께 사용하였다. 원래 1번처럼 람다식으로 길게 작성하던 것을 2번과 같이 메소드 레퍼런스를 이용하여 간단하게 표현할 수 있다.

List<String> companies = Arrays.asList("google", "apple", "google", "apple", "samsung");
// 1. lambda expression
companies.stream().forEach(company -> System.out.println(company));
// 2. static method reference
companies.stream().forEach(System.out::println);

2. Instance 메소드 레퍼런스

Instance 메소드 레퍼런스의 메소드는 static이 아닌 객체의 메소드를 의미한다. 다음 코드는 Company 객체의 이름을 출력하는 예제이다. 먼저 람다식으로 작성해보았다.

public class Company{
	String name;
	public Company(String name){
		this.name = name;
	}
	public void printName(){
		System.out.println(name);
	}
}

public static void main(String args[]){
	List<Company> companies = Arrays.asList(new Company("google"),
    		new Company("apple"), new Company("samsung"));
	companies.stream().forEach(company -> company.printName());
}

위의 코드에서 company -> company.printName()은 람다식이다. company 객체가 인자로 전달되면 company 객체의 printName() 메소드를 호출하라는 뜻이다.

 

이것을 메소드 레퍼런스로 표현하면 Company::printName으로 쓸 수 있다. forEach에서 company 객체가 전달될 것을 알기 때문에 인스턴스의 메소드를 호출해주는 의미로 이해한다.

List<Company> companies1 = 
	Array.asList(new Company("google"), new Company("apple"), new Company("samsung"));
companies1.stream().forEach(Company::printName);

 

다음은 String::length를 사용하는 예제이다. 이 함수는 스트링 객체의 길이를 리턴해주는 Instance 메소드이다. mapToInt()가 string이 int로 변환되길 예상하고 있다.

List<String> companies = Arrays.asList("google", "apple", "google", "apple", "samsung");
companies.stream()
	.mapToInt(String::length)
	.forEach(System.out::println);

 

Instace 메소드 레퍼런스는 Static 메소드 레퍼런스와 헷갈릴 수 있는데, 요구하는 인자와 리턴타입을 알고 있다면 어렵지 않게 사용할 수 있다.

3. Constructor 메소드 레퍼런스

Constructor 메소드 레퍼런스는 Constructor를 생성해주는 코드이다. 다음 예제는 람다식으로 생성자를 호출하는 코드이다.

public class Company{
	String name;
	public Company(String name){
		this.name = name;
	}
    
	public void printName(){
		System.out.println(name);
	}
}

public static void main(String args[]){
	List<String> companies = Arrays.asList("google", "apple", "google", "apple", "samsung");
	companies.stream()
		.map(name -> new Company(name))
		.forEach(company -> company.printName());
}

 

위 코드를 메소드 레퍼런스를 사용하여 리팩토링하였다. Company::new의 의미는 name -> new Company(name)와 같다. map은 String 인자가 전달되고, Company로 리턴되길 예상하고 있다. 

List<String> companies = Arrays.asList("google", "apple", "google", "apple", "samsung");
companies.stream()
	.map(Company::new)
	.forEach(Company::printName);
728x90
반응형

'Language > Java' 카테고리의 다른 글

[Java] Optional<T> 클래스  (0) 2022.07.05
[Java] Stream API - filter, map, flatMap  (0) 2022.07.04
[Java] 람다식(lambda expression)  (0) 2022.07.04
[Java] 익명 객체(anonymous object)  (0) 2022.07.04
[Java] Input/Output 정리  (0) 2021.07.13