- ,
Number , Number . identity T extends Number, 0 - Integer T.
, Number , :
Integer sumToInt = MathUtility.sum(numbers, condition).as(Integer.class);
Double sumToDouble = MathUtility.sum(numbers, condition).as(Double.class);
, Number , Number , , , - , , :
SumOp<Integer> sumIntOp = SumOp.of(Integer.class);
//sumIntOp is reused twice.
Integer sumToInt1 = sumIntOp.sum(numbers1, condition1);
Integer sumToInt2 = sumIntOp.sum(numbers2, condition2);
MathUtility
class MathUtility {
private static <T extends Number> Sum sum(List<T> numbers,
Predicate<T> condition) {
return sum(numbers.parallelStream().filter(condition));
}
private static <T extends Number> Sum sum(Stream<T> stream) {
return new Sum() {
public <T extends Number> T as(Class<T> type) {
return SumOp.of(type).sum(stream);
}
};
}
interface Sum {
<T extends Number> T as(Class<T> type);
}
}
SumOp
public class SumOp<T extends Number> {
private static final Map<Class<?>, SumOp<?>> OPERATORS = new HashMap<>();
private final T identity;
private final BinaryOperator<T> plusOp;
private final Function<Number, T> valueExtractor;
static {
register(Integer.class, new SumOp<>(0, Integer::sum, Number::intValue));
register(Double.class, new SumOp<>(0., Double::sum, Number::doubleValue));
}
public static <T extends Number> void register(Class<T> type,
SumOp<T> sumOp) {
OPERATORS.put(type, sumOp);
}
public static <T extends Number> SumOp<T> of(Class<T> type) {
return (SumOp<T>) OPERATORS.computeIfAbsent(type, it -> {
String message = "No SumOp registered for type:" + type.getName();
throw new IllegalArgumentException(message);
});
}
public SumOp(T identity,
BinaryOperator<T> plusOp,
Function<Number, T> valueExtractor) {
this.identity = identity;
this.valueExtractor = valueExtractor;
this.plusOp = plusOp;
}
public <I extends Number> T sum(List<I> numbers,
Predicate<I> 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);
}
}