java8新特性:方法引用
我们用Lambda表达式来实现匿名方法。但有些情况下,我们用Lambda表达式仅仅是调用一些已经存在的方法,除了调用动作外,没有其他任何多余的动作,在这种情况下,我们倾向于通过方法名来调用它,而Lambda表达式可以帮助我们实现这一要求,它使得Lambda在调用那些已经拥有方法名的方法的代码更简洁、更容易理解。方法引用可以理解为Lambda表达式的另外一种表现形式。
在Lambda表达式中,将其划分了几块。这一行就是lambda表达式。
() -> System.out.println("使用Lambda表达式");
下面我们对lambda的格式进行一个介绍:
(1)左边括号:lambda的形参列表,就好比是我们定义一个接口,里面有一个抽象方法,这个抽象方法的形参列表。
(2)箭头:lambda的操作符,所以你看见这个箭头心中知道这是一个lambda表达式就可以了。
(3)右边lambda体:就好比是我们实现了接口中的抽象方法。
在最后一块中,有时候,lambda体可能仅仅调用一个已存在的方法,而不做任何其它事,对于这种情况,通过一个方法名字来引用这个已存在的方法会更加清晰。
所以我们来总结:方法引用是一个更加紧凑,易读的 Lambda 表达式,注意方法引用是一个 Lambda 表达式,其中方法引用的操作符是双冒号 "::"
类型 | 语法 | 对应的Lambda表达式 |
---|---|---|
静态方法引用 | 类名::staticMethod | (args) -> 类名.staticMethod(args) |
实例方法引用 | inst::instMethod | (args) -> inst.instMethod(args) |
对象方法引用 | 类名::instMethod | (inst,args) -> 类名.instMethod(args) |
构建方法引用 | 类名::new | (args) -> new 类名(args) |
方法引用举例
静态方法引用
有一个Person类,如下所示:
@Data //用了注解后,setter/getter, 构造函数,toString,hashCode,equals方法由框架生成 public class Person { private String name; private Integer age; //静态方法 public static int compareByAge(Person a, Person b) { return a.age.compareTo(b.age); //两个年龄比大小 } }
现假设,一个部门有30人,把他们存放在一个数组中,并按年龄排序,通常我们可以自己写一个比较器,代码如下:
Person[] rosterAsArray = new Person[30]; // 添加数组元素省略 class PersonAgeComparator implements Comparator<Person> { public int compare(Person a, Person b) { return a.getBirthday().compareTo(b.getBirthday()); } } Arrays.sort(rosterAsArray, new PersonAgeComparator());
Arrays.sort的声明为:public static <T> void sort(T[] a, Comparator<? super T> c),比较器参数Comparator为一个函数式接口,利用上一节Lambda表达式所学知识,可以改写为以下代码:
Person[] rosterAsArray = new Person[30];
// 添加数组元素省略
Arrays.sort(rosterAsArray, (a,b) -> a.getAge().compareTo(b.getAge()));
然而,你会发现,Perdon类中已经有了一个静态方法的比较器:compareByAge,因此,我们改用Person类已经提供的比较器:
Person[] rosterAsArray = new Person[30];
// 添加数组元素省略
Arrays.sort(rosterAsArray, (a,b) -> Person.compareByAge(a,b));
以上代码,因为Lambda表达式调用了一个已经存在的静态方法,根据我们第2节表格中的语法,上面的代码可以最终改写成静态方法引用:
Person[] rosterAsArray = new Person[30];
// 添加数组元素省略
Arrays.sort(rosterAsArray, Person::compareByAge);
下面这个例子更简单:
public class Test { public static void main(String[] args) { List<Integer> list = Arrays.asList(82,22,34,50,9); list.sort(Integer::compare); System.out.println(list); } }
对一个Integer列表进行排序,因为Integer中已经存在静态的比较方法compare(),因此可以直接用静态方法引用的方式来调用 ,运行结果为:
[9, 22, 34, 50, 82]
实例方法引用
实例方法引用,顾名思义就是调用已经存在的实例的方法,与静态方法引用不同的是类要先实例化,静态方法引用类无需实例化,直接用类名去调用。
@Data class User { private String name; private Integer age; public User(String name, Integer age) { this.name = name; this.age = age; } } public class TestInstanceReference { public static void main(String[] args) { TestInstanceReference test = new TestInstanceReference(); User user = new User("欧阳峰",32); Supplier<String> supplier = () -> user.getName();//Supplier的get方法的匿名实现 System.out.println("Lambda表达式输出结果:" + supplier.get()); /* user::getName本质是Supplier接口中的抽象get方法的匿名实现 */ Supplier<String> supplier2 = user::getName; System.out.println("实例方法引用输出结果:" + supplier2.get()); } }
输出结果:
Lambda表达式输出结果:欧阳峰
实例方法引用输出结果:欧阳峰
对象方法引用
若Lambda参数列表中的第一个参数是实例方法的参数调用者,而第二个参数是实例方法的参数时,可以使用对象方法引用。
String的equals()方法:
public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = value.length; if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } return false; } public static void main(String[] args) { BiPredicate<String,String> bp = (x, y) -> x.equals(y); BiPredicate<String,String> bp1 = String::equals; boolean test = bp1.test("xy", "xx"); System.out.println(test); }
BiPredicate的test()方法接受两个参数,x和y,具体实现为x.equals(y),满足Lambda参数列表中的第一个参数是实例方法的参数调用者,而第二个参数是实例方法的参数,因此可以使用对象方法引用。
构造方法引用
注意:需要调用的构造器的参数列表要与函数式接口中抽象方法的参数列表保持一致。
如:要获取一个空的User列表:
Supplier<List<User>> userSupplier = () -> new ArrayList<>(); List<User> user = userSupplier.get(); Supplier<List<User>> userSupplier2 = ArrayList<User>::new; // 构造方法引用写法 List<User> user2 = userSupplier.get();
标签:特性,Person,引用,new,方法,java8,表达式,Lambda From: https://www.cnblogs.com/huang2979127746/p/16665212.html