Tengo la siguiente enumeración.
public enum AggregationType { MIN, MAX, AVERAGE }supongamos que tengo una función en la que paso un valor de enumeración como
public Float someFunction(final AggregationType enum) { return (float) provides.stream() .mapToDouble(this::someFunc) .average() .orElse(-1); }Quiero aplicar estos métodos .average() .min() .max() en una secuencia basada en el valor de enumeración.
¿Cómo puedo lograr esto? No quiero usar simplemente la función de cambio dentro de alguna función, sino en esta declaración de devolución.
Entonces quiero tener algo como
public Float someFunction(final AggregationType enum) { return (float) provides.stream() .mapToDouble(this::someFunc) .decideWhichMethodShouldBeUsed() .orElse(-1); }donde decideWhichMethodShouldBeUsed() decide qué función usar en función de la enumeración.
Cuando puede cambiar el tipo de enum a
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; } }puedes implementar el método como
public Float someFunction(final AggregationType aType) { return (float)aType.operation.apply(provides.stream().mapToDouble(this::someFunc)) .orElse(-1); } Si cambiar el tipo de enumeración no es una opción, debe manejar la asignación a la operación real en el lugar donde desea implementar someFunction , por ejemplo
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); } También puede usar una declaración de switch , pero es bastante torpe
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); } Las cosas mejoran cuando usa una versión reciente de Java, ya que entonces puede usar una expresión de 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); } Esto solo lo acepta el compilador cuando se manejan todas las constantes de enum . Luego, generará un equivalente al default -> throw new AssertionError(); detrás de escena que nunca se tomará en tiempo de ejecución, siempre que nadie cambie el tipo de enum después de que se haya compilado este código.
Por lo general, solo la primera variante obliga a los desarrolladores que consideran agregar nuevas constantes a AggregationType a considerar también el manejo de la operation asociada.