java8方法引用

Posted yuanbing1226

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java8方法引用相关的知识,希望对你有一定的参考价值。

在java中我们可以通过创建新的对象来使用对象的引用

    List<String> list = new ArrayList<>();
    store(list);

那么对于方法呢,如果我们想在另一个方法中使用对象的方法,那么就必须将对象传递到这个方法中。试想以下,我们把方法的行为当参数传递会不会更好呢。在java8中,lambda表达式可以轻松做到这一点,方法引用的语法是 Object :: methodName。

    Consumer<String> c = s -> System.out.println(s);
    
    为了使代码更清晰,可以将lambda表达式转换为方法引用。
    
    Consumer<String> c = System.out :: println;

在方法引用中,将包含该方法的对象(或类)放在::运算符之前,并将该方法的名称放在没有参数的位置之后。首先,方法引用不能用于任何方法。它只能用于替换单个方法的lambda表达式。要使用lambda表达式,首先得有一个
函数接口,即一个只有一个抽象方法的函数接口。

几种类型的方法引用
  • 1 对静态方法的方法引用。
  • 2 对特定类型对象的示例方法的方法引用。
  • 3 对现有对象实例方法的方法引用。
  • 4 对构造函数的方法引用。
静态方法的方法引用
    (args)-> Class.staticMethod(args);
     Class :: staticMethod;
 

我们用方法引用符号 :: 代替 . ,并且不会将参数传递给方法引用,通常我们不必将参数传递给方法引用。但是参数取决于方法引用的类型。
在这种情况下,该方法采用的任何参数(如果有的话)会自动传递到后面。请看下例

    public static boolean isMoreThanFifty(int n1, int n2) {
        return (n1 + n2) > 50;
    }
    
    public static List<Integer> findNumbers(List<Integer> l, BiPredicate<Integer, Integer> p) {
        
        return l.stream()
                .filter(i -> p.test(i, i + 10))
                .collect(Collectors.toList());
    }

    /*
     * 使用匿名内部类实现
     */
    String s1 = findNumbers(list, new BiPredicate<Integer, Integer>() {

        @Override
        public boolean test(Integer t, Integer u) {
            
            return (t + u) > 50;
        }
    }).toString();
    System.out.println("s1 : " + s1);
    
    /**
     * 使用lambda表达式
     */
    String s2 = findNumbers(list, (i1, i2) -> Numbers.isMoreThanFifty(i1, i2)).toString();
    System.out.println("s2 : " + s2);
    /**
     * 使用方法引用
     */
    String s3 = findNumbers(list, Numbers :: isMoreThanFifty).toString();
    System.out.println("s3 : " + s3);

    //console log
    s1 : [45, 33, 24, 40]
    s2 : [45, 33, 24, 40]
    s3 : [45, 33, 24, 40]
对特定类型对象的示例方法的方法引用

我们有如下lambda表达式

    (obj, args) -> obj.instanceMethod(args)
    

如果一个对象的实例被传递,并且它的一个方法被执行了一些可选的参数,这可以转化为以下方法引用。

    ObjectType::instanceMethod
    
    public double calculateWeight() {
        double weight = 0;
        // Calculate weight
        return weight;
    }
    
    public void test() {
        List<Shipment> l = new ArrayList<Shipment>();

        // Using an anonymous class
        calculateOnShipments(l, new Function<Shipment, Double>() {
          public Double apply(Shipment s) { // The object
            return s.calculateWeight(); // The method
          }
        });

        // Using a lambda expression
        calculateOnShipments(l, s -> s.calculateWeight());

        // Using a method reference
        calculateOnShipments(l, Shipment::calculateWeight);
    }
    
对现有对象实例方法的方法引用
    public class Car {
        private String id;
        private String color;
    }
    
    public void execute(Car car, Consumer<Car> c) {
        c.accept(car);
    }
    
    execute(car, mechanic::fix);
对构造函数的方法引用
    Supplier<List<String>> supplier = new Supplier<List<String>>() {

        @Override
        public List<String> get() {
            return new ArrayList<String>();
        }
    };
    
    Supplier<List<String>> supplier2 = () -> new ArrayList<String>();
    
    Supplier<List<String>> supplier3 = ArrayList::new;
    
    /*
     * 如果构造函数有一个参数,可以使用Function接口。构造函数是两个参数的,可以使用BiFunction,如果是三个参数的话,则不得不创建以自己的函数接口了。
     */
    Function<String, Integer> function = Integer::new;
    
    BiFunction<String, String, Locale> biFunction = new BiFunction<String, String, Locale>() {

        @Override
        public Locale apply(String t, String u) {
            return new Locale(u, t);
        }
    };
    
    biFunction = (lang, country) -> new Locale(lang, country);
    
    biFunction = Locale::new;
    
结束语

在编程中使用方法引用,可以优化lambda,这样的代码更加简介,富于表达。上文中引用的代码可以在GitHub上进行下载

java8方法引用
为什么完美的lambda表达式只有一行
java8函数式编程







以上是关于java8方法引用的主要内容,如果未能解决你的问题,请参考以下文章

Java8——方法引用和构造器引用

Java8新特性:函数式接口,方法与构造器引用

java8的特性都有哪些

从java8迁移到java9时,对方法的引用是不明确的

java8的lambda表达式及方法引用

java8的lambda表达式及方法引用