관리 메뉴

개발공부기록

메서드 참조가 필요한 이유, 메서드 참조(시작, 매개변수, 임의 객체의 인스턴스 메서드 참조, 활용) 본문

자바 로드맵 강의/고급 3 - 람다, 스트림, 함수형 프로그래밍

메서드 참조가 필요한 이유, 메서드 참조(시작, 매개변수, 임의 객체의 인스턴스 메서드 참조, 활용)

소소한나구리 2025. 6. 1. 17:35
728x90

메서드 참조가 필요한 이유

메서드 참조(Method References) 알아보기

예제1

package methodref.start;

public class MethodRefStartV1 {
	public static void main(String[] args) {
		BinaryOperator<Integer> add1 = (x, y) -> x + y;
		BinaryOperator<Integer> add2 = (x, y) -> x + y;

		Integer result1 = add1.apply(1, 2);
		System.out.println("result1 = " + result1);

		Integer result2 = add2.apply(1, 2);
		System.out.println("result2 = " + result2);
	}
}
/* 실행 결과
result1 = 3
result2 = 3
*/
  • 두 정수를 더하는 간단한 연산을 수행하는 동일한 람다를 add1, add2로 각각 정의하고 있는 예제이다
  • 이렇게 동일한 기능을 하는 람다를 여러곳에서 계속 생성해서 사용하면 코드가 중복되어 유지보수가 어려워지고 덧셈 로직이 변경되면 모든 람다를 각각 수정해야 한다.

예제2

package methodref.start;

public class MethodRefStartV2 {
	public static void main(String[] args) {
		BinaryOperator<Integer> add1 = (x, y) -> add(x, y);
		BinaryOperator<Integer> add2 = (x, y) -> add(x, y);

	    // 호출 및 출력 동일
	}

	private static int add(int x, int y) {
		return x + y;
	}
}
/* 결과 동일 */
  • 이 예제에서는 동일안 람다식을 add() 메서드로 추출하여 람다에서는 add() 메서드를 호출한다.
  • 로직이 한 곳으로 모여 유지보수가 쉬워졌으며 코드 중복 문제도 해결했다.
  • 하지만 람다를 작성할 때 마다 (x, y) -> add(x, y) 형태의 코드를 반복해서 작성해야하며 매개변수를 전달하는 부분이 조금 장황하다.

예제3

package methodref.start;

public class MethodRefStartV3 {
	public static void main(String[] args) {
        // 메서드 참조
		BinaryOperator<Integer> add1 = MethodRefStartV3::add;
		BinaryOperator<Integer> add2 = MethodRefStartV3::add;

    // add() 메서드 정의 및 호출, 출력 동일
}
/* 실행 결과 동일 */
  • 메서드 참조(Method Reference)문법인 클래스명::메서드명을 사용하여 (x, y) -> add(x, y)라는 람다를 더욱 간단하게 표현하였으며 내부적으로 (x, y) -> add(x, y)와 동일하게 동작한다.

 

메서드 참조의 장점

  • 메서드 참조를 사용하면 코드가 더욱 간결해지고 가독성이 향상되며 더 이상 매개변수를 명시적으로 작성할 필요가 없다.(컴파일러가 자동으로 매개변수를 매칭함)
  • 별도의 로직 분리와 함께 재사용성 역시 높아지게 된다.

메서드 참조는 "이미 정의된 메서드를 그대로 참조하여 람다 표현식을 더 간결하게 작성하는 방법" 이라고 할 수 있다.

 

위의 예제처럼 (x, y) -> add(x, y)라는 람다는 사실상 매개변수 x, y를 그대로 add() 메서드에 전달하기만 하는 코드이기 때문에 클래스명::메서드명 형태의 메서드 참조로 간단히 표현할 수 있다.

이렇게 하면 불필요한 매개변수 선언 없이 코드가 깔끔해지고 가독성도 높아진다.

 

메서드 참조는 이미 정의된 메서드를 람다로 변환하여 더욱 간결하게 사용할 수 있도록 해주는 문법적 편의 기능으로 장황한 람다 대신 간단하고 매우 직관적으로 사용할 수 있다.

람다를 작성할 때 이미 정의된 메서드를 그대로 호출하는 경우(추가 로직이 없는 경우)라면 메서드 참조를 통해 더욱 직관적이고 간결한 코드를 작성할 수 있다.


메서드 참조

시작

람다 내부에서 단순히 어떤 메서드(정적/인스턴스/생성자 등)를 호출만하고 있는 경우에는 메서드 참조를 사용할 수 있으며 람다와 메서드 참조는 동등하게 동작한다

 

메서드 참조의 4가지 유형

