[英]Use of Java 8 Lambdas with Generics
Is it possible to do this using Predicate interface.是否可以使用 Predicate 接口来做到这一点。
I have a client class that utilizes functions provided by a MathUtility class.我有一个使用 MathUtility 类提供的函数的客户端类。 Whatever the Mathmatical operation it should happen only within the MathUtility class.无论是什么数学运算,它都应该只在 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
}
Right now it fails with this error - The method reduce(T, BinaryOperator<T>) in the type Stream<T> is not applicable for the arguments (int, T::sum)
现在它因此错误而失败 - The method reduce(T, BinaryOperator<T>) in the type Stream<T> is not applicable for the arguments (int, T::sum)
Note: I do not want to write sum functions for different Number types注意:我不想为不同的 Number 类型编写 sum 函数
EDIT: Detailed discussion on this topic covered in this Github Notebook编辑:此Github Notebook 中涵盖的有关此主题的详细讨论
Is there a way to do it without writing a sum function for every possible type of
T
that i'm expecting?有没有办法在不为我期望的每种可能类型的T
编写 sum 函数的情况下做到这一点?
As Aaron Davis stated in a comment above, you can pass the reduction parameters to the method itself.正如 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);
}
An example would be:一个例子是:
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
Number
to be summed, Since the Number
class has no static sum method.您必须指出要求和的实际Number
类型,因为Number
类没有静态 sum 方法。identity
with type of T extends Number
, 0
is an concrete type of Integer and does not compatible with type of T
.您必须为T extends Number
类型分配identity
, T extends Number
, 0
是 Integer 的具体类型,与T
类型不兼容。you can make which actual type of Number
to be summed later, for example:您可以稍后对哪种实际类型的Number
求和,例如:
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:或者,您可以预先对哪种实际类型的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);
}
}
A much simpler approach I tired is this.我厌倦了一个更简单的方法是这个。
The point to be noted is that the addition logic doesn't happen at the invoking side instead only within the MathUtility.需要注意的一点是,加法逻辑不会发生在调用端,而是只发生在 MathUtility 中。 The downside here is that you have to create Addition classes for every Number type you want the + operation.这里的缺点是您必须为每个您想要 + 操作的 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);
}
}
The answer is yes, that should be possible.答案是肯定的,这应该是可能的。 The you defined is not known to have the method "sum", therefore the compiler complains.不知道您定义的具有“sum”方法,因此编译器会抱怨。 Try to define尝试定义
public interace SumInterface {
public int sum(int a, int b);
}
(I haven't tried this code in IDE but this should do the trick) (我没有在 IDE 中尝试过这段代码,但这应该可以解决问题)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.