0%

java8-方法引用

什么是方法引用

方法引用是lambd表达式的一种特殊形式。看起来更易读更自然

如果想要对苹果的重量进行排序我们可以这样写:

inventory.sort((a1,a2) -> a1.getWeight() - a2.getWeight());

使用方法引用之后是这样的

inventory.sort(Apple::getWeight);

方法引用的语法格式

  1. 指向静态方法的引用
    Class::staticMethod
    
  2. 指向现有对象的实例方法的方法引用
    object::instanceMethod
    
  3. 指向任意类型实例方法的方法引用
    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 redApples = filter(inventory,Apple::getColor,”red”);
可以读作:筛选苹果库存中颜色为红色的苹果
inventory.sort(Comparator.comparing(Apple::getColor));
可以读作:库存根据苹果的颜色进行排序
但是方法引用在某些方面的比较复杂的,比如要将所有苹果的重量加10,需要使用两个方法引用
addWeight(inventory,Apple::getWeight,Apple::setWeight,10);