  1. 정적 메서드 참조
    • 이름 그대로 정적(static)메서드를 참조한다
    • 문법: 클래스명::메서드명
    • 예: Math::max, Integer::parseInt 등
  2. 특정 객체의 인스턴스 메서드 참조
    • 특정 객체의 인스턴스 메서드를 참조한다
    • 문법: 객체명::인스턴스메서드명
    • 예: person::introduce, person::getName 등
  3. 생성자 참조
    • 생성자를 참조한다
    • 문법: 클래스명::new
    • 예: Person::new 등
  4. 임의 객체의 인스턴스 메서드 참조
    • 첫 번째 매개변수(또는 해당 람다가 받을 대상)가 그 메서드를 호출하는 객체가 된다
    • 문법: 클래스명::인스턴스메서드명
    • 예: Person::introduce, == (Person p) -> p.introduce()

 

매개변수가 없을 때 메서드 참조 예제

정적 메서드, 특정 객체의 인스턴스 메서드, 생성자를 메서드 참조한 예제이다

 

Person

package methodref;

public class Person {
	private String name;

	// 생성자
	public Person() {
		this("Unknown");
	}

	// 생성자, 매개변수
	public Person(String name) {
		this.name = name;
	}

	// 정적 메서드
	public static String greeting() {
		return "Hello";
	}

	// 정적 메서드, 매개변수
	public static String greetingWithName(String name) {
		return "Hello" + name;
	}

	public String getName() {
		return name;
	}

	// 인스턴스 메서드
	public String introduce() {
		return "I am " + name;
	}

	// 인스턴스 메서드, 매개변수
	public String introduceWithNumber(int number) {
		return "I am " + name + ", my number is " + number;
	}
}
  • 매개변수가 있거나 없는 생성자, 정적 메서드, 인스턴스 메서드들을 가지고 있는 예제를 위한 Person 객체이다

MethodRefEx1

package methodref;

public class MethodRefEx1 {
	public static void main(String[] args) {
		// 1. 정적 메서드 참조
		Supplier<String> staticMethod1 = () -> Person.greeting();
		Supplier<String> staticMethod2 = Person::greeting;	// 클래스::정적메서드

		System.out.println("staticMethod1 = " + staticMethod1.get());
		System.out.println("staticMethod2 = " + staticMethod2.get());

		// 2. 특정 객체의 인스턴스 참조
		Person person = new Person("Kim");
		Supplier<String> instanceMethod1 = () -> person.introduce();
		Supplier<String> instanceMethod2 = person::introduce;	// 객체::인스턴스메서드

		System.out.println("instanceMethod1 = " + instanceMethod1.get());
		System.out.println("instanceMethod2 = " + instanceMethod2.get());

		// 3. 생성자 참조
		Supplier<Person> newPerson1 = () -> new Person();
		Supplier<Person> newPerson2 = Person::new;	// 클래스::new

		System.out.println("newPerson1 = " + newPerson1.get());
		System.out.println("newPerson2 = " + newPerson2.get());

	}
}

/* 실행 결과
staticMethod1 = Hello
staticMethod2 = Hello
instanceMethod1 = I am Kim
instanceMethod2 = I am Kim
newPerson1 = methodref.Person@4e50df2e
newPerson2 = methodref.Person@1d81eb93
*/
  1. () -> Person.greeting() ➡️ Person::greeting: 정적 메서드를 참조한 예시이다
  2. () -> person.introduce() ➡️ person::introduce: 특정 객체(Person)의 인스턴스 메서드를 참조한 예시이다.
  3. () -> new Person() ➡️ Person::new: 생성자를 참조한 예시이다

이렇게 이미 정의된 메서드를 호출하기만 하는 람다는 메서드 참조로 간단히 표현할 수 있다.

 

메서드 참조에서 ()를 사용하지 않는 이유

