Java 11 Select 一种基于枚举值应用于流的方法

Java 11 Select a method to apply on a stream based on enum value

我有以下枚举。

public enum AggregationType
{
    MIN,
    MAX,
    AVERAGE
}

让我们假设我有一个传递枚举值的函数,比如

public Float someFunction(final AggregationType enum) {
            return (float) provides.stream()
                                      .mapToDouble(this::someFunc)
                                      .average()
                                      .orElse(-1);
        

}

我想在基于枚举值的流上应用此 .average() .min() .max() 方法。

我怎样才能做到这一点?我不想在 someFunction 中使用简单的 switch 函数,而是在这个 return 语句中使用。

所以我想拥有类似

的东西
public Float someFunction(final AggregationType enum) {
            return (float) provides.stream()
                                      .mapToDouble(this::someFunc)
                                      .decideWhichMethodShouldBeUsed()
                                      .orElse(-1);


}

在哪里决定使用哪个方法() 根据枚举决定使用哪个函数。

何时可以将 enum 类型更改为

public enum AggregationType {
    MIN(DoubleStream::min),
    MAX(DoubleStream::max),
    AVERAGE(DoubleStream::average);

    public final Function<DoubleStream, OptionalDouble> operation;

    AggregationType(Function<DoubleStream, OptionalDouble> f) {
        operation = f;
    }
}

你可以实现这样的方法

public Float someFunction(final AggregationType aType) {
    return (float)aType.operation.apply(provides.stream().mapToDouble(this::someFunc))
        .orElse(-1);
}

如果更改枚举类型不是一个选项,则必须在要实现的地方处理到实际操作的映射someFunction,例如

private static final Map<AggregationType,Function<DoubleStream, OptionalDouble>> OPS;
static {
    EnumMap<AggregationType,Function<DoubleStream, OptionalDouble>>
        m = new EnumMap<>(AggregationType.class);
    m.put(AggregationType.MIN, DoubleStream::min);
    m.put(AggregationType.MAX, DoubleStream::max);
    m.put(AggregationType.AVERAGE, DoubleStream::average);
    OPS = Collections.unmodifiableMap(m);
}

public Float someFunction(final AggregationType aType) {
    return (float)OPS.get(aType).apply(provides.stream().mapToDouble(this::someFunc))
        .orElse(-1);
}

你也可以使用 switch 语句,但它很笨重

public Float someFunction(final AggregationType aType) {
    DoubleStream ds = provides.stream().mapToDouble(this::someFunc);
    OptionalDouble d;
    switch(aType) {
        case MAX: d = ds.max(); break;
        case MIN: d = ds.min(); break;
        case AVERAGE: d = ds.average(); break;
        default: throw new AssertionError();
    }
    return (float)d.orElse(-1);
}

当你使用最近的 Java 版本时,情况会变得更好,因为那时你可以使用 switch 表达式:

public Float someFunction(final AggregationType aType) {
    DoubleStream ds = provides.stream().mapToDouble(this::someFunc);
    return (float)(switch(aType) {
        case MAX -> ds.max();
        case MIN -> ds.min();
        case AVERAGE -> ds.average();
    }).orElse(-1);
}

这只有在处理完所有 enum 常量后才会被编译器接受。然后,它会在幕后生成一个等价于 default -> throw new AssertionError(); 的东西,它永远不会在运行时获取,只要 no-one 在这段代码编译后更改 enum 类型。

通常,只有第一个变体会迫使考虑向 AggregationType 添加新常量的开发人员也考虑处理关联的 operation.