12/08/2018, 15:56

Method References

Lại tiếp theo bài trước Lambda Expressions..... Chúng ta sử dụng lambda expression để tạo ra anonymous method. Thỉnh thoảng, một lambda expression không làm gì cả ngoài việc chỉ gọi đến một method có sẵn. Trong những trường hợp này, thường sẽ rõ ràng hơn khi gọi đến method đó bằng name. Method ...

Lại tiếp theo bài trước Lambda Expressions..... Chúng ta sử dụng lambda expression để tạo ra anonymous method. Thỉnh thoảng, một lambda expression không làm gì cả ngoài việc chỉ gọi đến một method có sẵn. Trong những trường hợp này, thường sẽ rõ ràng hơn khi gọi đến method đó bằng name. Method referencecho phép bạn là việc đó, nó gọn nhẹ và dễ đọc hơn lambda expression đối với những method đó. Xem xét lại class Person ở bài trước (Lambda Expressions):

public class Person {

    public enum Sex {
        MALE, FEMALE
    }

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

    public int getAge() {
        // ...
    }
    
    public Calendar getBirthday() {
        return birthday;
    }    

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

Giả sử có một danh sách person, và bạn muốn sắp xếp chúng theo tuổi. Bạn có thể sử dụng đoạn code bên dưới: 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());
    }
}

Arrays.sort(rosterAsArray, new PersonAgeComparator()); Method sort được gọi tới ở đây là static <T> void sort(T[] a, Comparator<? super T> c) Interface Comparator là một functional interface, vì vậy, có thể sử dụng lambda expression thay cho việc định nghĩa và khởi tạo 1 class implement Comparator:

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

Tuy nhiên, method compare đã có sẵn ở trong hàm Person.compareByAge. Bạn có thể gọi đến method này thay cho phần body của của lambda expression.

Arrays.sort(rosterAsArray,
    (a, b) -> Person.compareByAge(a, b)
);

Vì lambda expression gọi đến một method có sẵn, bạn có thể sử dụng method reference thay cho lambda expression: Arrays.sort(rosterAsArray, Person::compareByAge); Method Person::compareByAge có ý nghĩa giống với lambda expression (a, b) -> Person.compareByAge(a, b).

Kinds of Method References

Có 4 loại method reference:

Reference to a Static Method Ví dụ bên trên Person::compareByAge là một reference đến một static method.

Reference to an Instance Method of a Particular Object Ví dụ bên dưới sẽ là một reference đến một instance method của một object cụ thể:

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);

myComparisonProvider::compareByName gọi đến method compareByName, nằm trong object myComparisonProvider. JRE sẽ tự suy luận ra type của các arguments, trong trường hợp này là (Person, Person)

Reference to an Instance Method of an Arbitrary Object of a Particular Type Ví dụ dưới đây là một reference đến một instance method của một object tùy ý với 1 type cụ thể:

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

Method reference sẽ gọi đến method a.compareToIgnoreCase(b).

Reference to a Constructor Bạn có thể reference đến một constructor giống với cách khi dùng static method bằng cách sử dụng "new". Method bên dưới copy các phần tử từ một collection sang một collection khác:

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;
}

Interface Supplier chứa một method get không có argument và return một object. Vì vậy, bạn có thể gọi method transferElements với một lambda expression như sau:

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

Bạn có thể sử dụng một constructor reference ở vị trí của lambda expression: Set<Person> rosterSet = transferElements(roster, HashSet::new); Java complier sẽ biết bạn muốn tạo một HashSet collection chứa các element có kiểu Person. Cách khác bạn có thể chỉ rõ như sau: Set<Person> rosterSet = transferElements(roster, HashSet<Person>::new);

Nguồn bài viết:

https://docs.oracle.com/javase/tutorial/java

0