  • 메서드 참조의 문법을 보면 메서드명 뒤에 ()가 없는것을 확인할 수 있는데, ()는 메서드를 즉시 호출한다는 의미를 가진다.
  • 즉, 메서드 참조를 하는 시점에는 메서드를 호출하는것이 아니라 단순히 메서드의 이름으로 해당 메서드를 참조만 한다는 뜻으로 해당 메서드의 실제 호출 시점은 함수형 인터페이스를 통한 이후에 이루어진다.

 

매개변수가 있을 때 메서드 참조 예제

매개변수가 있는 정적 메서드, 특정 객체의 인스턴스 메서드, 생성자를 메서드 참조한 예제이다

 

MethodRefEx2

package methodref;

public class MethodRefEx2 {
    public static void main(String[] args) {
        // 1. 정적 메서드 참조
        Function<String, String> staticMethod1 = name -> Person.greetingWithName(name);
        Function<String, String> staticMethod2 = Person::greetingWithName;

        System.out.println("staticMethod1 = " + staticMethod1.apply("kim"));
        System.out.println("staticMethod2 = " + staticMethod2.apply("kim"));

        // 2. 특정 객체의 인스턴스 참조
        Person person = new Person("Kim");
        Function<Integer, String> instanceMethod1 = n -> person.introduceWithNumber(n);
        Function<Integer, String> instanceMethod2 = person::introduceWithNumber;

        System.out.println("instanceMethod1 = " + instanceMethod1.apply(1));
        System.out.println("instanceMethod2 = " + instanceMethod2.apply(1));

        // 3. 생성자 참조
        Function<String, Person> newPerson1 = name -> new Person(name);
        Function<String, Person> newPerson2 = Person::new;

        System.out.println("newPerson1 = " + newPerson1.apply("kim"));
        System.out.println("newPerson2 = " + newPerson2.apply("kim"));

    }
}

/* 실행 결과
staticMethod1 = Hellokim
staticMethod2 = Hellokim
instanceMethod1 = I am Kim, my number is 1
instanceMethod2 = I am Kim, my number is 1
newPerson1 = methodref.Person@1ddc4ec2
*/
  • 매개변수가 있는 메서드 참조의 예시를 보면 매개변수가 없는 메서드 참조의 예시와 완전히 동일한 모양인 것을 확인할 수 있다
  • 메서드 참조는 매개변수를 생략하기 때문인데 만약 매개변수가 여러개라면 순서대로 전달된다.

메서드 참조에서 매개변수를 생략하는 이유

