메소드 레퍼런스(Method References)

6 min read

메소드 레퍼런스(Method References)

당신은 사용 람다 표현식을 익명 메소드를 만들 수 있습니다. 그러나 때로는 람다식이 기존 메서드를 호출하는 것 외에는 아무것도 수행하지 않습니다. 이러한 경우 기존 방법을 이름으로 언급하는 것이 더 명확합니다. 메서드 참조를 사용하면이 작업을 수행 할 수 있습니다. 그들은 이미 이름을 가지고있는 메소드를위한 작고 읽기 쉬운 식입니다.

아래는 샘플 코드입니다.


package com.github.sejoung.codetest.lamdas.methodreferences;

import java.time.LocalDate;
import java.time.chrono.IsoChronology;
import java.util.ArrayList;
import java.util.List;

public class Person {

    public enum Sex {
        MALE, FEMALE
    }

    String name;
    LocalDate birthday;
    Sex gender;
    String emailAddress;

    Person(String nameArg, LocalDate birthdayArg,
           Sex genderArg, String emailArg) {
        name = nameArg;
        birthday = birthdayArg;
        gender = genderArg;
        emailAddress = emailArg;
    }

    public int getAge() {
        return birthday
                .until(IsoChronology.INSTANCE.dateNow())
                .getYears();
    }

    public void printPerson() {
        System.out.println(name + ", " + this.getAge());
    }

    public Sex getGender() {
        return gender;
    }

    public String getName() {
        return name;
    }

    public String getEmailAddress() {
        return emailAddress;
    }

    public LocalDate getBirthday() {
        return birthday;
    }

    public static int compareByAge(Person a, Person b) {
        return a.birthday.compareTo(b.birthday);
    }

    public static List<Person> createRoster() {

        List<Person> roster = new ArrayList<>();
        roster.add(
                new Person(
                        "Fred",
                        IsoChronology.INSTANCE.date(1980, 6, 20),
                        Person.Sex.MALE,
                        "fred@example.com"));
        roster.add(
                new Person(
                        "Jane",
                        IsoChronology.INSTANCE.date(1990, 7, 15),
                        Person.Sex.FEMALE, "jane@example.com"));
        roster.add(
                new Person(
                        "George",
                        IsoChronology.INSTANCE.date(1991, 8, 13),
                        Person.Sex.MALE, "george@example.com"));
        roster.add(
                new Person(
                        "Bob",
                        IsoChronology.INSTANCE.date(2000, 9, 12),
                        Person.Sex.MALE, "bob@example.com"));

        return roster;
    }

}

package com.github.sejoung.codetest.lamdas.methodreferences;

import java.util.*;
import java.util.function.Supplier;

public class MethodReferencesTest {

    // The method transferElements copies elements from one collection to
    // another

    public static <T, SOURCE extends Collection<T>, DEST extends Collection<T>> DEST transferElements( SOURCE sourceCollection, Supplier<DEST> collectionFactory) {
        DEST result = collectionFactory.get();
        for (T t : sourceCollection) {
            result.add(t);
        }
        return result;
    }

    public static void main(String... args) {

        List<Person> roster = Person.createRoster();

        for (Person p : roster) {
            p.printPerson();
        }


        Person[] rosterAsArray =
                roster.toArray(new Person[roster.size()]);

        class PersonAgeComparator
                implements Comparator<Person> {
            public int compare(Person a, Person b) {
                return a.getBirthday().compareTo(b.getBirthday());
            }
        }

        // Without method reference
        Arrays.sort(rosterAsArray, new PersonAgeComparator());

        // With lambda expression
        Arrays.sort(rosterAsArray,
                (Person a, Person b) -> {
                    return a.getBirthday().compareTo(b.getBirthday());
                }
        );

        // With method reference
        Arrays.sort(rosterAsArray, Person::compareByAge);

        // Reference to an instance method of a particular object
        class ComparisonProvider {
            public int compareByName(Person a,
                                     Person b) {
                return a.getName().compareTo(b.getName());
            }

            public int compareByAge(Person a,
                                    Person b) {
                return a.getBirthday().compareTo(b.getBirthday());
            }
        }
        ComparisonProvider myComparisonProvider = new ComparisonProvider();
        Arrays.sort(rosterAsArray, myComparisonProvider::compareByName);

        // Reference to an instance method
        // of an arbitrary object of a particular type

        String[] stringArray = { "Barbara", "James", "Mary", "John",
                "Patricia", "Robert", "Michael", "Linda" };
        Arrays.sort(stringArray, String::compareToIgnoreCase);

        Set<Person> rosterSetLambda =
                transferElements(roster, () -> { return new HashSet<>(); });

        Set<Person> rosterSet = transferElements(
                roster, HashSet::new);
        System.out.println("Printing rosterSet:");
        rosterSet.stream().forEach(p -> p.printPerson());
    }
}


