使用 .apply 引用方法

Reference to method with .apply

我有一个名为“赛车手”的简单列表 class

class Racer {
    private String name; 
    private String teamName;
    // and getters
}

我正在使用一种方法来查找列表中字段的最大长度:

int maxRacerNameLength = getMaxFieldLength(racers, Racer::getName);
int maxTeamNameLength = getMaxFieldLength(racers, Racer::getTeamName);

方法实现:

private int getMaxFieldLength(List<Racer> racers, Function<Racer, String> getter) {
    return racers.stream().mapToInt(racer -> getter.apply(racer).length()).max().getAsInt();
}

如何使用方法引用摆脱最后一个 lambda?

您可以将 mapToInt(racer->getter.apply(racer).length()) 分成两步来完成:

return racers.stream().map(getter::apply).mapToInt(String::length).max().getAsInt();

演示:

public class Main {
    public static void main(String[] args) {
        List<Racer> racers = List.of(
                                        new Racer("Andy", "One"), 
                                        new Racer("Thomas", "Four"), 
                                        new Racer("John", "One"),
                                        new Racer("Newton", "Four")
                                    );

        System.out.println(getMaxFieldLength(racers, Racer::getName));
        System.out.println(getMaxFieldLength(racers, Racer::getTeamName));
    }

    static int getMaxFieldLength(List<Racer> racers, Function<Racer, String> getter) {
        return racers.stream().map(getter::apply).mapToInt(String::length).max().getAsInt();
    }
}

输出:

6
4

方法参考种类:

Kind Example
Reference to a static method ContainingClass::staticMethodName
Reference to an instance method of a particular object containingObject::instanceMethodName
Reference to an instance method of an arbitrary object of a particular type ContainingType::methodName
Reference to a constructor ClassName::new

Method References 了解更多信息。

您可以通过以下方式实现您想要的:

private int getMaxFieldLength(List<Racer> racers, Function<Racer, String> getter) {
    return racers.stream()
                 .map(getter)
                 .mapToInt(String::length)
                 .max()
                 .getAsInt();
}

但是,我不建议使用 getAsInt 获取 OptionalInt 的值。那是一个湿滑的斜坡。赛车手列表可能为空,这将导致 NoSuchElementException.

在那种情况下,您应该 return 一个默认值(这里 0 似乎没问题):

private int getMaxFieldLength(List<Racer> racers, Function<Racer, String> getter) {
    return racers.stream()
                 .map(getter)
                 .mapToInt(String::length)
                 .max()
                 .orElse(0);
}

或returnOptionalInt让方法调用者处理:

private OptionalInt getMaxFieldLength(List<Racer> racers, Function<Racer, String> getter) {
    return racers.stream()
                 .map(getter)
                 .mapToInt(String::length)
                 .max();
}

如果实施必须始终找到 integers 流的最大值,您宁愿选择 ToIntFunction 而不是 Function<Racer, String>。这会将方法的实现和签名更改为:

private int getMaxFieldLength(List<Racer> racers, ToIntFunction<Racer> toLength) {
    return racers.stream()
            .mapToInt(toLength)
            .max()
            .orElse(Integer.MIN_VALUE); // or throw exception for empty racers
}

这将反过来使用该方法:

int maxRacerNameLength = getMaxFieldLength(racers, racer -> racer.getName().length());
int maxTeamNameLength = getMaxFieldLength(racers,racer -> racer.getTeamName().length());