上一节介绍了Java8新特性中的Lambda表达式,
本小节继续讲解Java8的新特性之二:方法引用。方法引用其实也离不开Lambda表达式。
我们用Lambda表达式来实现匿名方法。
但有些情况下,我们用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类,有一个比比较方法
//lombok注解 自动生成getter setter tostring方法
@Data
public class Person {
private String name;
private Integer age;
public static int compareByAge(Person a, Person b) {
return a.age.compareTo(b.age);
}
public Person(String name,Integer age){
this.name=name;
this.age=age;
}
//compareto的具体实现代码
// public static int compare(int x, int y) {
// return x < y ? -1 : (x == y ? 0 : 1);
//}
}
现假设,一个部门有2人,把他们存放在一个数组中,并按年龄排序,通常我们可以自己写一个比较器,代码如下:
import java.util.Arrays;
import java.util.Comparator;
public class YinYong {
public static void main(String[] args) {
// 可以弄一万个用户
Person person1=new Person("小王",24);
Person person2=new Person("小李",23);
Person[] list = new Person[2];
list[0]=person1;
list[1]=person2;
// public static <T> void sort(T[] a, Comparator<? super T> c)
// 这个是sort的定义,第二个参数要是一个comparator 这没问题 所以直接使用
// Arrays.sort(list, new PersonAgeComparator());
//然后用lambda表达式来写一下 不用
Arrays.sort(list,(a,b)->a.getAge().compareTo(b.getAge()));
for (int i = 0; i <list.length ; i++) {
System.out.println(list[i]);
};
// 然后你发现 你不是在类里面写了一个比较器吗?直接用不久好了
Arrays.sort(list, (a,b) -> Person.compareByAge(a,b));
//因为这个一个静态方法,使用方法引用 这代码简洁的
Arrays.sort(list,Person::compareByAge);
}
static class PersonAgeComparator implements Comparator<Person> {
public int compare(Person a, Person b) {
return a.getAge().compareTo(b.getAge());
}
}
}
来一个直接简单的例子
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);
}
}
实例方法引用
先说明一下这个supplier 他也是用来创建对象的
public class TestSupplier {
private int age;
TestSupplier(){
System.out.println(age);
}
public static void main(String[] args) {
//创建Supplier容器,声明为TestSupplier类型,此时并不会调用对象的构造方法,即不会创建对象
Supplier<TestSupplier> sup= TestSupplier::new;
System.out.println("--------");
//调用get()方法,此时会调用对象的构造方法,即获得到真正对象
sup.get();
//每次get都会调用构造方法,即获取的对象不同
sup.get();
}
}
实例引用代码
@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) {
User user = new User("欧阳峰",32);
Supplier<String> supplier = new Supplier<String>() {
@Override
public String get() {
return user.getName();
}
};
Supplier<String> supplier = () -> user.getName();
System.out.println("Lambda表达式输出结果:" + supplier.get());
Supplier<String> supplier2 = user::getName;
System.out.println("实例方法引用输出结果:" + supplier2.get());
}
}
对象方法引用
若Lambda参数列表中的第一个参数是实例方法的参数调用者,而第二个参数是实例方法的参数时,可以使用对象方法引用。
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();