一、是什么?
方法引用是用来直接访问类或者实例已经存在的方法或者构造方法。
二、哪里能用?
三、怎么理解?
这里以Arrays的sort方法进行讲解:public static <T> void sort(T[] a, Comparator<? super T> c)
public void introduce() { String[] strArray ={"a", "c", "b"}; //在学完lambda表达式后,如果你想创建一个Comparator实例,你可能会用以下方法: Arrays.sort(strArray, (s1,s2)->s1.compareTo(s2)); //你仔细看就会发现整个lambda体其实就只是在调用String类的compareTo()方法而已 //因此我们可以使用方法引用的方式来进行简写 Arrays.sort(strArray,String::compareTo); }
四、有哪些?
- 方法引用 ,形式有三种: 1、实例::实例方法名 2、 类名::静态方法名 3、类名::实例方法名
- 构造器引用 ,形式有一种: 类名::new
- 数组引用 ,形式有一种:类型[]::new
五、具体例子
准备:定义一个person类,字段如下:
public class Person { private String name; private int age; public Person(String name) { this.name = name; } public Person(String name, int age) { this.name = name; this.age = age; } //省略get/set方法... }
1. 实例::实例方法名
public void test1(){ Person person=new Person("小明",18); Supplier<String> supplier=()->person.getName(); System.out.println(supplier.get()); //上面lambda体只用到person实例的getName()方法,因此可以改写成实例::实例方法名 Supplier<String> supplier1=person::getName; System.out.println(supplier1.get()); }
2. 类名::静态方法名
public void test2(){ //普通lambda方式 Comparator<Integer> com = (x, y) -> Integer.compare(x, y); //类名:静态方法名 Comparator<Integer> com2 = Integer::compare; }
3. 类名::实例方法名,前提:Lambda 参数列表的第一个参数,是实例方法的调用者,第二个参数(或无参)是实例方法的参数。
public void test3() { String[] strArray = {"a", "c", "b"}; Arrays.sort(strArray, (s1, s2) -> s1.compareTo(s2)); //lambda的第一个参数s1 是实例方法compareTo()的调用者 //且lambda的第二个参数s2 是compareTo()的参数 Arrays.sort(strArray, String::compareTo); }
4. 类名::new ,前提:构造器的参数列表,需要与函数式接口中参数列表保持一致
public void test4(){ // Function的参数为String,匹配 public Person(String name) Function<String, Person> fun = Person::new; //BiFunction的参数为String,Integer,匹配 public Person(String name, int age) BiFunction<String, Integer, Person> fun2 = Person::new; }
5. 类型[]::new
public void test5() { Function<Integer, String[]> fun = (length) -> new String[length]; String[] strs1 = fun.apply(10); System.out.println(strs1.length); System.out.println("--------------------------"); Function<Integer, String[]> fun2 = String[]::new; String[] strs2 = fun2.apply(20); System.out.println(strs2.length); }
6. 补充:
6.1. 当lambda体调用的方法是父类中的方法或者是当前类中的方法时,可以使用 super::实例方法名 或 this::实例方法名
public class Father { public int add(int a, int b) { return a + b; } } public class Son extends Father { public int add(int a, int b) { return a + b + 2; } public int calculate(BiFunction<Integer, Integer, Integer> function, int a, int b) { return function.apply(a, b); } @Test public void test() { int fatherAdd = calculate(super::add, 1, 2); int sonAdd = calculate(this::add, 1, 2); System.out.println(fatherAdd); System.out.println(sonAdd); } } //运行结果: 3 5
6.2 当lambda体中的方法有泛型是,可以在双冒号:: 之后指定类型。
public interface MyFunc<T> { int func(T[] als, T v); } public class MyArrayOps { //统计v在数组中出现的次数 public static <T> int countMatching(T[] array, T v) { int count = 0; for (T t : array) { if (t.equals(v)) count++; } return count; } } public class Run { public static <T> int myOp(MyFunc<T> f, T[] array, T v) { return f.func(array, v); } public static void main(String[] args) { Integer[] vals = {1, 2, 3, 4, 2, 3, 4, 4, 5}; String[] strs = {"One", "Two", "Three", "Two"}; //不指定MyFunc类型时,可根据后面的参数推断 int count1 = myOp(MyArrayOps::countMatching, vals, 4); System.out.println("vals contains " + count1 + " 4s"); //要指定类型时,可以在::后面指定,指定完可以限制后面两个参数的类型 int count2 = myOp(MyArrayOps::<String>countMatching, strs, "Two"); System.out.println("strs contains " + count2 + " Twos"); } }