[자바]/자바

[Java] 메서드 참조 (Method References)

쿠릉쿠릉 쾅쾅 2022. 2. 4. 17:21
728x90

 

메서드 참조

  • 메서드를 참조해서 매개 변수의 정보 및 리턴 타입을 알아내어, 람다식에서 불필요한 매개 변수를 제거하는 것이 목적이다.
  • 람다식이 하나의 메서드만 호출하는 경우에만 사용할 수 있다.
  • 메서드 참조에서 람다식에 있는 인자 전달에 대한 정보를 생략할 수 있는 이유는 함수형 인터페이스에 정의되어 있는 추상 메서드를 호출할 때 전달되는 매개변수 값을 추상 메서드를 구현하고 있는 메서드의 인자로 그대로 전달하기 때문이다.
Consumer<List<Integer>> c1 = x -> Collections.reverse(x);  // 람다 표현식
c1.accept(ls);

Consumer<List<Integer>> c2 = Collections::reverse;  // 메서드 참조
c2.accept(ls);
  • Consumer 함수형 인터페이스의 추상 메서드인 accept() 메서드를 호출 할 때 전달되는 매개변수 값을 그대로 reverse 메서드의 매개변수 값으로 전달하기 때문에 람다식에 있는 인자 전달에 대한 정보를 생략할 수 있다. 

 

 

 

 

 

메서드 참조의 4가지 유형

  • static 메서드의 참조
  • 참조변수를 통한 인스턴스 메서드 참조
  • 클래스 이름을 통한 인스턴스 메서드 참조
  • 생성자 참조

 

 

🔍 static 메서드 참조

  • 클래스 :: 메서드
람다 메서드 참조
(x) -> ClassName.method(x) Class::method

 

 

더보기
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;

public  class Prac {	
    public static void main (String[] args) { 
    	
    	List<Integer> ls = Arrays.asList(1, 3, 5, 7, 9);
    	ls = new ArrayList<>(ls);
    	
    	Consumer<List<Integer>> c1 = x -> Collections.reverse(x);  // 람다 표현식
    	c1.accept(ls);
    	System.out.println(ls);

    	Consumer<List<Integer>> c2 = Collections::reverse;  // 메서드 참조
    	c2.accept(ls);
    	System.out.println(ls);
    	
    }
    
}
[9, 7, 5, 3, 1]
[1, 3, 5, 7, 9]

 

 

 

 

🔍 인스턴스 메서드 참조1  (참조변수를 통한 인스턴스 메서드 참조)

  • 참조변수 :: 메서드
람다 메서드 참조
(obj, x) -> obj.method(x) Class::method

 

 

더보기

예제1

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;

public  class Prac {	
    public static void main (String[] args) { 
    	
    	List<Integer> ls = Arrays.asList(1, 3, 5, 7, 9);
    	ls = new ArrayList<>(ls);
    	JustSort js = new JustSort();
    	
        // 람다 표현색
    	Consumer<List<Integer>> c1 = e -> js.sort(e);  // js를 final 선언된 것처럼 다뤄야 한다.
    	c1.accept(ls);
    	System.out.println(ls);

        // 메서드 참조
    	Consumer<List<Integer>> c2 = js::sort;  // js를 final 선언된 것처럼 다뤄야 한다.
    	c2.accept(ls);
    	System.out.println(ls);
    	
    }
    
}

class JustSort {
	public void sort(List<?> lst) {
		Collections.reverse(lst);
	}
}
[9, 7, 5, 3, 1]
[1, 3, 5, 7, 9]
  • 람다식이 참조한 지역변수는 final 선언이 된 것처럼 다뤄져야한다. 메서드 참조도 똑같다.

 


 

 예제2

import java.util.Arrays;
import java.util.List;

public  class Prac {	
    public static void main (String[] args) { 
    	
    	List<String> ls = Arrays.asList("Box", "Robot");
    	
    	ls.forEach(s -> System.out.print(s));  // 람다 표현식
    	
    	System.out.println();
    	
    	ls.forEach(System.out::print);  // 메서드 참조
    }
    
}
BoxRobot
BoxRobot

 

 

 

 

 

🔍 인스턴스 메서드 참조2 (클래스 이름을 통한 인스턴스 메서드 참조)

/* 람다 표현식 */
ToIntBiFunction<클래스명, 클래스명> bf = (인자1, 인자2) -> 인자1.인스턴스메서드명(인자2)


/* 메서드 참조 */
ToIntBiFunction<클래스명, 클래스명> bf = 클래스명::인스턴스메서드명
  • 람다식에서 첫 번째 매개변수인 인자1의 인스턴스 메서드의 매개변수로 두 번째 매개변수인 인자2가 들어올 경우 메서드 참조를 할 수 있다.
  • 즉, 인스턴스 없이 인스턴스 메서드를 참조할 수 있는 것이다.

 

 

더보기
import java.util.function.ToIntBiFunction;

