将Java 8 Lambdas与generics一起使用

是否可以使用Predicate接口执行此操作。

我有一个客户端类,它使用MathUtility类提供的函数。 无论Mathmatical操作是什么,它都应该只在MathUtility类中发生。

//in client MathUtility.sum(listOfInts, (Integer i)->{return (i<3);}); //in utility class MathUtility { public static  T sumWithCondition(List numbers, Predicate condition) { return numbers.parallelStream() .filter(condition) .map(i -> i) .reduce(0, T::sum); //compile time error } public static  T avgWithCondition(List numbers, Predicate condition) { //another function } //lot many functions go here } 

现在它失败并出现此错误 – The method reduce(T, BinaryOperator) in the type Stream is not applicable for the arguments (int, T::sum)

注意:我不想为不同的Number类型编写sum函数

有没有办法在没有为我期待的每种可能类型的T编写求和函数的情况下做到这一点?

正如Aaron Davis在上面的评论中所说,您可以将减少参数传递给方法本身。

 public static  T sumWithCondition(List numbers, Predicate condition, T identity, BinaryOperator accumulator) { return numbers.parallelStream().filter(condition).reduce(identity, accumulator); } 

一个例子是:

 List list = Arrays.asList(1, 2, 3, 4, 5); System.out.println(sumWithCondition(list, i -> i > 1, 0, (a, b) -> a + b)); >> 14 List list2 = Arrays.asList(BigInteger.ONE, BigInteger.ONE); System.out.println(sumWithCondition(list2, i -> true, BigInteger.ZERO, (a, b) -> a.add(b))); >> 2 
  1. 你必须指出要求和的实际数字类型,因为Number类没有静态求和方法。
  2. 你必须分配类型为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 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  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); } } 

SumOp

 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 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); } } 

我厌倦了一个更简单的方法就是这个。

需要注意的是,加法逻辑不会发生在调用端,而只发生在MathUtility中。 这里的缺点是你必须为你想要+操作的每个Number类型创建Addition类。

 System.out.println( MathUtility.sum(listOfInts, i->i<4, new MathUtility.IntegerAddition()).get() ); class MathUtility { static class IntegerAddition implements BinaryOperator { @Override public Integer apply(Integer t, Integer u) { return t + u; } } public static  Optional sum(List list, Predicate condition, BinaryOperator operation){ //ability to add is only here return list.parallelStream() .filter(condition) .map(i -> i) .reduce(operation); } } 

答案是肯定的,这应该是可能的。 你所定义的不知道方法是“sum”,因此编译器会抱怨。 尝试定义

 public interace SumInterface { public int sum(int a, int b); } 

(我没有在IDE中尝试过这个代码,但是应该这样做)