什么是方法引用
方法引用是lambd表达式的一种特殊形式。看起来更易读更自然
如果想要对苹果的重量进行排序我们可以这样写:
inventory.sort((a1,a2) -> a1.getWeight() - a2.getWeight());
使用方法引用之后是这样的
inventory.sort(Apple::getWeight);
方法引用的语法格式
- 指向静态方法的引用
Class::staticMethod
- 指向现有对象的实例方法的方法引用
object::instanceMethod
- 指向任意类型实例方法的方法引用
Class::instanceMethod
语法简述
指向静态方法的引用
类的静态方法必须满足函数描述符,也就是Class.staticMethod的参数和返回值要和函数描述符一致
对于Function<Integer,Integer> function = Class::staticMethod;
Class的staticMethod的静态方法定义应该是:
public static intstaticMethod(int number){
//一个返回int类型的代码块
}
对于Consumer consumer = Class:staticMethod;
Class的staticMethod的静态方法定义应该是:
public static void staticMethod(int number){
//没有返回值的代码块
}
对于Predicate pred = Class::staticMethod;
Class.staticMethod的静态方法定义应该是:
public static boolean staticMethod(int number){
//返回boolean类型的代码块
}
对于Supplier supplier = Class::staticMethod;
Class.staticMethod的静态方法定义应该是:
public static int staticMethod(){
//返回int类型的代码块
}
指向现有对象的实例方法的方法引用
类的实例方法必须满足函数描述符,也就是对象调用的方法的参数和返回值要和函数描述法一致
对于Function<Class,Integer> function = object::instanceMethod;
Class的实例方法定义应该是:
public int instanceMethod(){
//返回int类型的代码块
}
如果是BiFunction<Class,Integer,Integer> function = object::instanceMethod;
Class的实例方法定义应该是:
public int instacneMethod(int number){
//返回int类型的代码块
}
下同
对于Consumer<Class,Integer> consumer = object::instanceMethod;
Class的实例方法定义应该是:
public void instacneMethod(int number){
//没有返回值的代码块
}
对于Predicate predicate = object::instanceMethod;
Class的实例方法定义应该是:
public boolean instanceMethod(){
//返回boolean类型的代码块
}
对于Suplier supplier = object::instanceMethod;
Class的实例方法定义应该是:
public int instanceMethod(){
//返回int类型的代码块
对于第三种格式,函数描述符至少含有一个参数,也就是说必须有一个参数用来调用方法
对于Function<Class,Integer> function = Class::instanceMethod;
Class的实例方法定义应该是:
public int instanceMethod(){
//返回int类型的代码块
}
对于Function<Class,Integer,Integer> function = Class::instanceMethod;
Class的实例方法定义应该是:
public int instanceMethod(int number){
//返回int类型的代码块
}
对于Consumer consumer = Class::instanceMethod;
Class的实例方法定义应该是:
public void instanceMethod(){
//没有返回值的代码块
}
对于Comparator<Class,Class> comparator = Class::instanceMethod;
Class的实例方法定义应该是:
public int instanceMethod(Class clazz){
//比较两个数大小的代码块,最后返回一个数用来表示大于,小于,等于
}
实例:
使用方法引用来完成列表苹果的筛选,排序,输出,增加重量,返回对应的苹果重量列表
Apple.java
public class Apple {
private int weight;
private String color;
//getter setter
}
Main.java
public class Main {
public static void main(String[] args) {
List<Apple> inventory = Arrays.asList(
new Apple(10,"green"),
new Apple(20,"red"),
new Apple(12,"red"),
new Apple(25,"green"));
List<String> strs = Arrays.asList(
"red","green","red","black"
);
//筛选
List<Apple> redApples = filter(inventory,Apple::getColor,"red");
forEach(redApples,System.out::println);
List<String> red = filter(strs,String::toString,"red");
forEach(red,System.out::println);
//将所有苹果的重量表示为一个列表
List<Integer> appleWeight = map(inventory,Apple::getWeight);
forEach(appleWeight,System.out::println);
//将所有苹果的重量加10
addWeight(inventory,Apple::getWeight,Apple::setWeight,10);
forEach(inventory,System.out::println);
//排序
inventory.sort(Comparator.comparing(Apple::getColor));
forEach(inventory,System.out::println);
}
public static <T> void forEach(List<T> inventory,Consumer<T> consumer) {
for(T t : inventory) {
consumer.accept(t);
}
}
public static <T> void addWeight(List<T> inventory,ToIntFunction<T> func,ObjIntConsumer<T> consumer,int added) {
for(T t : inventory) {
consumer.accept(t,func.applyAsInt(t) + added);
}
}
public static <T,R> List<R> map(List<T> inventory,Function<T,R> func){
List<R> result = new ArrayList<>();
for(T t : inventory) {
result.add(func.apply(t));
}
return result;
}
public static <T,R> List<T> filter(List<T> inventory,Function<T,R> func,Object obj){
List<T> result = new ArrayList<>();
for(T t : inventory) {
if(func.apply(t).equals(obj)) {
result.add(t);
}
}
return result;
}
}
可以看见方法引用的可读性是要强于lanbda表达式的,如:
List
可以读作:筛选苹果库存中颜色为红色的苹果
inventory.sort(Comparator.comparing(Apple::getColor));
可以读作:库存根据苹果的颜色进行排序
但是方法引用在某些方面的比较复杂的,比如要将所有苹果的重量加10,需要使用两个方法引用
addWeight(inventory,Apple::getWeight,Apple::setWeight,10);