실행결과

Fred, 38
Jane, 28
George, 27
Bob, 18
Printing rosterSet:
George, 27
Bob, 18
Jane, 28
Fred, 38

Process finished with exit code 0

아래는 메소드 참조의 종류에 대해서 서술합니다 종류는 4가지가 있다.

종류|예 ---|--- 정적 메서드에 대한 참조|ContainingClass::staticMethodName 특정 객체의 인스턴스 메소드 참조|containingObject::instanceMethodName 특정 유형의 임의의 객체에 대한 인스턴스 메소드 참조|ContainingType::methodName 생성자에 대한 참조|ClassName::new

첫번째 정적 매서드에 대한 참조에 대해서 설명하겠다

위에 코드에서 정적 메서드 참조한 예는

먼저 메소드 참조 없이 처리를 하려면


        class PersonAgeComparator
                implements Comparator<Person> {
            public int compare(Person a, Person b) {
                return a.getBirthday().compareTo(b.getBirthday());
            }
        }
        
        Arrays.sort(rosterAsArray, new PersonAgeComparator());

위에 처럼 Comparator클래스를 만든후 Arrays.sort 메소드를 사용해서 만들었다 이것을 람다로 바꾸면


        Arrays.sort(rosterAsArray,
                (Person a, Person b) -> {
                    return a.getBirthday().compareTo(b.getBirthday());
                }
        );

위에 처럼 익명 클래스를 이용해서 처리를 하였다.

여기서 메소드 참조를 사용하면


Arrays.sort(rosterAsArray, Person::compareByAge);

위에 처럼 바꿀수 있는것인데 이것이 정적 메서드 참조한 예이다.

두번째 특정 객체의 인스턴스 메소드 참조는


        class ComparisonProvider {
            public int compareByName(Person a,
                                     Person b) {
                return a.getName().compareTo(b.getName());
            }

            public int compareByAge(Person a,
                                    Person b) {
                return a.getBirthday().compareTo(b.getBirthday());
            }
        }
        ComparisonProvider myComparisonProvider = new ComparisonProvider();
        Arrays.sort(rosterAsArray, myComparisonProvider::compareByName);

위에 처럼 특정 객체를 만들어서 new 한후에 인스턴스 myComparisonProvider::compareByName 메소드 참조를 하였다.

세번째 특정 유형의 임의의 객체에 대한 인스턴스 메소드 참조는


 String[] stringArray = { "Barbara", "James", "Mary", "John",
                "Patricia", "Robert", "Michael", "Linda" };
        Arrays.sort(stringArray, String::compareToIgnoreCase);

위에 코드를 보면 String 유형의 compareToIgnoreCase 메소드를 참조 하였다.

마지막으로 생성자 참조는


    public static <T, SOURCE extends Collection<T>, DEST extends Collection<T>> DEST transferElements( SOURCE sourceCollection, Supplier<DEST> collectionFactory) {
        DEST result = collectionFactory.get();
        for (T t : sourceCollection) {
            result.add(t);
        }
        return result;
    }

위에 메소드를 부르는 곳에서 보면 아래 처럼


        Set<Person> rosterSetLambda =
                transferElements(roster, () -> { return new HashSet<>(); });


쓰는데 메소드 참조로 바꾸면


 Set<Person> rosterSet = transferElements(
                roster, HashSet::new);

참조