Version: Next

方法引用

  • 当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用
  • 方法引用可以看做是Lambda表达式深层次的表达。
  • 方法引用就是Lambda表达式,也就是函数式接口的一个实例,通过方法的名字来指向一个方法,可以认为是Lambda表达式的一个语法糖

要求

  • 实现接口的抽象方法的参数列表返回值类型,必须与方法引用的方法的参数列表和返回值类型一致

格式 ::

  • 类::方法名
  • 对象::方法名

三种使用情况:

  1. 对象::实例方法名
  2. 类::静态方法名
  3. 类::实例方法名

对象::实例方法

  • Consumer中的void accept(T t)
  • PrintStream中的void println(T t)
  • Lambda表达式

    这个例子中,lambda体中使用的是System.out.println(),它是一个已经实现的方法,就可以使用方法引用

public static List<User> getUsers() {
User user1 = new User(1, "a", 20);
User user2 = new User(2, "b", 21);
User user3 = new User(3, "c", 22);
User user4 = new User(4, "d", 23);
User user5 = new User(5, "e", 24);
return Arrays.asList(user1, user2, user3, user4, user5);
}
@Test
public void testMethodReference1() {
List<User> users = getUsers();
Consumer<User> consumer = user -> {
System.out.println(user);
};
consumer.accept(users.get(0));
}
  • 方法引用
@Test
public void testMethodReference1_1() {
List<User> users = getUsers();
PrintStream printStream = System.out;
Consumer<User> consumer = printStream::println;
consumer.accept(users.get(0));
}
  • Supplier中的T get()
  • User中的String getName()
  • Lambda表达式
@Test
public void testMethodReference1_2() {
List<User> users = getUsers();
Supplier<String> supplier = () -> users.get(0).getName();
System.out.println(supplier.get());
}
  • 方法引用
@Test
public void testMethodReference1_3() {
List<User> users = getUsers();
Supplier<String> supplier = users.get(0)::getName;
System.out.println(supplier.get());
}

类::静态方法名

  • Comparator中的int compare(T t1, T t2)
  • Integer中的int compare(T t1, T t2)
@Test
public void testMethodReference2() {
List<User> users = getUsers();
User user1 = users.get(0);
User user2 = users.get(1);
int age1 = user1.getAge();
int age2 = user2.getAge();
Comparator<Integer> comparator = (t1, t2) -> Integer.compare(t1, t2);
System.out.println(comparator.compare(age1, age2));
}
@Test
public void testMethodReference2_1() {
List<User> users = getUsers();
User user1 = users.get(0);
User user2 = users.get(1);
int age1 = user1.getAge();
int age2 = user2.getAge();
Comparator<Integer> comparator = Integer::compare;
System.out.println(comparator.compare(age1, age2));
}
  • Function中的R apply(T t)
  • Math中的Long round(Double d)
@Test
public void testMethodReference2_2() {
Function<Double, Long> function = d -> Math.round(d);
System.out.println(function.apply(22.3));
}
@Test
public void testMethodReference2_2() {
Function<Double, Long> function = Math::round;
System.out.println(function.apply(22.3));
}

类::实例方法

  • Comparator中的int compare(T t1, T t2)
  • String中的int t1.compareTo(t2)
  • 虽然参数列表不匹配,但是其中一个参数是方法调用者
@Test
public void testMethodReference3() {
Comparator<String> comparator = (s1, s2) -> s1.compareTo(s2);
System.out.println(comparator.compare("a", "c"));
}
@Test
public void testMethodReference3() {
Comparator<String> comparator = String::compareTo;
System.out.println(comparator.compare("a", "c"));
}
  • BiPredicate中的boolean test(T t1, T t2)
  • String中的boolean t1.equals(t2)
@Test
public void testMethodReference3_1() {
BiPredicate<String, String> biPredicate = (s1, s2) -> s1.equals(s2);
System.out.println(biPredicate.test("a", "a"));
}
@Test
public void testMethodReference3_1() {
BiPredicate<String, String> biPredicate = String::equals;
System.out.println(biPredicate.test("a", "a"));
}
  • Function中的 R apply(T t)
  • User中的String getName()
  • t就作为getName()的调用者
@Test
public void testMethodReference3_2() {
Function<User, String> function = user -> user.getName();
System.out.println(function.apply(new User(1, "A", 20)));
}
@Test
public void testMethodReference3_2() {
Function<User, String> function = User::getName;
System.out.println(function.apply(new User(1, "A", 20)));
}

例:遍历集合

  1. 增强for循环
  2. 使用foreach(Consumer),里面写lambda表达式
  3. 使用foreach(Consumer),当Consumer参数列表和Lambda体参数列表一致时,可以使用方法引用
  • 增强for循环
@Test
public void testForeach1() {
List<User> users = getUsers();
for (User user : users) {
System.out.println(user);
}
}
User{id=1, name='a', age=20}
User{id=2, name='b', age=21}
User{id=3, name='c', age=22}
User{id=4, name='d', age=23}
User{id=5, name='e', age=24}
  • foreach(Consumer) lambda表达式
@Test
public void testForeach1() {
List<User> users = getUsers();
users.forEach(user -> System.out.println(user.getName()));
}
a
b
c
d
e
  • foreach(Consumer) 方法引用
@Test
public void testForeach1() {
List<User> users = getUsers();
users.forEach(user -> System.out.println(user));
}

因为Consumer的参数为user, lambda体中的方法参数也为user,就可以用方法引用,改写为:

@Test
public void testForeach1() {
List<User> users = getUsers();
users.forEach(System.out::println);
}
User{id=1, name='a', age=20}
User{id=2, name='b', age=21}
User{id=3, name='c', age=22}
User{id=4, name='d', age=23}
User{id=5, name='e', age=24}