  • 함수형 인터페이스의 시그니처(매개변수와 반환 타입)가 이미 정해져 있고, 컴파일러가 그 시그니처를 바탕으로 메서드 참조와 연결해 주기 때문에 명시적으로 매개변수를 작성하지 않아도 자동으로 추론되어 호출된다
  • 예를 들어 Function<String, String> 이라는 함수형 인터페이스는 입력과 출력에 String이라는 시그니처를 가지고 있기 때문에 Person::greetingWithName라고 메서드 참조를 하면 컴파일러가 Function<String, String>을 만족하려면 greetingWithName(String name)을 호출해야 한다고 판단하여 매개변수를 전달한다.

임의 객체의 인스턴스 메서드 참조

MethodRefEx3

package methodref;

public class MethodRefEx3 {
    public static void main(String[] args) {
        // 4. 임의 객체의 인스턴스 메서드 참조(특정 타입의 메서드 참조)
        Person person1 = new Person("Kim");
        Person person2 = new Person("Park");
        Person person3 = new Person("Lee");

        // 람다
        Function<Person, String> fun1 = (Person person) -> person.introduce();
        System.out.println("person1.introduce = " + fun1.apply(person1));
        System.out.println("person2.introduce = " + fun1.apply(person2));
        System.out.println("person3.introduce = " + fun1.apply(person3));

        // 메서드 참조
        // 타입이 첫 번째 매개변수가 됨, 그리고 첫 번째 매개변수의 메서드를 호출, 나머지는 순서대로 매개변수에 전달
        Function<Person, String> fun2 = Person::introduce;  // 타입::인스턴스메서드
        System.out.println("person1.introduce = " + fun2.apply(person1));
        System.out.println("person2.introduce = " + fun2.apply(person2));
        System.out.println("person3.introduce = " + fun2.apply(person3));
    }
}
/* 실행 결과
person1.introduce = I am Kim
person2.introduce = I am Park
person3.introduce = I am Lee
person1.introduce = I am Kim
person2.introduce = I am Park
person3.introduce = I am Lee
*/

 

  • Person 타입을 매개변수로 받고 넘겨받은 person인스턴스의 introduce() 인스턴스 메서드를 호출한다
  • 람다를 실행하면 Function<Person, String> 함수형 인터페이스를 사용하기 때문에 Person 타입의 인스턴스를 인자로 받고 String을 반환한다.
  • apply()에 person1, person2, person3을 각각 전달하면 각 인스턴스의 introduce()가 호출된다.
  • 이 람다는 매개변수로 지정한 특정한 타입의 객체에 대해 동일한 메서드를 호출하는 패턴을 보인다
    • 매개변수로 지정한 특정 타입: Person
    • 메서드: introduce()
  • 즉, 특정 타입의 임의 객체의 인스턴스 메서드를 참조하는데 위의 예제에서는 Person 타입을 구현한 어떠한 객체든 해당 람다에 전달할 수 있다.
  • 이렇게 특정 타입의 임의 객체에 대해 동일한 인스턴스 메서드를 호출하는 패턴을 메서드 참조로 손쉽게 표현할 수 있다

위와 같은 메서드 참조를 특정 타입의 임의 객체의 인스턴스 참조(Reference to an instance method of an arbitrary object of a particular type)라고 공식 문서에 나와있는데 편의상 임의 객체의 인스턴스 참조라고도 한다고 한다.

 

임의 객체의 인스턴스 참조는 클래스명::인스턴스메서드와 같이 사용하며 왼쪽이 클래스명이고 오른쪽이 인스턴스 메서드이다

 

Person::introduce는 아래와 같은 람다가 된다

  1. 왼 쪽에 지정한 클래스(Person)를 람다의 첫 번째 매개변수로 사용한다
    • (Person person)
  2. 그 다음 오른쪽에 지정한 인스턴스 메서드를 첫 번째 매개변수를 통해 호출한다
    • (Person person) -> person.introduce()

메서드 참조 정리

  1. 정적 메서드 참조 - 클래스명::클래스메서드(Person::greeting)
  2. 특정 객체의 인스턴스 메서드 참조 - 객체명::인스턴스메서드(person::introduce)
  3. 생성자 참조 - 클래스명::new(Person::new)
  4. 임의 객체의 인스턴스 메서드 참조 - 클래스명::인스턴스메서드(Person::introduce)

여기서 2번과 4번이 조금 헷갈릴 수 있는데 두 메서드 참조는 문법과 기능이 전혀 다르다.

이둘의 차이를 조금 더 자세히 살펴보면 아래와 같다

 

2번(특정 객체의 인스턴스 메서드 참조)은 메서드 참조를 선언할 때부터 이름 그대로 특정 객체(인스턴스)를 지정해야 한다

