在使用 Lambda 表达式的时候,我们实际上传递进去的代码就是一种解决方案:拿什么参数做什么操作。试想,有这样一种情况:我们在 Lambda 中所指定的操作方案,已经有地方存在相同方案,那是否还有必要再重写逻辑呢?
当然可以不需要。这时就用到了我们今天要讲解的内容:Java的方法引用符 “::”。
// Lambda 表达式写法:
s -> System.out.println(s);
// :: 方法引用写法:
System.out::println
我么可以通过方法引用,来使用已经存在的方案,使表达式变得更加简洁。
正文
Java 8 中,双冒号 :: 称为“方法引用操作符”,:: 符号为引用运算符,而它所在的表达式被称为方法引用,我们可以使用它来引用类的方法。
:: 引用类的方法,返回一个函数接口(function interface),这等同于 lambda 表达式,但与 lambda 表达式不同的是,lambda表达式需要自定义一个lambda body,而 :: 引用的是一个方法。
/**
* 表示接受一个参数并生成结果的函数。
* @param<T>函数的输入类型
* @param<R>函数结果的类型
* @从1.8开始
*/
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
static <T> Function<T, T> identity() {
return t -> t;
}
}
方法引用操作符有【四种类型】:
- ClassName :: New :对构造函数的引用,相当于创建对象;
- ClassName :: static_method :如果有参数会把参数当方法的实参;
- ClassName :: instance_method :把第一个参数当做类对象,用来调用 instance_method,其他参数当做方法的参数;
- instance :: instance_method :如果有参数会把参数当方法的实参;
案例
下面,简单展示一下 Java引用符四种类型的使用:
import java.util.Arrays;
import java.util.Optional;
import java.util.function.Supplier;
/** 引用操作符的四种类型 */
public class JavaTest {
public static class User {
private String id;
private Integer age;
private String name;
// ... 省略了参数的get(),set()方法
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("User{");
sb.append("id='").append(id).append('\'');
sb.append(", age=").append(age);
sb.append(", name='").append(name).append('\'');
sb.append('}');
return sb.toString();
}
public static void testStatic(String s){
System.out.println(s);
}
}
/**
* 1.构造器引用
* ClassName::New => new ClassName()
* 如果调用时有参数,相当于调用带参的构造函数
*/
@Test
public void test1(){
App.toString(User::new);
}
public static void toString(Supplier supplier){
System.out.println(supplier.get().toString());
}
/**
* 2.静态方法引用
* ClassName::static_method =》 CLassName.static_method()
* 如果调用时有参数,直接放到静态方法的形参中
*/
@Test
public void test2(){
Arrays.asList("name1","name2").stream().forEach(User::testStatic);
}
/**
* 3.特定类对方法引用
* ClassName::instance_method => obj.instance_method(xxx)
* 调用时参数:第一个参数是实体对象 上面的obj
* 如果有其他参数,会传到方法中
*/
@Test
public void test3(){
User user = new User();
user.setId("625");
user.setAge(30);
user.setName("java punk");
Optional.of(user).ifPresent(User::toString);
}
/**
* 4.特定对象对方法引用
* instance::instance_method =》instance.instance_method(xxxx);
* 如果有参数,参数就是方法的参数
*/
@Test
public void test4(){
User user = new User();
user.setId("625");
user.setAge(30);
user.setName("java punk");
toString(user::toString);
}
}