Java 8方法引用,双冒号(::)运算符

在Java 8中,双冒号(::)运算符称为方法引用。 请参考以下示例:

匿名类打印列表。

List list = Arrays.asList("node", "java", "python", "ruby");
list.forEach(new Consumer() {       // anonymous class
    @Override
    public void accept(String str) {
        System.out.println(str);
    }
});

匿名类-> Lambda表达式。

List list = Arrays.asList("node", "java", "python", "ruby");
list.forEach(str -> System.out.println(str)); // lambda

Lambda表达式->方法引用。

List list = Arrays.asList("node", "java", "python", "ruby");
list.forEach(System.out::println);          // method references

匿名类-> Lambda表达式->方法参考

注意
lambda表达式或方法引用都不执行任何操作,只是对现有方法的另一种调用。 使用方法参考,可以获得更好的可读性。

有四种方法参考:

  • 引用静态方法ClassName::staticMethodName
  • 引用特定对象Object::instanceMethodName的实例方法
  • 引用特定类型ContainingType::methodName的任意对象的实例方法–
  • 引用构造函数ClassName::new

1.静态方法

Lambda表达式。

(args) -> ClassName.staticMethodName(args)

方法参考。

ClassName::staticMethodName

1.1此示例打印一个字符串列表,该列表引用了静态方法SimplePrinter::print

Java8MethodReference1a.java
package com.mkyong;

import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;

public class Java8MethodReference1a {

    public static void main(String[] args) {

        List list = Arrays.asList("A", "B", "C");

        // anonymous class
        list.forEach(new Consumer() {
            @Override
            public void accept(String x) {
                SimplePrinter.print(x);
            }
        });

        // lambda expression
        list.forEach(x -> SimplePrinter.print(x));

        // method reference
        list.forEach(SimplePrinter::print);

    }

}

class SimplePrinter {
    public static void print(String str) {
        System.out.println(str);
    }
}

1.2此示例将字符串列表转换为整数列表,该方法引用静态方法Integer::parseInt

Integer.java
public static int parseInt(String s) throws NumberFormatException {
        return parseInt(s,10);
  }
Java8MethodReference1b.java
package com.mkyong;

import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

public class Java8MethodReference1b {

    public static void main(String[] args) {

        List list = Arrays.asList("1", "2", "3");

        // anonymous class
        List collect1 = list.stream()
                .map(new Function() {
                    @Override
                    public Integer apply(String s) {
                        return Integer.parseInt(s);
                    }
                })
                .collect(Collectors.toList());

        // lambda expression
        List collect2 = list.stream()
                .map(s -> Integer.parseInt(s))
                .collect(Collectors.toList());

        // method reference
        List collect3 = list.stream()
                .map(Integer::parseInt)
                .collect(Collectors.toList());

    }

}

1.3本示例将两个Integer连接起来并返回String 它将方法引用静态方法IntegerUtils::join作为参数传递给另一个接受BiFunction方法。

Java8MethodReference1c.java
package com.mkyong;

import java.util.function.BiFunction;

public class Java8MethodReference1c {

    public static void main(String[] args) {

        // anonymous class
        String result1 = playTwoArgument(1, 2, new BiFunction() {
                  @Override
                  public String apply(Integer a, Integer b) {
                      return IntegerUtils.join(a, b);
                  }
              });                                                                   // 3

        // lambda
        String result1 = playTwoArgument(1, 2, (a, b) -> IntegerUtils.join(a, b));  // 3

        // method reference
        String result2 = playTwoArgument(1, 2, IntegerUtils::join);                 // 3

    }

    private static  R playTwoArgument(Integer i1, Integer i2,
        BiFunction func) {
        return func.apply(i1, i2);
    }

}

class IntegerUtils{

    public static String join(Integer a, Integer b) {
        return String.valueOf(a + b);
    }

}

2.引用特定对象的实例方法

Lambda表达式。

(args) -> object.instanceMethodName(args)

方法参考。

object::instanceMethodName

2.1此示例按薪水对Employee列表进行排序。 我们可以引用特定对象ComparatorProvider的实例方法compareBySalary

Java8MethodReference2
package com.mkyong;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;

public class Java8MethodReference2 {

