JavaEE学习日志持续更新----> 必看!JavaEE学习路线(文章总汇)
Java学习日志(十五)
方法引用
概述
简单来说,方法引用就是对lambda表达式的再次简化
如:存在以下lambda表达式,用来对字符串进行输出
public class Demo01 {
public static void print(String s, Consumer<String> con){
con.accept(s);
}
public static void main(String[] args) {
//lambda表达式
print("HelloWorld", (String s) -> {
System.out.println(s);//HelloWorld
});
//lambda表达式省略形式
print("HelloWorld", s -> System.out.println(s));//HelloWorld
}
}
上述代码中存在以下lambda表达式
print("HelloWorld", s -> System.out.println(s));//HelloWorld
由于System.out对象(PrintStream)已经存在,println方法也已经存在,所以可以使用System.out对象引用println方法对字符串进行输出。
System.out::println (省略了参数)
所以可以使用方法引用对lambda表达式进行再次简化
//方法引用简化lambda表达式
print("HelloWorld",System.out::println);//HelloWorld
方法引用符
符号表示 : :: (双冒号)
符号说明 :双冒号为方法引用运算符,而它所在的表达式被称为方法引用。
应用场景 :如果Lambda要表达的函数方案 , 已经存在于某个方法的实现中,那么则可以使用方法引用。
如上例中,System.out对象中有个println(String)方法 , 恰好就是我们所需要的 , 那么对于Consumer接口作为参数,对比下面两种写法,完全等效:
- Lambda表达式写法:s -> System.out.println(s); 拿到参数之后经Lambda之手,继而传递给System.out.println方法去处理。
- 方法引用写法:System.out::println 直接让System.out中的println方法来取代Lambda。
所以,函数式接口是Lambda的基础,而方法引用是Lambda的简化形式。
常见引用方式
对象名–引用成员方法
若对象已经存在,且对象中的方法也已经存在,则可以使用对象来引用成员方法
格式:对象名::成员方法
示例:对象为String对象,方法为String对象的toUpperCase方法
/*
对象名引用成员方法
*/
public class Demo01 {
/*
定义一个方法
方法的参数传递supplier接口,泛型使用String
*/
public static void getString(Supplier<String> sup){
//使用Supplier接口的方法get,获取一个字符串
String s = sup.get();
System.out.println(s);
}
public static void main(String[] args) {
String s = "helloWorld";//字符串对象,底层是数组
//调用getString方法,方法的参数Supplier是一个函数式接口
getString(()->{
//返回一个大写的字符串
return s.toUpperCase();
});
//简化lambda表达式
getString(()->s.toUpperCase());
//方法引用再次简化lambda表达式
/*
字符串对象s已经存在,字符串中的方法toUpperCase方法也已经存在,
就可以使用对象来引用成员方法
对象名::成员方法
*/
getString(s::toUpperCase);
}
}
所以最终简化了lambda表达式的方法引用为
getString(s::toUpperCase);
类名–引用静态方法
若类已经存在,且类中的静态方法也已经存在,则可以使用类名–引用静态方法
格式:类名::静态方法
示例:类为Math类,静态方法为Math类的random方法
/*
类名引用静态方法
*/
public class Demo01 {
/*
定义一个方法
方法的参数传递Supplier接口,泛型使用double
*/
public static void getDouble(Supplier<Double> sup){
//使用get方法,获取一个随机小数
Double d = sup.get();
System.out.println(d);
}
public static void main(String[] args) {
//调用getDouble方法
getDouble(()->{
//获取一个随机小数
return Math.random();//[0.0-1.0)
});
//简化lambda表达式
getDouble(()-> Math.random());
//方法引用简化lambda
/*
Math类已经存在,random静态方法也已经存在,所以可以使用类名引用静态方法
格式: 类名::静态方法
*/
getDouble(Math::random);
}
}
所以最终简化了lambda表达式的方法引用为
getDouble(Math::random);
类–构造引用
若类的构造方法已经存在,则可以使用构造方法的名称引用new来创建对象
格式:构造方法的名称::new
示例:类为自定义类Person,构造方法已存在
Person类的构造方法
public Person(String name) {
this.name = name;
}
/*
类--构造引用
*/
public class Demo01 {
/*
定义一个方法
参数传递一个字符串的姓名
参数传递Function接口,泛型使用<String,Person>
*/
public static void getPerson(String name, Function<String, Person> fun) {
//使用Function接口中的方法apply
Person p = fun.apply(name);
System.out.println(p);
}
public static void main(String[] args) {
//调用getPerson方法
getPerson("aaa", (String name) -> {
return new Person(name);
});
//简化lambda
getPerson("aaa", name -> new Person(name));
//方法引用简化lambda
/*
Person类的构造方法已经存在,所以可以使用构造方法的名称引用new创建对象
目的就是使用构造方法,根据姓名创建对象
构造方法的名称::new
*/
getPerson("aaa", Person::new);
}
}
所以最终简化了lambda表达式的方法引用为
getPerson("aaa", Person::new);
数组–构造引用
若数组的数据类型已经存在,则可以使用int[]引用new来创建一个指定长度的数组
格式:数据类型[]::new
示例:数组的数据类型为int
/*
数组--构造引用
*/
public class Demo01 {
/*
创建一个方法
参数传递int类型的数组长度
传递Function接口,泛型使用<Integer,int[]>
*/
public static void getArray(int n, Function<Integer, int[]> fun) {
//使用Function接口中的apply方法
int[] arr = fun.apply(n);
System.out.println(Arrays.toString(arr));//[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
}
public static void main(String[] args) {
//调用getArray方法
getArray(10, (Integer i) -> {
//根据数组的长度,创建数组对象并返回
return new int[i];
});
//简化lambda
getArray(10, i -> new int[i]);
//方法引用再简化lambda
/*
数组的数据类型已经存在,创建数组的动作为new,所以可以使用
格式: 数据类型[]::new
*/
getArray(10, int[]::new);
}
}
所以最终简化了lambda表达式的方法引用为
getArray(10, int[]::new);