  • person::introduce: 인스턴스 person을 지정한다.
  • () -> person.introduce(): 지정한 person의 인스턴스 메서드를 사용한다.
  • 이 방식은 실행 시점에 이미 지정된 인스턴스가 사용된다

4번(임의 객체의 인스턴스 메서드 참조)는 메서드 참조를 선언할 때는 어떤 객체(인스턴스)가 대상이 될지 모른다

  • Person::introduce: Person 이라는 타입만 지정하며 어떤 인스턴스가 사용될지는 아직 모른다
  • (Person person) -> person.introduce(): 매개변수로 넘어오는 person 인스턴스의 메서드를 사용한다.
  • 이 방식은 실행 시점에 인스턴스를 외부에서 전달해서 변경할 수 있다
    • fun1.apply(person1)
    • fun1.apply(person2)
    • fun1.apply(person3)

임의 객체의 인스턴스 메서드 참조는 선언 시점에 호출할 인스턴스를 지정하지 않는 대신 호출 대상을 매개변수로 선언해두고 실행 시점에 호출할 인스턴스를 받는다

즉, 실행 시점이 되어야 어떤 객체가 호출되는지 알 수 있으므로 임의 객체의 인스턴스 메서드 참조라고 한다

 

둘의 핵심적인 차이는 메서드 참조나 람다를 정의하는 시점에 호출할 대상의 인스턴스가 고정되는 것인지, 아닌지에 달려있다.

  • 특정 객체의 인스턴스 메서드 참조: 선언 시점에 메서드를 호출할 특정 객체가 고정된다
  • 특정 타입의 임의 객체의 인스턴스 메서드 참조: 선언시점에 메서드를 호출할 특정 객체가 고정되지 않고 실행 시점에 인자로 넘긴 임의의 객체가 사용된다.

 

공식문서에서 말하는 특정 타입, 임의 객체의 단어를 풀어서 설명하면 아래와 같다 

  • 특정 타입: 타입은 선언 시에 특정한 타입으로 고정된다, 예제에서는 Person 타입으로 고정 했다
  • 임의 객체: 메서드를 호출할 객체는 고정되지 않는다. Person 타입을 사용하는 임의 객체가 실행 시점에 사용될 수 있다.

복잡해 보이는 이 4번의 메서드 참조가 가장 많이 사용된다고 한다.

 

활용 예제

MethodRefEx4

package methodref;

public class MethodRefEx4 {
    public static void main(String[] args) {
        List<Person> persons = List.of(
                new Person("Kim"),
                new Person("Park"),
                new Person("Lee")
        );

        List<String> result1 = mapPersonToString(persons, (Person person) -> person.introduce());
        List<String> result2 = mapPersonToString(persons, Person::introduce);
        System.out.println("result1 = " + result1);
        System.out.println("result2 = " + result2);

        List<String> upperResult1 = mapStringToString(result1, (String s) -> s.toUpperCase());
        List<String> upperResult2 = mapStringToString(result2, String::toUpperCase);
        System.out.println("upperResult1 = " + upperResult1);
        System.out.println("upperResult2 = " + upperResult2);
    }

    static List<String> mapPersonToString(List<Person> personList, Function<Person, String> fun) {
        List<String> result = new ArrayList<>();
        for (Person person : personList) {
            String applied = fun.apply(person);
            result.add(applied);
        }
        return result;
    }