public  class Prac {	
    public static void main (String[] args) { 
    	IBox ib1 = new IBox(5);
    	IBox ib2 = new IBox(7);
    	
    	ToIntBiFunction<IBox, IBox> bf1 = (b1, b2) -> b1.larger(b2);  // 람다 표현식
    	int bigNum1 = bf1.applyAsInt(ib1, ib2);
    	System.out.println(bigNum1);
    	
    	
    	ToIntBiFunction<IBox, IBox> bf2 = IBox::larger;  // 메서드 참조
    	int bigNum2 = bf2.applyAsInt(ib1, ib2);
    	System.out.println(bigNum2);
    	
    }
    
}

class IBox {
	private int n;
	
	public IBox(int i) {
		n = i;
	}
	
	public int larger(IBox b) {
		if(n > b.n)
			return n;
		
		return b.n;
	}
}
7
7
  •  람다식에서 호출하는 메서드 larger()가 첫 번째 인자인 b1의 인스턴스 메서드이며 larger() 메서드의 매개변수로  두 번째 인자인 b2가 전달될 경우 메서드 참조를 할 수 있다. 

 

 

 

 

 

 

🔍 생성자 참조

  • 람다식으로 인스턴스를 생성하고 이의 참조 값을 반환해야 하는 경우 메서드 참조로 대체 할 수 있다.
람다 메서드 참조
(a, b) -> new 클래스(a) Class::new

 

 

더보기

예제1

import java.util.function.Function;

public  class Prac {	
    public static void main (String[] args) { 
    	
    	char[] src = {'R', 'o', 'b', 'o', 't'};
    	
    	Function<char[], String> f1  = ar -> new String(ar);  // 람다 표현식
    	String str = f1.apply(src);
    	System.out.println(str);
    	
    	
    	Function<char[], String> f2  = String::new;  // 메서드 참조
    	str = f2.apply(src);
    	System.out.println(str);
    	
    }
}
Robot
Robot

 


 

예제2

import java.util.function.Supplier;

public  class Prac {	
    public static void main (String[] args) { 
    	
    	Supplier<MyClass> f1 = () -> new MyClass();
    	MyClass m1 = f1.get();
    	System.out.println(m1);
    	
    	Supplier<MyClass> f2 = MyClass::new;
    	MyClass m2 = f2.get();
    	System.out.println(m2);
    	
    	Supplier<String> f3 = String::new;
    	String str = f3.get();
    	
    }
}

class MyClass {
	@Override
	public String toString() {
		return "생성자";
	}
}
생성자
생성자
  •  매개변수가 필요없는 생성자를 통해 인스턴스를 생성할 때는 Supplier 함수형 인터페이스를 사용하면 된다.

 


 

 예제3

import java.util.function.Function;

public  class Prac {	
    public static void main (String[] args) { 
    	
    	Function<Integer, MyClass> f1 = i -> new MyClass(i);  // 람다 표현식
    	MyClass m1 = f1.apply(1);
    	System.out.println(m1);
    	
    	Function<Integer, MyClass> f2 = MyClass::new;  // 메서드 참조
    	MyClass m2 = f2.apply(5);
    	System.out.println(m2);
    	
    	Function<Integer, int[]> fArr1 = x -> new int[x];  // 람다 표현식
    	int[] arr1 = fArr1.apply(10);  // 배열 크기가 10인 배열 생성
    	
    	
    	Function<Integer, int[]> fArr2 = int[]::new;  // 메서드 참조
    	int[] arr2 = fArr1.apply(20);  // 배열 크기가 20인 배열 생성
    	
    }
}

class MyClass {
	int i;
	
	MyClass(int i) {
		this.i = i;
	}
	
	@Override
	public String toString() {
		return i +"";
	}
	
}
1
5
  • 매개변수가 필요한 생성자라면 매개변수의 개수에 따라 알맞은 함수형 인터페이스를 사용해야 한다.
  • Function 함수형 인터페이스를 통해 배열을 만들 수 있다.

 


 

예제4

import java.util.function.BiFunction;

public  class Prac {	
    public static void main (String[] args) { 
    	
    	BiFunction<Integer, String, MyClass> bf1 = (i, s) -> new MyClass(i, s);
    	MyClass m1 = bf1.apply(1, "하");
    	System.out.println(m1);
    	
    	BiFunction<Integer, String, MyClass> bf2 = MyClass::new;
    	MyClass m2 = bf2.apply(5, "상");
    	System.out.println(m2);
    	
    }
}

class MyClass {
	int i;
	String s;
	
	MyClass(int i, String s) {
		this.i = i;
		this.s = s;
	}
	
	@Override
	public String toString() {
		return i + ", " + s;
	}
	
}
1, 하
5, 상
  •  생성자의 매개변수가 2개가 필요한 경우 BiFunction 함수형 인터페이스를 이용한다. 

 

728x90