Java Lambda:方法引用


Java lambda表达式是Java8中的新功能,极大地增强了Java的表达能力。A Javaλ表达式是可以在不属于任何类的情况下创建的匿名(即未命名)方法。相反,它用于实现由功能接口(此接口包含一个且仅包含一个抽象方法,但也可以包含多个系统默认值静电方法)。因此,lambda表达式产生一种匿名类的形式。

方法引用是与lambda表达式相关的一个重要特性,它可以让您重用现有的方法定义,并像传递lambda表达式一样传递它们。它的语法形式为:

  Object :: methodName


在方法引用中,将对象类(或类),它包含要在分隔符之前调用的方法。:: 运算符,方法的名称在该运算符之后提供,不带参数。

有四种类型的方法引用:

类型

句法

兰姆达

静电法

ClassName::staticMethodName

(参数)->ClassName.staticMethodName(参数)

参考现有对象的实例方法

Object::instanceMethodName

(参数)->object.instanceMethodName(参数)

对特定类型的任意对象的实例方法的引用

ClassName::instanceMethodName

(arg0,睡觉)->arg0.instanceMethodName(睡觉)

注意:Argo的类型为ClassName

对构造函数的引用

ClassName::New

(参数)->新类名(参数)

以下各节将介绍这些类型的方法引用中的每一种。

静电方法参考

下面的程序演示静电方法引用。首先,它声明一个名为IntPredicate的函数接口 它有一个名为check()。此方法具有int 参数,并返回一个boolean 价值。因此,它可以用于根据某些条件测试整数值。然后,程序创建一个名为IntPredicatesChecker,它定义了两个静态方法,isEven() isPositive()。在StaticMethodReferenceDemo 类,一个名为numCheck() 是定义的,它有它的第一个参数,即对IntPredicate。它的第二个参数指定要检查的整数。在main()时,调用将执行两种不同的检查numCheck(),传递对要执行的检查的方法引用。

@FunctionalInterface
public interface IntPredicate {
    boolean check(int i);
}

public class IntPredicatesChecker {
    // A static method for checking if  a number is positive
    public static boolean isPositive(int n) {
        return n > 0;
    }

    // A static method for checking if a number is even
    public static boolean isEven(int n) {
        return (n % 2) == 0;
    }
}

public class StaticMethodReferenceDemo {
    public StaticMethodReferenceDemo() {
    }

    // This method takes a functional interface as the type of its first parameter. Thus it can accept a reference to any instance of that
    // interface, including one created by a method reference
    public boolean numCheck(IntPredicate p, int n) {
        return p.check(n);
    }

    public static void main(String[] args) {
        StaticMethodReferenceDemo demo = new StaticMethodReferenceDemo();
        boolean result;
        int num = 9;
        // Here, Using lambda expression to check if a number is even
        IntPredicate lb1 = number -> (number % 2) ==0;
        result = demo.numCheck(lb1, num);
        System.out.println("Using lambda expression: " + num + " is even: " + result);

        // Here, a method reference to  static method isEven of IntPredicatesChecker is passed to numCheck().
        result = demo.numCheck(IntPredicatesChecker::isEven, num);
        System.out.println("Using static method reference: " + num + " is even: " + result);

        // Here, Using lambda expression to check if a number is positive
        IntPredicate lb2 = number -> number > 0;
        result = demo.numCheck(lb2, num);
        System.out.println("Using lambda expression: " + num + " is positive: " + result);

        // Here, a method reference to  static method isPositive of IntPredicatesChecker is passed to numCheck().
        result = demo.numCheck(IntPredicatesChecker::isPositive, num);
        System.out.println("Using static method reference: " + num + " is positive: " + result);

    }
}


程序运行输出为:

Using lambda expression: 9 is even: false
Using static method reference: 9 is even: false
Using lambda expression: 9 is positive: true
Using static method reference: 9 is positive: true


在节目里面,要特别注意这一行:

result = demo.numCheck(IntPredicatesChecker::isEven, num);


此处是对staticmethod的引用isEven() 作为第一个参数传递给numCheck()。请注意,isEven() 方法的方法签名和返回类型与check() 接口的方法代码IntPredicate。所以呢,isEven() IntPredicate 功能界面。

对对象的实例方法的方法引用

语法类似于静电方法参考,除了一个类的对象被使用,而不是使用类名。下面的程序说明了这一点。它使用相同的IntPredicate 接口在上一个程序中。还有一个叫做IntNumChecker,哪一家公司有一个int 实例字段,并定义该方法isBigger()。这将确定对象的实例值num_s是否大于传入的值。

public class IntNumChecker {
    final private int num;

    public IntNumChecker(int num) {
        this.num = num;
    }

    public int getNum() {
        return num;
    }