    static List<String> mapStringToString(List<String> strings, Function<String, String> fun) {
        List<String> result = new ArrayList<>();
        for (String s : strings) {
            String applied = fun.apply(s);
            result.add(applied);
        }
        return result;
    }
}
/* 실행 결과
result1 = [I am Kim, I am Park, I am Lee]
result2 = [I am Kim, I am Park, I am Lee]
upperResult1 = [I AM KIM, I AM PARK, I AM LEE]
upperResult2 = [I AM KIM, I AM PARK, I AM LEE]
*/
  • mapPersonToString 메서드
    • Person 객체 리스트를 받아서 String 리스트로 변환하는 메서드로 변환 로직을 Function<Person, String>으로 받아 유연하게 처리한다.
    • Person::introduce는 클래스::인스턴스메서드 이므로 임의 객체의 인스턴스 메서드 참조를 사용한 것이다
    • 왼쪽에 지정한 Person이 첫 번째 매개변수가 되고 오른쪽에 지정한 인스턴스 메서드를 해당 매개변수가 호출한다
    • fun.apply(person) 메서드에 List<Person> persons에 담긴 각각의 인스턴스가 인자로 넘어가면서 해당 인스턴스의 introduce() 메서드가 호출된다.
  • mapStringToString
    • String 리스트를 다른 형태의 String 리스트로 변환하는 메서드이며 입력값의 List가 Person에서 String으로 변경되는 것만 제외하면 위와 완전히 동일하다
    • String::toUpperCase이므로 임의 객체의 인스턴스 메서드 참조를 사용한 것이며 매개변수로 넘어온 각각의 String 인스턴스가 fun.apply(s) 메서드의 인자로 넘어가면서 해당 인스턴스의 toUpperCase() 메서드가 호출된다

 

MethodRefEx5

package methodref;

public class MethodRefEx5 {
    public static void main(String[] args) {
        List<Person> persons = List.of(
                new Person("Kim"),
                new Person("Park"),
                new Person("Lee")
        );

        List<String> result1 = MyStreamV3.of(persons)
                .map(person -> person.introduce())
                .map(str -> str.toUpperCase())
                .toList();

        System.out.println("result1 = " + result1);

        List<String> result2 = MyStreamV3.of(persons)
                .map(Person::introduce)
                .map(String::toUpperCase)
                .toList();

        System.out.println("result2 = " + result2);
    }

}

/* 실행 결과
result1 = [I AM KIM, I AM PARK, I AM LEE]
result2 = [I AM KIM, I AM PARK, I AM LEE]
*/
  • 기존에 만들었던 MyStreamV3을 활용하여 스트림에 메서드 참조를 활용하는 예제이다.
  • result1은 람다를 사용하여 각 Person 객체에 대해 introduce() 메서드를 호출한 후 결과 문자열을 모두 대문자로 변환한다.
  • result2는 동일한 처리 과정을 메서드 참조로 간략하게 표현했다.

람다 대신에 메서드 참조를 사용한 코드를 비교해보면 코드가 더 간결해지고 의도가 더 명확하게 드러나는 것을 확인할 수 있다.

람다로도 충분히 표현할 수 있지만 내부적으로 호출만 하는 간단한 람다라면 메서드 참조가 더 짧고 명확하게 표현될 수 있으며 이런 방식은 코드 가독성을 높이는 장점이 있다.

 

임의 객체의 인스턴스 메서드 참조에서 매개변수가 늘어나면?

MethodRefEx6

package methodref;

public class MethodRefEx6 {
    public static void main(String[] args) {
         // 4. 임의 객체의 인스턴스 메서드 참조
        Person person = new Person("Kim");

        // 람다
        BiFunction<Person, Integer, String> fun1 =
                (Person p, Integer number) -> p.introduceWithNumber(number);

        System.out.println("fun1.introduceWithNumber = " + fun1.apply(person, 1));

        // 메서드 참조, 타입::인스턴스메서드명
        // 타입이 첫 번째 매개변수가 되고 첫 번째 매개변수의 메서드를 호출
        // 나머지는 순서대로 매개변수에 전달
        BiFunction<Person, Integer, String> fun2 = Person::introduceWithNumber;
        System.out.println("fun2.introduceWithNumber = " + fun2.apply(person, 1));
    }
}
/* 실행 결과
fun1.introduceWithNumber = I am Kim, my number is 1
fun2.introduceWithNumber = I am Kim, my number is 1
*/
  • BiFunction<Person, Integer, String> 인터페이스를 사용하여 (Person, Integer) -> String 형태의 람다/메서드 참조를 구현한다.
  • fun1에서는 람다를 사용하여 p.introduceWithNumber(number)를 호출하고 fun2에서는 Person::introduceWithNumber라는 메서드 참조를 사용한다.
  • 첫 번째 매개변수(Person)가 메서드를 호출하는 객체가 되고 두 번째 매개변수(Integer)가 introduceWithNumber() 메서드의 실제 인자로 전달된다
  • 첫 번째 이후의 매개변수는 모두 순서대로 실제 인자로 전달된다.

이처럼 임의 객체의 인스턴스 메서드 참조는 함수형 인터페이스의 시그니처에 따라 첫 번째 인자를 호출 대상 객체로, 나머지 인자들은 순서대로 해당 메서드의 매개변수로 전달된다.

 

정리

메서드 참조의 필요성

