是否可以使用Predicate接口执行此操作。
我有一个使用MathUtility类提供的函数的客户端类。无论Mathmatical操作是什么,它都应该只在MathUtility类中发生。
//in client
MathUtility.sum(listOfInts, (Integer i)->{return (i<3);});
//in utility
class MathUtility<T extends Number> {
public static <T extends Number> T sumWithCondition(List<T> numbers, Predicate<T> condition) {
return numbers.parallelStream()
.filter(condition)
.map(i -> i)
.reduce(0, T::sum); //compile time error
}
public static <T extends Number> T avgWithCondition(List<T> numbers, Predicate<T> condition) {
//another function
}
//lot many functions go here
}
现在它失败并出现此错误 - The method reduce(T, BinaryOperator<T>) in the type Stream<T> is not applicable for the arguments (int, T::sum)
注意:我不想为不同的数字类型编写和函数
答案 0 :(得分:5)
有没有办法在没有为我期待的每种可能类型的
T
编写求和函数的情况下这样做?
正如Aaron Davis在上面的评论中所说,你可以将减少参数传递给方法本身。
public static <T> T sumWithCondition(List<T> numbers, Predicate<T> condition, T identity, BinaryOperator<T> accumulator) {
return numbers.parallelStream().filter(condition).reduce(identity, accumulator);
}
一个例子是:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
System.out.println(sumWithCondition(list, i -> i > 1, 0, (a, b) -> a + b));
>> 14
List<BigInteger> list2 = Arrays.asList(BigInteger.ONE, BigInteger.ONE);
System.out.println(sumWithCondition(list2, i -> true, BigInteger.ZERO, (a, b) -> a.add(b)));
>> 2
答案 1 :(得分:2)
Number
的实际类型,因为Number
类没有静态求和方法。 identity
分配T extends Number
类型,0
是具体类型的整数,并且与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);
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);
}
}
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));
//todo: add more SumOp for other Number types
}
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);
}
}
答案 2 :(得分:1)
我厌倦了一个更简单的方法就是这个。
需要注意的是,加法逻辑不是在调用端发生,而是仅在MathUtility中发生。 这里的缺点是你必须为你想要+操作的每个Number类型创建Addition类。
System.out.println(
MathUtility.sum(listOfInts, i->i<4, new MathUtility.IntegerAddition()).get()
);
class MathUtility<T extends Number> {
static class IntegerAddition implements BinaryOperator<Integer> {
@Override
public Integer apply(Integer t, Integer u) {
return t + u;
}
}
public static <T extends Number> Optional<T> sum(List<T> list, Predicate<T> condition, BinaryOperator<T> operation){
//ability to add is only here
return list.parallelStream()
.filter(condition)
.map(i -> i)
.reduce(operation);
}
}
答案 3 :(得分:-2)
答案是肯定的,这应该是可能的。你定义的那个不知道有方法&#34; sum&#34;因此编译器会抱怨。尝试定义
public interace SumInterface {
public int sum(int a, int b);
}
(我还没有在IDE中尝试过这个代码,但这应该可以解决问题)