    // check if num is bigger than the input value n
    boolean isBigger(int n) {
        return num > n;
    }

    public static void main(String[] args) {
        IntNumChecker checker = new IntNumChecker(10);
        int numToCompare = 9;
        IntPredicate p = checker::isBigger;
        boolean result = p.check(numToCompare);
        if (result) {
            System.out.println(checker.num + " is bigger than " + numToCompare);
        }else {
            System.out.println(checker.num + " is smaller or equal than " + numToCompare);
        }
    }
}


该程序的输出为:

10 is bigger than 9


需要特别注意的是这一行:

IntPredicate p = checker::isBigger;

分配给p的方法引用引用Object上的实例方法:isBigger()方格IntNumChecker的。因此,当通过该引用p调用check()时,如下所示:

result = p.check(9);


这种方法,check(),我会打电话给你的isBigger()在对象检查器中。

参数方法参照

在这四种类型中,这种类型是最抽象的。在这种情况下,您可以使用类的名称,而不是使用特定对象。因此,函数接口的第一个参数与调用对象匹配。这就是我们称之为p的原因。参数方法参考。睡觉参数与方法指定的参数(如果有)匹配。下面的示例使用参数方法参照。首先,我们来看一下功能接口,IntNumPredicate,使用一个名为check()。的check()的第一个参数的类型为IntNumChecker 它将用于接受正在操作的对象,第二个参数接受int 价值。*这允许我们创建对实例方法的方法引用isBigger() 可以与任何IntNumChecker  对象(例如,Checker 1和Check 2)。

@FunctionalInterface
public interface IntNumPredicate {
    boolean check(IntNumChecker m, int n);
}

public class IntNumChecker {
    final private int num;

    public IntNumChecker(int num) {
        this.num = num;
    }

    // check if num is bigger than the input value n
    boolean isBigger(int n) {
        return num > n;
    }

    public static void main(String[] args) {
        IntNumChecker checker1 = new IntNumChecker(10);
        int numToCompare = 9;
        IntNumPredicate p = IntNumChecker::isBigger;
        boolean result = p.check(checker1,9);
        if (result) {
            System.out.println(checker1.num + " is bigger than " + numToCompare);
        }else {
            System.out.println(checker1.num + " is smaller  " + numToCompare);
        }

        // second object of IntNumChecker
        IntNumChecker checker2 = new IntNumChecker(8);
        result = p.check(checker2,9);

        if (result) {
            System.out.println(checker2.num + " is bigger than " + numToCompare);
        }else {
            System.out.println(checker2.num + " is smaller " + numToCompare);
        }
    }
}


您需要特别注意这一行:

 IntNumPredicate p = IntNumChecker::isBigger;


分配给Ep的方法引用引用了该方法isBigger() 对象的任何其他对象(例如,checkker1、checkker2)上IntNumChecker

对构造函数的引用

构造函数引用的工作方式类似于对静电方法的引用。在演示的程序中,我们创建了两个函数接口来显示如何使用构造函数引用。在界面中IntSupplier,该apply()方法接受一个int 价值和回报ObjIntCreation对象,而在界面中IntObjectSupplier,该apply() 方法接受ObjIntCreation并返回到一个ObjIntCreation 对象。在main()中,演示了使用构造函数引用创建对象的两个示例。在第一个示例中,apply(num) 方法与apply() 接口中的方法IntSupplier,而在第二个示例中,apply(newObj1)方法,它与apply()接口中的方法IntObjectSupplier

@FunctionalInterface
public interface IntSupplier {
    ObjIntCreation apply(int n);
}

@FunctionalInterface
public interface IntObjectSupplier {
    ObjIntCreation apply(ObjIntCreation obj);
}

public class ObjIntCreation {
    private int num;

    public ObjIntCreation(int num) {
        this.num = num;
    }

    public ObjIntCreation(ObjIntCreation n) {
        this.num = n.num;
    }

    public static void main(String[] args) {

        // using the "IntSupplier" functional interface
        int num = 10;
        IntSupplier s1 = ObjIntCreation::new;
        ObjIntCreation newObj1 = s1.apply(num);
        System.out.println("new object has a instance value " + newObj1.num);

        // using the "IntObjectSupplier" functional interface
        IntObjectSupplier s2 = ObjIntCreation::new;
        ObjIntCreation newObj = s2.apply(newObj1);
        System.out.println("new object has a instance value " + newObj.num);
    }
}


结论

总而言之,可以使用方法引用来使您的代码更简洁和可读性更好。例如,您可以通过将所有代码放在静电方法中并创建对该方法的引用来避免一个方法的限制,而不是使用有很多行的类或λ表达式。希望这能帮上忙。请在下面的评论中告诉我们您的想法!