方法引用的出现原因
在使用 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 表达式被构造器替代的时候,它的形式参数全部传递给了构造器作为参数