    public static void main(String[] args) {

        List list = Arrays.asList(
                new Employee("mkyong", 38, BigDecimal.valueOf(3800)),
                new Employee("zilap", 5, BigDecimal.valueOf(100)),
                new Employee("ali", 25, BigDecimal.valueOf(2500)),
                new Employee("unknown", 99, BigDecimal.valueOf(9999)));

        // anonymous class
        /*list.sort(new Comparator() {
            @Override
            public int compare(Employee o1, Employee o2) {
                return provider.compareBySalary(o1, o2);
            }
        });*/

        ComparatorProvider provider = new ComparatorProvider();

        // lambda
        // list.sort((o1, o2) -> provider.compareBySalary(o1, o2));

        // method reference
        list.sort(provider::compareBySalary);

        list.forEach(x -> System.out.println(x));

    }

}

class ComparatorProvider {

    public int compareByAge(Employee o1, Employee o2) {
        return o1.getAge().compareTo(o2.getAge());
    }

    public int compareByName(Employee o1, Employee o2) {
        return o1.getName().compareTo(o2.getName());
    }

    public int compareBySalary(Employee o1, Employee o2) {
        return o1.getAge().compareTo(o2.getAge());
    }

}
Employee.java
package com.mkyong;

import java.math.BigDecimal;

public class Employee {

    String name;
    Integer age;
    BigDecimal salary;

    // generated by IDE, getters, setters, constructor, toString
}

输出量

Employee{name='zilap', age=5, salary=100}
Employee{name='ali', age=25, salary=2500}
Employee{name='mkyong', age=38, salary=3800}
Employee{name='unknown', age=99, salary=9999}

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

该语句有点混乱,需要很少的解释,请参见以下示例:

Lambda表达式。

// arg0 is the first argument
(arg0, rest_of_args) -> arg0.methodName(rest_of_args)

// example, assume a and b are String
(a, b) -> a.compareToIgnoreCase(b)

方法参考。

// first argument type
arg0_Type::methodName

// arg0 is type of ClassName
ClassName::methodName

// example, a is type of String
String::compareToIgnoreCase

对于(String a, String b) ,其中ab是任意名称,而String是其任意类型。 本示例使用方法引用特定类型String的任意对象a (第一个参数)的实例方法compareToIgnoreCase

3.1查看此方法参考中的官方示例

String[] stringArray = { "Barbara", "James", "Mary", "John",
                "Patricia", "Robert", "Michael", "Linda" };
  Arrays.sort(stringArray, String::compareToIgnoreCase);

我们传递了一个方法参考String::compareToIgnoreCase作为Arrays.sort的比较器。

说明
查看Arrays.sort方法签名:

public static  void sort(T[] a, Comparator c) {
}

在上面的示例中, Arrays.sort需要Comparator Comparator是一个函数接口,其抽象方法compare匹配BiFunction ,它接受String两个参数并返回一个int

Comparator.java
@FunctionalInterface
public interface Comparator {
    int compare(T o1, T o2);  // this matches BiFunction
}

查看BiFunction方法签名:

BiFunction.java
@FunctionalInterface
public interface BiFunction {
      R apply(T t, U u);
}

进一步阅读– Java 8 BiFunction示例

下面的lambda提供了BiFunction ,因此Arrays.sort接受下面的lambda表达式作为有效语法。

(String a, String b) -> a.compareToIgnoreCase(b) // return int

// a is type of String
// method reference
String::compareToIgnoreCase

3.2让我们看看另一个例子。

Java8MethodReference3a.java
package com.mkyong;

import java.util.function.BiPredicate;
import java.util.function.Function;

public class Java8MethodReference3a {

    public static void main(String[] args) {

        // lambda
        int result = playOneArgument("mkyong", x -> x.length());   // 6

        // method reference
        int result2 = playOneArgument("mkyong", String::length);   // 6

        // lambda
        Boolean result3 = playTwoArgument("mkyong", "y", (a, b) -> a.contains(b)); // true

        // method reference
        Boolean result4 = playTwoArgument("mkyong", "y", String::contains);        // true

        // lambda
        Boolean result5 = playTwoArgument("mkyong", "1", (a, b) -> a.startsWith(b)); // false

        // method reference
        Boolean result6 = playTwoArgument("mkyong", "y", String::startsWith);        // false

        System.out.println(result6);
    }

    static  R playOneArgument(String s1, Function func) {
        return func.apply(s1);
    }

    static Boolean playTwoArgument(String s1, String s2, BiPredicate func) {
        return func.test(s1, s2);
    }

}

3.3让我们看看另一个示例,自定义对象。

Java8MethodReference3b.java
package com.mkyong;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.function.BiFunction;

