方法引用

91 阅读3分钟

我们在使用lambda时,如果方法体中只有一个方法的调用的话(包括构造方法),我们可以用方法引用进一步简化代码。

一、推荐使用

我们在使用lambda时不需要考虑什么时候用方法引用,用哪种方法引用,方法引用的格式是什么。我们只需要在写完lambda方法发现方法体只有一行代码,并且是方法的调用时使用快捷键尝试是否能够转换成方法引用即可。

当我们方法引用使用的多了慢慢的也可以直接写出方法引用。

二、基本格式

类名或方法名::方法名

三、语法详情(了解)

3.1 引用类的静态方法

格式

类名::方法名

使用前提

如果我们在重写方法的时候,方法体中只有一行代码,并且这行代码是调用了某个类的静态方法,并且我们把要重写的抽象方法中所有的参数都按照顺序传入了这个静态方法中,这个时候我们就可以引用类的静态方法。

例如:

如下代码就可以用方法引用进行简化

List<Author> authors = getAuthors();
authors.stream()
        .map(author -> author.getAge())
        .map(age -> String.valueOf(age))
        .forEach(age -> System.out.println(age));

注意,如果我们所重写的方法是没有参数的,调用的方法也是没有参数的也相当于符合以上规则。

优化后如下:

List<Author> authors = getAuthors();
authors.stream()
        .map(author -> author.getAge())
        .map(String::valueOf)
        .forEach(System.out::println);

3.2 引用对象的实例方法

格式

对象名::方法名

使用前提

如果我们在重写方法的时候,方法体中只有一行代码,并且这行代码是调用了某个对象的成员方法,并且我们把要重写的抽象方法中所有的参数都按照顺序传入了这个成员方法中,这个时候我们就可以引用对象的实例方法。

例如:

List<Author> authors = getAuthors();
StringBuilder sb = new StringBuilder();
authors.stream()
        .map(author -> author.getName())
        .forEach(name -> sb.append(name));

System.out.println(sb);

优化后:

List<Author> authors = getAuthors();
StringBuilder sb = new StringBuilder();
authors.stream()
        .map(author -> author.getName())
        .forEach(sb::append);

System.out.println(sb);

3.3 引用类的实例方法

格式

类名::方法名

使用前提

如果我们在重写方法的时候,方法体中只有一行代码,并且这行代码是调用了第一个参数的成员方法,并且我们把要重写的抽象方法中剩余的所有的参数都按照顺序传入了这个成员方法中,这个时候我们就可以引用类的实例方法。

例如:

public interface UseString {
    String use(String str,int start,int length);
}
public static String subAuthorName(String str, UseString useString) {
    int start = 0;
    int length = 1;
    return useString.use(str, start, length);
}
subAuthorName("哈哈哈哈", new UseString() {
    @Override
    public String use(String str, int start, int length) {
        return str.substring(start, length);
    }
});

lamdba表达式:

subAuthorName("哈哈哈", ((str, start, length) -> str.substring(start, length)));

优化后:

subAuthorName("哈哈哈哈", String::substring);

3.4 构造器引用

如果方法体中的一行代码是构造器的话就可以使用构造器引用。

格式

类名::new

使用前提

如果我们在重写方法的时候,方法体中只有一行代码,并且这行代码是调用了某个类的构造方法(new 类(属性)),并且我们把要重写的抽象方法中的所有的参数都按照顺序传入了这个构造方法中,这个时候我们就可以引用构造器。

例如:

List<Author> authors = getAuthors();
authors.stream()
        .map(author -> author.getName())
        .map(name -> new StringBuilder(name))
        .forEach(name -> System.out.println(name));

优化后:

List<Author> authors = getAuthors();
authors.stream()
        .map(author -> author.getName())
        .map(StringBuilder::new)
        .forEach(name -> System.out.println(name));

四、服务预热解析

原本在服务预热时,将预热数据封装到map集合中,将value接口对象的值写为了 this::方法名

image.png

将其展开为Lambda表达式为: () -> initFastJson()() -> this.initFastJson()

全部展开匿名内部类为:

initFunctionMap.put("预热fastjson", new InitFunction() {
    @Override
    public void invoke() {
        initFastJson();
    }
});

由于参数列表为空,返回值为空,且调用了initFastJson()对象,所以可写为() -> this.initFastJson(),又因为只有一行代码,且重写的抽象方法参数列表按顺序传入了这个成员方法中。最后可简写为类名::方法名,即this::initFastJson