Is it possible to do this using Predicate interface.
I have a client class that utilizes functions provided by a MathUtility class. Whatever the Mathmatical operation it
Number
to be summed, Since the Number
class has no static sum method. identity
with type of T extends Number
,0
is an concrete type of Integer and does not compatible with type of T
.you can make which actual type of Number
to be summed later, for example:
Integer sumToInt = MathUtility.sum(numbers, condition).as(Integer.class);
Double sumToDouble = MathUtility.sum(numbers, condition).as(Double.class);
OR you can make which actual type of Number
to be summed ahead, when using this style you are free to take type of actual Number
to every sum to be called, one the other hand, you can reuse it without taking any confused parameters and which is exactly what you want,for example:
SumOp sumIntOp = SumOp.of(Integer.class);
//sumIntOp is reused twice.
Integer sumToInt1 = sumIntOp.sum(numbers1, condition1);
Integer sumToInt2 = sumIntOp.sum(numbers2, condition2);
class MathUtility {
private static Sum sum(List numbers,
Predicate condition) {
return sum(numbers.parallelStream().filter(condition));
}
private static Sum sum(Stream stream) {
return new Sum() {
public T as(Class type) {
return SumOp.of(type).sum(stream);
}
};
}
interface Sum {
T as(Class type);
}
}
public class SumOp {
private static final Map, SumOp>> OPERATORS = new HashMap<>();
private final T identity;
private final BinaryOperator plusOp;
private final Function valueExtractor;
static {
register(Integer.class, new SumOp<>(0, Integer::sum, Number::intValue));
register(Double.class, new SumOp<>(0., Double::sum, Number::doubleValue));
//todo: add more SumOp for other Number types
}
public static void register(Class type,
SumOp sumOp) {
OPERATORS.put(type, sumOp);
}
public static SumOp of(Class type) {
return (SumOp) OPERATORS.computeIfAbsent(type, it -> {
String message = "No SumOp registered for type:" + type.getName();
throw new IllegalArgumentException(message);
});
}
public SumOp(T identity,
BinaryOperator plusOp,
Function valueExtractor) {
this.identity = identity;
this.valueExtractor = valueExtractor;
this.plusOp = plusOp;
}
public T sum(List numbers,
Predicate condition) {
return sum(numbers.stream().filter(condition));
}
public T sum(Stream extends Number> stream) {
return stream.reduce(identity, this::plus, plusOp);
}
private T plus(Number augend, Number addend) {
return plusOp.apply(valueIn(augend), valueIn(addend));
}
private T valueIn(Number it) {
return valueExtractor.apply(it);
}
}