简体   繁体   中英

What is Java equivalent of C# default(T)

I'm currently working on generic Sum projection for one of my projects. The code is like,

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

However there is a little glitch here since I need to initialize the total (obviously to 0). But is there anyway to do it in java like in C# I could use default(U) .

Java's equivalent to C#'s default(T) is null , which clearly would not work in your case, because you would get a NullPointerException the first time you tried to add something to your total.

In order to initialize your total you would need a factory method in java, but it still would not work, because:

  1. you cannot use += on generics in java.
  2. java.lang.Number is immutable, so you cannot add anything to it.

You have two options.

The massively overengineered approach:

Define a new interface called, say, MyNumber which contains an add method, and write associated non-immutable numeric classes implementing this interface, so your code would then look like this:

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

(You would also need to write a factory so that you can create an instance to hold your total without knowing precisely what type it is.)

The pragmatic approach:

Write cascaded if statements like this:

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
}
...

Generics only exist for reference types anyway , so this would always be null . There also seems to be an implicit assumption that the + operator is defined for U - are you sure there aren't more constraints on what U can be? Also have you looked at doing Stream.map followed by Stream.reduce ? (I assume you are using Java 8 as you have Function )

EDIT I think what you are looking for is the monoid pattern. It doesn't exist in Java but you can define it yourself -

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

And thus your example would become

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

but that would require changing the signature of eval , which might not be possible as I see it's annotated @Override .

This approach is extensible to Lists and Strings with Concatenation, Sets with union and Maps where the value is itself a monoid, "adding" all values of a given key, and functions under composition where the "zero" is the identity function.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM