• JAVA 8 方法引用


    什么是方法引用

      简单地说,就是一个Lambda表达式。在Java 8中,我们会使用Lambda表达式创建匿名方法,但是有时候,我们的Lambda表达式可能仅仅调用一个已存在的方法,而不做任何其它事,对于这种情况,通过一个方法名字来引用这个已存在的方法会更加清晰,Java 8的方法引用允许我们这样做。方法引用是一个更加紧凑,易读的Lambda表达式,注意方法引用是一个Lambda表达式,其中方法引用的操作符是双冒号"::"。

    方法引用例子

     先看一个例子

    首先定义一个Person类,如下:

    package methodreferences;
    
    import java.time.LocalDate;
    
    public class Person
    {
    
        public Person(String name, LocalDate birthday)
        {
            this.name = name;
            this.birthday = birthday;
        }
    
        String name;
        LocalDate birthday;
    
        public LocalDate getBirthday()
        {
            return birthday;
        }
    
        public static int compareByAge(Person a, Person b)
        {
            return a.birthday.compareTo(b.birthday);
        }
    
        @Override
        public String toString()
        {
            return this.name;
        }
    }

    假设我们有一个Person数组,并且想对它进行排序,这时候,我们可能会这样写:

    原始写法

    package methodreferences;
    
    import java.time.LocalDate;
    import java.util.Arrays;
    import java.util.Comparator;
    
    public class Main
    {
    
        static class PersonAgeComparator implements Comparator<Person> {
            public int compare(Person a, Person b) {
                return a.getBirthday().compareTo(b.getBirthday());
            }
        }
        
        public static void main(String[] args)
        {
            Person[] pArr = new Person[]{
                new Person("003", LocalDate.of(2016,9,1)),
                new Person("001", LocalDate.of(2016,2,1)),
                new Person("002", LocalDate.of(2016,3,1)),
                new Person("004", LocalDate.of(2016,12,1))};
    
            Arrays.sort(pArr, new PersonAgeComparator());
            
            System.out.println(Arrays.asList(pArr));
        }
    }

    其中,Arrays类的sort方法定义如下:

    public static <T> void sort(T[] a, Comparator<? super T> c)

    这里,我们首先要注意Comparator接口是一个函数式接口,因此我们可以使用Lambda表达式,而不需要定义一个实现Comparator接口的类,并创建它的实例对象,传给sort方法。

    使用Lambda表达式,我们可以这样写:

    改进一,使用Lambda表达式,未调用已存在的方法

    package methodreferences;
    
    import java.time.LocalDate;
    import java.util.Arrays;
    
    public class Main
    {
    
        public static void main(String[] args)
        {
            Person[] pArr = new Person[]{
                new Person("003", LocalDate.of(2016,9,1)),
                new Person("001", LocalDate.of(2016,2,1)),
                new Person("002", LocalDate.of(2016,3,1)),
                new Person("004", LocalDate.of(2016,12,1))};
    
            Arrays.sort(pArr, (Person a, Person b) -> {
                return a.getBirthday().compareTo(b.getBirthday());
            });
            
            System.out.println(Arrays.asList(pArr));
        }
    }

    然而,在以上代码中,关于两个人生日的比较方法在Person类中已经定义了,因此,我们可以直接使用已存在的Person.compareByAge方法。

    改进二,使用Lambda表达式,调用已存在的方法

    package methodreferences;
    
    import java.time.LocalDate;
    import java.util.Arrays;
    
    public class Main
    {
    
        public static void main(String[] args)
        {
            Person[] pArr = new Person[]{
                new Person("003", LocalDate.of(2016,9,1)),
                new Person("001", LocalDate.of(2016,2,1)),
                new Person("002", LocalDate.of(2016,3,1)),
                new Person("004", LocalDate.of(2016,12,1))};
    
            Arrays.sort(pArr, (a, b) -> Person.compareByAge(a, b));
            
            System.out.println(Arrays.asList(pArr));
        }
    }

    因为这个Lambda表达式调用了一个已存在的方法,因此,我们可以直接使用方法引用来替代这个Lambda表达式,

    改进三,使用方法引用

    package methodreferences;
    
    import java.time.LocalDate;
    import java.util.Arrays;
    
    public class Main
    {
    
        public static void main(String[] args)
        {
            Person[] pArr = new Person[]{
                new Person("003", LocalDate.of(2016,9,1)),
                new Person("001", LocalDate.of(2016,2,1)),
                new Person("002", LocalDate.of(2016,3,1)),
                new Person("004", LocalDate.of(2016,12,1))};
    
            Arrays.sort(pArr, Person::compareByAge);
            
            System.out.println(Arrays.asList(pArr));
        }
    }

    在以上代码中,方法引用Person::compareByAge在语义上与Lambda表达式 (a, b) -> Person.compareByAge(a, b) 是等同的,都有如下特性:

    • 真实的参数是拷贝自Comparator<Person>.compare方法,即(Person, Person);
    • 表达式体调用Person.compareByAge方法;

    四种方法引用类型

    静态方法引用

    我们前面举的例子Person::compareByAge就是一个静态方法引用。

    特定实例对象的方法引用

    如下示例,引用的方法是myComparisonProvider 对象的compareByName方法;

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

    任意对象(属于同一个类)的实例方法引用

    如下示例,这里引用的是字符串数组中任意一个对象的compareToIgnoreCase方法。

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

    构造方法引用

    如下示例,这里使用了关键字new,创建了一个包含Person元素的集合。

    Set<Person> rosterSet = transferElements(roster, HashSet<Person>::new);
    transferElements方法的定义如下,功能为集合拷贝,
    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;
    }

    什么场景适合使用方法引用

    当一个Lambda表达式调用了一个已存在的方法

    什么场景不适合使用方法引用

    当我们需要往引用的方法传其它参数的时候,不适合,如下示例:

    IsReferable demo = () -> ReferenceDemo.commonMethod("Argument in method.");

    参考资料

    http://java8.in/java-8-method-references/

    https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html

  • 相关阅读:
    微信小程序之项目的创建
    Java中的线程--多线程面试题
    Java中的线程--并发库中的集合
    Java中的线程--线程中的工具
    Java中的线程--Lock和Condition实现线程同步通信
    Linux指定用户运行程序
    CPU、内存、磁盘三者的关系
    shell从字符串中提取子串(正则表达式)
    ssh登录失败的常见问题分析
    正则表达式匹配不含有某字符串的行
  • 原文地址:https://www.cnblogs.com/chenpi/p/5885706.html
Copyright © 2020-2023  润新知