  • 람다에서 이미 정의된 메서드를 단순히 호출하기만 하는 경우 메서드 참조로 더 간결하게 표현할 수 있다.
  • 코드 중복을 줄이고 가독성을 높여주며 유지보수 측면에서도 편리하다.

1. 간결성

  • 람다 표현식을 더욱 간단하게 표현할 수 있다
  • 매개변수를 생략한다
  • 특히 메서드 체이닝에서 코드가 깔끔해진다

2. 가독성

  • 메서드 이름을 직접 사용하여 의도가 더 명확해진다
  • 복잡한 람다 표현식을 단순화 할 수 있다.

3. 유연성

  • 다양한 함수형 인터페이스와 함께 사용할 수 있다.
  • 스트림 API와 결합하여 강력한 데이터 처리가 가능하다

4. 재사용성

  • 기존 메서드를 람다 표현식으로 쉽게 변환할 수 있다.
  • 동일한 메서드를 여러 컨텍스트에서 재사용할 수 있다.

 

메서드 참조의 4가지 유형

  • 정적 메서드 참조 - 클래스명::메서드명
  • 특정 객체의 인스턴스 메서드 참조 - 객체명::메서드명
  • 생성자 참조 - 클래스명::new
  • 임의 객체의 인스턴스 메서드 참조 - 클래스명::인스턴스메서드명
    • 클래스명으로 지정한 첫 번째 매개변수가 호출 대상 객체가 됨
    • 첫 번째 이후의 매개변수는 메서드의 인자로 전달됨

 

임의 객체의 인스턴스 메서드 참조

  • 특정 타입의 객체가 런타임에 주어지면 그 객체를 사용해 인스턴스 메서드를 호출하는 방식을 간단하게 표현함
  • (Person p) -> p.introduce 대신 Person::introduce로 표기됨

 

활용 예시

  • 컬렉션(List, Map 등)의 원소들을 변환(map)할 때나 스트림(Stream)에서 map, filter 등을 사용할 때 이미 정의된 메서드를 그대로 쓸 수 있다면 메서드 참조를 사용할 때 더욱 깔끔하고 직관적인 코드를 작성할 수 있다.

 

람다와의 관계

  • 메서드 참조는 람다를 메서드 호출만으로 축약한 문법이며 내부 동작은 사실상 동일하다.
  • 람다로 표현하기에 직관적인 경우에는 람다를 사용하면 되지만 메서드 참조가 더 간결하고 읽기 쉬운 경우에는 메서드 참조를 사용하면 된다.

 

메서드 참조는 자바 코드의 간결함과 가독성을 향상시켜주는 매우 유용한 기능이므로 여러 상황에서 적극적으로 활용하는 것을 추천한다.

다만, 익숙해지는데 어느정도의 시간이 필요하다.

 


출처 : 인프런 - 김영한의 실전 자바 - 고급3편 (유료) / 김영한님  
유료 강의이므로 정리에 초점을 두고 코드는 일부만 인용함

728x90