我正在为我的一个项目进行通用Sum投影.代码就像,
public class Sum<T,U extends Number> implements IProject<T,U,U>
{
@Override
public U eval(Iterable<T> tList, Function<T,U> property)
{
U total;
for (T t : tList)
{
total += property.apply(t);
}
return total;
}
}
Run Code Online (Sandbox Code Playgroud)
但是这里有一点小问题,因为我需要初始化总数(显然为0).但是无论如何在java中我都可以使用它default(U).
无论如何,泛型仅针对引用类型而存在,因此始终如此null。似乎还有一个隐含的假设,即 + 运算符的定义是为了U- 您确定没有更多的限制吗U?您还看过Stream.map随后做的事情Stream.reduce吗?(我假设您正在使用 Java 8 Function)
编辑我认为你正在寻找的是幺半群模式。它在 Java 中不存在,但你可以自己定义它 -
interface Monoid<T>
{
T getZero();
T add(T left, T right);
}
Run Code Online (Sandbox Code Playgroud)
因此你的例子将变成
public U eval(Iterable<T> tList, Function<T,U> property, Monoid<U> m)
{
U initial = m.getZero();
return StreamSupport.stream(tList.spliterator(), false)
.map(property)
.reduce(initial, (uLeft, uRight) -> m.add(uLeft, uRight));
}
Run Code Online (Sandbox Code Playgroud)
但这需要更改 的签名eval,这可能是不可能的,因为我看到它被注释了@Override。
这种方法可扩展到具有串联的列表和字符串、具有并集的集合和映射,其中值本身就是一个幺半群,“添加”给定键的所有值,以及组合下的函数,其中“零”是恒等函数。
Java的等同于C#的default(T)是null,这显然不会工作你的情况,因为你会得到一个NullPointerException你第一次尝试的东西添加到您的总.
为了初始化你的总数,你需要一个java的工厂方法,但它仍然无法工作,因为:
+=在java中使用泛型.java.lang.Number 是不可变的,所以你不能添加任何东西.你有两个选择.
大量过度设计的方法:
定义一个名为的新接口,例如,MyNumber它包含一个add方法,并编写实现此接口的相关非不可变数值类,因此您的代码将如下所示:
@Override
public <T extends MyNumber> T add( T total, Iterable<T> myNumbers )
{
for( T myNumber : myNumbers )
total.add( myNumber );
return total;
}
Run Code Online (Sandbox Code Playgroud)
(您还需要编写一个工厂,以便您可以创建一个实例来保存您的总数,而无需确切知道它是什么类型.)
务实的方法:
写下这样的级联if语句:
if( number instanceof Integer )
{
//declare int total
//loop to sum integers
//box the total into a Number
}
else if( number instanceof Long )
{
//declare long total
//loop to sum longs
//box the total into a Number
}
...
Run Code Online (Sandbox Code Playgroud)