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

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

匿名类打印列表。

 

List<String> list = Arrays.asList("node", "java", "python", "ruby");

list.forEach(new Consumer<String>() {       // anonymous class

    @Override

    public void accept(String str) {

        System.out.println(str);

    }

});

匿名类-> Lambda表达式。

 

List<String> list = Arrays.asList("node", "java", "python", "ruby");

list.forEach(str -> System.out.println(str)); // lambda

Lambda表达式->方法引用。

 

List<String> 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<String> list = Arrays.asList("A", "B", "C");

 

        // anonymous class

        list.forEach(new Consumer<String>() {

            @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此示例将String列表转换为Integers列表,该方法引用静态方法Integer::parseInt

整数.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<String> list = Arrays.asList("1", "2", "3");

 

        // anonymous class

        List<Integer> collect1 = list.stream()

                .map(new Function<String, Integer>() {

                    @Override

                    public Integer apply(String s) {

                        return Integer.parseInt(s);

                    }

                })

                .collect(Collectors.toList());

 

        // lambda expression

        List<Integer> collect2 = list.stream()

                .map(s -> Integer.parseInt(s))

                .collect(Collectors.toList());

 

        // method reference

        List<Integer> 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<Integer, Integer, String>() {

                  @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> R playTwoArgument(Integer i1, Integer i2,

        BiFunction<Integer, Integer, R> 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按薪水排序列表。我们可以参考compareBySalary特定对象的实例方法ComparatorProvider

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<Employee> 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<Employee>() {

            @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是其任意类型。此示例使用方法引用来引用特定类型compareToIgnoreCase的任意对象a(第一个参数)的实例方法String

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 <T> void sort(T[] a, Comparator<? super T> c) {

}

在以上示例中,Arrays.sort期望为Comparator<String>。的Comparator是一个功能接口,其抽象方法compare匹配BiFunction<String, String, Integer>,它需要的两个参数,String并返回一个int

比较器

 

@FunctionalInterface

public interface Comparator<T> {

    int compare(T o1, T o2);  // this matches BiFunction<String, String, Integer>

}

查看BiFunction方法签名:

BiFunction.java

 

@FunctionalInterface

public interface BiFunction<T, U, R> {

      R apply(T t, U u);

}

进一步阅读– Java 8 BiFunction示例

下面的lambda提供了的实现BiFunction<String,String,Integer>,因此Arrays.sortaccept接受下面的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> R playOneArgument(String s1, Function<String, R> func) {

        return func.apply(s1);

    }

 

    static Boolean playTwoArgument(String s1, String s2, BiPredicate<String, String> 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<InvoiceCalculator, Invoice, BigDecimal> 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。因此,我们可以引用特定类型normal or promotion的任意对象(f)的实例方法()InvoiceCalculator

 

(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<Map> obj1 = () -> new HashMap();   // default HashMap() constructor

        Map map1 = obj1.get();

 

        // method reference

        Supplier<Map> obj2 = HashMap::new;

        Map map2 = obj2.get();

 

        // lambda

        Supplier<Invoice> obj3 = () -> new Invoice(); // default Invoice() constructor

        Invoice invoice1 = obj3.get();

 

        // method reference

        Supplier<Invoice> 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<BigDecimal> list = Arrays.asList(

                BigDecimal.valueOf(9.99),

                BigDecimal.valueOf(2.99),

                BigDecimal.valueOf(8.99));

 

        // lambda

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

 

        // method reference

        List<Invoice> invoices = fakeInvoice(list, Invoice::new);

 

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

    }

 

    static List<Invoice> fakeInvoice(List<BigDecimal> list, Function<BigDecimal, Invoice> func) {

        List<Invoice> 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}

完毕。

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值