我有以下枚举。
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()
根据枚举决定使用哪个函数。
当您可以将
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
。
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();
}
}