Java新特性-方法引用

方法引用的出现原因

在使用 Lambda 表达式的时候,我们实际上传递进去的代码就是一种解决方案:拿参数做操作, 如果我们在 Lambda 中所指定的操作方案,已经有地方存在相同方案, 就可以通过方法引用来使用已经存在的方案

体验方法的引用

新建一个 Printable 接口

/**
 * @author BNTang
 */
public interface Printable {
    void printString(String s);
}

方法引用符::: 参数传给了 System 当中

/**
 * @author BNTang
 */
public class PrintableMain {
    public static void main(String[] args) {
        usePrintable(System.out::println);
    }
    
    private static void usePrintable(Printable printable) {
        printable.printString("test");
    }
}

方法引用符

:: 该符号为引用运算符,而它所在的表达式被称为方法引用

推导与省略

  • 如果使用 Lambda,那么根据 “可推导就是可省略” 的原则,无需指定参数类型,也无需指定的重载形式,它们都将被自动推导
  • 如果使用方法引用,也是同样可以根据上下文进行推导
  • 方法引用是 Lambda 的孪生兄弟

引用类方法

引用类方法,其实就是引用类的静态方法,格式:类名::静态方法,下面将给出一段示例进行参考,首先新建一个 Converter 接口

/**
 * @author BNTang
 */
public interface Converter {

    Number convert(String str);

}

然后 psvm 进行使用一下如下

/**
 * @author BNTang
 */
public class ConverterMain {
    public static void main(String[] args) {
        useConverter((String str) -> {
            return Integer.parseInt(str);
        });
    }

    private static void useConverter(Converter converter) {
        System.out.println(converter.convert("6666"));
    }
}

如上的写法存在简化的写法,一步一步来进行改造,首先先来改造一下 Lambda 的简写写法,改造之后如下

/**
 * @author BNTang
 */
public class ConverterMain {
    public static void main(String[] args) {
        useConverter(str -> Integer.parseInt(str));
    }

    private static void useConverter(Converter converter) {
        System.out.println(converter.convert("6666"));
    }
}

Lambda 表达式的改造完成了,那么就来开始看看引用类方法吧,进行改造如下, Lambda 表达式被类方法替代的时候,它的形式参数全部传递给静态方法作为参数

/**
 * @author BNTang
 */
public class ConverterMain {
    public static void main(String[] args) {
        useConverter(Integer::parseInt);
    }

    private static void useConverter(Converter converter) {
        System.out.println(converter.convert("6666"));
    }
}

引用对象方法

格式:对象::成员方法 不多说什么直接上案例了,自行参考,新建一个 CalculateInterface 接口

/**
 * @author BNTang
 */
public interface CalculateInterface {
    void calculate(Integer numOne, Integer numTwo);
}

然后在新建一个 CalculateString 普通的类

/**
 * @author BNTang
 */
public class CalculateString {

    public void printCalculate(Integer numOne, Integer numTwo) {
        System.out.println(numOne + numTwo);
    }

}

在进行 psvm 进行测试使用如下

/**
 * @author BNTang
 */
public class CalculateString {

    public void printCalculate(Integer numOne, Integer numTwo) {
        System.out.println(numOne + numTwo);
    }

}

我没有写的一步到位,主要是为了更好了让阅读者看到一步一步简化和演变的过程,进行改造 Lambda 的简写写法如下

/**
 * @author BNTang
 */
public class CalculateMain {
    public static void main(String[] args) {
        useCalculate((a, b) -> System.out.println(a + b));
    }

    private static void useCalculate(CalculateInterface calculateInterface) {
        calculateInterface.calculate(1, 2);
    }
}

改造就到这,接下来开始就来看看对象方法的引用吧,首先我实例化了一个对象,然后在调用 useCalculate 里面就可以进行对象方法的引用了,Lambda 表达式被对象的实例方法替代的时候,它的形式参数全部传递给了该方法作为参数, 如下所示

/**
 * @author BNTang
 */
public class CalculateMain {
    public static void main(String[] args) {

        CalculateString calculateString = new CalculateString();
        useCalculate(calculateString::printCalculate);
    }

    private static void useCalculate(CalculateInterface calculateInterface) {
        calculateInterface.calculate(1, 2);
    }
}

引用类的实例方法

格式和上面的一样不在介绍,废话不多说直接上代码,新建一个 MyString 接口

/**
 * @author BNTang
 */
public interface MyString {
    String mySubString(String s, int x, int y);
}

老规矩,先来看看最初的 Lambda 写法

/**
 * @author BNTang
 */
public class MyStringMain {
    public static void main(String[] args) {
        useMyString((String s, int x, int y) -> {
            return s.substring(x, y);
        });
    }

    private static void useMyString(MyString myString) {
        System.out.println(myString.mySubString("HelloWorld", 2, 5));
    }
}

Lambda 简化写法,至于简化的原理我之前的 Lambda 文章已经解释过了

/**
 * @author BNTang
 */
public class MyStringMain {
    public static void main(String[] args) {
        useMyString((s, x, y) -> s.substring(x, y));
    }

    private static void useMyString(MyString myString) {
        System.out.println(myString.mySubString("HelloWorld", 2, 5));
    }
}

引用类的实例方法,Lambda 表达式被类的实例方法替代的时候,第一个参数作为调用者,后面的参数全部传递给了该方法作为参数,例如第一个参数就是我们上方写的 HelloWorld 它作为调用者,后面的参数全部传递给了该方法作为参数,改造之后的内容如下所示

/**
 * @author BNTang
 */
public class MyStringMain {
    public static void main(String[] args) {
        useMyString(String::substring);
    }

    private static void useMyString(MyString myString) {
        System.out.println(myString.mySubString("HelloWorld", 2, 5));
    }
}

引用构造器

引用构造器,其实就是引用构造方法,废话不多说直接上代码,使用格式同上,新建一个 Person

/**
 * @author BNTang
 */
public class Person {

    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

在新建一个 PersonBuildInterface 接口

/**
 * @author BNTang
 */
public interface PersonBuildInterface {
    Person build(String name, int age);
}

psvm 进行测试如下,和之前一样的一步一步简化到最终的简化代码

/**
 * @author BNTang
 */
public class PersonMain {
    public static void main(String[] args) {
        usePersonBuilder((name, age) -> {
            return new Person(name, age);
        });
    }

    private static void usePersonBuilder(PersonBuildInterface personBuildInterface) {
        Person bnTangPerson = personBuildInterface.build("BNTang", 23);
        System.out.println(bnTangPerson.getName() + "," + bnTangPerson.getAge());
    }
}

简化 Lambda 写法

/**
 * @author BNTang
 */
public class PersonMain {
    public static void main(String[] args) {
        usePersonBuilder((name, age) -> new Person(name, age));
    }

    private static void usePersonBuilder(PersonBuildInterface personBuildInterface) {
        Person bnTangPerson = personBuildInterface.build("BNTang", 23);
        System.out.println(bnTangPerson.getName() + "," + bnTangPerson.getAge());
    }
}

改造引用构造器

/**
 * @author BNTang
 */
public class PersonMain {
    public static void main(String[] args) {
        usePersonBuilder(Person::new);
    }

    private static void usePersonBuilder(PersonBuildInterface personBuildInterface) {
        Person bnTangPerson = personBuildInterface.build("BNTang", 23);
        System.out.println(bnTangPerson.getName() + "," + bnTangPerson.getAge());
    }
}

使用说明:Lambda 表达式被构造器替代的时候,它的形式参数全部传递给了构造器作为参数

posted @ 2021-01-29 17:41  BNTang  阅读(101)  评论(0编辑  收藏  举报