public class Java8MethodReference3b {

    public static void main(String[] args) {

        Invoice obj = new Invoice("A001", BigDecimal.valueOf(1.99), 3);

        InvoiceCalculator formula = new InvoiceCalculator();

        // lambda
        BigDecimal result = calculate(formula, obj, (f, o) -> f.normal(o));         // 5.97

        // method reference
        BigDecimal result2 = calculate(formula, obj, InvoiceCalculator::normal);    // 5.97

        // lambda
        BigDecimal result3 = calculate(formula, obj, (f, o) -> f.promotion(o));     // 5.37

        // method reference
        BigDecimal result4 = calculate(formula, obj, InvoiceCalculator::promotion); // 5.37

    }

    static BigDecimal calculate(InvoiceCalculator formula, Invoice s1,
                                BiFunction func) {
        return func.apply(formula, s1);
    }

}

class InvoiceCalculator {

    public BigDecimal normal(Invoice obj) {
        return obj.getUnitPrice().multiply(BigDecimal.valueOf(obj.qty));
    }

    public BigDecimal promotion(Invoice obj) {
        return obj.getUnitPrice()
                .multiply(BigDecimal.valueOf(obj.qty))
                .multiply(BigDecimal.valueOf(0.9))
                .setScale(2, RoundingMode.HALF_UP);
    }
}

class Invoice {

    String no;
    BigDecimal unitPrice;
    Integer qty;

    // generated by IDE, setters, gettes, constructor, toString
}

第一个参数是InvoiceCalculator的类型。 因此,我们可以引用特定类型InvoiceCalculator的任意对象( f )的实例方法( normal or promotion )。

(f, o) -> f.normal(o))
(f, o) -> f.promotion(o))

InvoiceCalculator::normal
InvoiceCalculator::promotion

得到它了? 没有更多的例子

4.引用构造函数。

Lambda表达式。

(args) -> new ClassName(args)

方法参考。

ClassName::new

4.1引用默认构造函数。

Java8MethodReference4a.java
package com.mkyong;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;

public class Java8MethodReference4a {

    public static void main(String[] args) {

        // lambda
        Supplier obj1 = () -> new HashMap();   // default HashMap() constructor
        Map map1 = obj1.get();

        // method reference
        Supplier obj2 = HashMap::new;
        Map map2 = obj2.get();

        // lambda
        Supplier obj3 = () -> new Invoice(); // default Invoice() constructor
        Invoice invoice1 = obj3.get();

        // method reference
        Supplier obj4 = Invoice::new;
        Invoice invoice2 = obj4.get();

    }

}

class Invoice {

    String no;
    BigDecimal unitPrice;
    Integer qty;

    public Invoice() {
    }

    //... generated by IDE
}

4.2引用接受参数的构造方法– Invoice(BigDecimal unitPrice)

Java8MethodReference4b.java
package com.mkyong;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;

public class Java8MethodReference4b {

    public static void main(String[] args) {

        List list = Arrays.asList(
                BigDecimal.valueOf(9.99),
                BigDecimal.valueOf(2.99),
                BigDecimal.valueOf(8.99));

        // lambda
        // List invoices = fakeInvoice(list, (price) -> new Invoice(price));

        // method reference
        List invoices = fakeInvoice(list, Invoice::new);

        invoices.forEach(System.out::println);
    }

    static List fakeInvoice(List list, Function func) {
        List result = new ArrayList<>();

        for (BigDecimal amount : list) {
            result.add(func.apply(amount));
        }
        return result;
    }

}

class Invoice {

    String no;
    BigDecimal unitPrice;
    Integer qty;

    public Invoice(BigDecimal unitPrice) {
        this.unitPrice = unitPrice;
    }

    //... generated by IDE
}

输出量

Invoice{no='null', unitPrice=9.99, qty=null}
Invoice{no='null', unitPrice=2.99, qty=null}
Invoice{no='null', unitPrice=8.99, qty=null}

做完了

参考文献

  • Java 8方法参考:如何使用它
  • 了解Java 8方法参考
  • Lambda表达式的翻译
  • Java教程–方法参考
  • Java 8教程
  • Java 8函数示例
  • Java 8 BiFunction示例
  • Java 8谓词示例
  • Java 8 BiPredicate示例
  • Java 8供应商示例

翻译自: https://mkyong.com/java8/java-8-method-references-double-colon-operator/

你可能感兴趣的:(Java 8方法引用,双冒号(::)运算符)