什么是Java相当于C#的默认值(T)

时间:2015-02-14 11:42:01

标签: java generics

我目前正在为我的一个项目进行通用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;
    }
}

然而这里有一点小问题,因为我需要初始化总数(显然为0)。但无论如何要在Java中这样做,就像在C#中我可以使用default(U)

2 个答案:

答案 0 :(得分:5)

Java等同于C#的default(T)null,这显然不适用于您的情况,因为在您第一次尝试添加某些内容时会出现NullPointerException你的总数。

为了初始化你的总数,你需要在java中使用工厂方法,但它仍然无效,因为:

  1. 你不能在java中使用+=泛型。
  2. java.lang.Number是不可变的,因此您无法添加任何内容。
  3. 您有两种选择。

    大量过度设计的方法:

    定义一个名为MyNumber的新接口,其中包含add方法,并编写实现此接口的相关非不可变数值类,因此您的代码将如下所示:

    @Override
    public <T extends MyNumber> T add( T total, Iterable<T> myNumbers )
    {
        for( T myNumber : myNumbers )
            total.add( myNumber );
        return total;
    }
    

    (你还需要编写一个工厂,这样你就可以创建一个实例来保存你的总数而不知道它究竟是什么类型。)

    实用主义方法:

    写下这样的级联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
    }
    ...
    

答案 1 :(得分:4)

Generics only exist for reference types anyway,所以这总是null。似乎还有一个隐含的假设,即U定义了+运算符 - 你确定U可以有更多限制吗?您还看过Stream.map后跟Stream.reduce吗? (我假设你正在使用Java 8,因为你有Function

编辑我认为您正在寻找的是幺半群模式。它并不存在于Java中,但您可以自己定义它 -

interface Monoid<T>
{
    T getZero();
    T add(T left, T right);
}

因此你的例子将成为

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

但这需要更改eval的签名,这可能是不可能的,因为我看到它的注释@Override

这种方法可以扩展到带有连接的列表和字符串,带有union和Maps的集合,其中值本身就是一个幺半群,&#34;添加&#34;给定键的所有值,以及组合下的函数,其中&#34;零&#34;是身份功能。