根据 Java 11 中的枚举值选择要应用于流的方法

问题描述 投票:0回答:2

我有以下枚举。

public enum AggregationType
{
    MIN,
    MAX,
    AVERAGE
}

假设我有一个传递枚举值的函数,例如:

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

}

我想在基于枚举值的流上应用此

.average()
.min()
.max()
方法。

我怎样才能实现这一目标?我不想在

someFunction
中使用简单的 switch 函数,而是在这个 return 语句中使用。

所以我想要这样的东西:

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


}

其中

decideWhichMethodShouldBeUsed()
根据枚举决定使用哪个函数。

java enums java-stream java-11
2个回答
5
投票

当您可以将

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();
等效的值,只要在编译此代码后没有人更改
enum
类型,该值就永远不会在运行时被获取。

通常,只有第一个变体会迫使考虑向

AggregationType
添加新常量的开发人员也考虑处理相关的
operation


0
投票

一种替代方法是使用

DoubleSummaryStatistics
将流收集到
Collectors.summarizingDouble
中,并根据枚举检索所需的值。

private Float someFunction(final AggregationType e) {
    DoubleSummaryStatistics stats = provides.stream()
            .collect(Collectors.summarizingDouble(this::someFunc));
    switch (e) {
        case MAX: return (float) stats.getMax();
        case MIN: return (float) stats.getMin();
        case AVERAGE: return (float) stats.getAverage();
        default: throw new AssertionError();
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.