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)
.
C is a middle-level language as it binds the bridges between machine-level and high-level languages. Java is a high-level language as the translation of Java code takes place into machine language, using a compiler or interpreter. C is only compiled and not interpreted. Java is both compiled and interpreted.
As Java was inspired by C and C++, its syntax is similar to these languages. C++ is both a procedural and object-oriented programing language. Hence, C++ has features specific to procedural languages as well as features of object-oriented programming language. Java is a completely object-oriented programming language.
Java does not have pointers. It has references almost exactly as C++ has.
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:
+=
on generics in java.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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With