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:
you cannot use += 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.
Related
How do I implement void add(Number number) so it adds number to the object instance
public interface Numbers {
static int toIntValue();
static void fromIntValue(int value);
default void add(Number number) {
// what do i write here
}
}
You mostly cannot do this; interfaces do not have any state, and the notion of 'add a number' strongly implies that you wish to update the state.
This is one way to go:
public interface Number /* Isn't Numbers a really weird name? */ {
int toIntValue();
default int add(int otherValue) {
return toIntValue() + otherValue;
}
}
Here no state is changed; instead a new int is returned.
Another problem here is that the whole notion of abstracting away a numeric type is that there is no default implementation of add.
That's just basic math. Complex numbers are a kind of number; it is clearly impossible to write code that can add 2 complex numbers together without knowing anything about complex numbers beforehand.
What you CAN do is create add out of other primitives, except, 'add' is generally the convenient primitive. For example, here's a take on multiply that can work as a default method, though it is not at all efficient:
public interface Number {
Number plus(Number a); /* an immutable structure makes more sense, in which case 'plus' is a better word than 'add' */
default Number multiply(int amt) {
if (amt == 0) return Number.ZERO; // Define this someplace.
Number a = this;
for (int i = 1; i < amt; i++) a = a.plus(this);
return a;
}
}
Here you've defined multiply in terms of plus.
Note that java already has an abstract number concept (java.lang.Number) and it indeed can do almost nothing, because trying to abstract math like this is hard in any language, and particularly so in java.
I'm trying to implement a function that returns the maximum object of a given Comparable (generic) list.
I have 3 classes that I have implemented their compareTo method that returns the 1 if this is bigger than other, -1 if this is smaller than other, and 0 if they're equal.
Now my problem is with understanding with how do I work with a generic input COmparable list.
Here's the signature of my function, and the code I wrote so far (that refuses to work on me):
public static Comparable<?> getMax(List<Comparable<?>> ls) {
LinkedList<Comparable<?>> tmpComp = new LinkedList<Comparable<?>>();
for (Comparable<?> c : ls)
tmpComp.add(c);
Comparable<?> maxObj = tmpComp.get(0);
for (Comparable<?> c : tmpComp)
if (c.compareTo(maxObj) > 0)
m = c;
return m;
}
I'm writing a system that has users in it, and ads. Users and ads both classes that have "profit" field on them that all I do in my compareTo methods is to compare which of the two (this, or other) have more profit and then just returns the right value according to that. The 3rd class is compared via another field, which is an int as well, that indicates the level (int) of the Quest.
Also that if statement, specifically, gives me an error of the type "is not applicable for the arguments".
Any clues?
Thanks in advance!
Reading your comment, I suggest you redesign your model to be:
interface ProfitGenerating {
double getProfit();
}
class User implements ProfitGenerating {
...
}
class Advert implements ProfitGenerating {
...
}
List<ProfitGenerating> profits = ...;
Optional<ProfitGenerating> maxProfit = profits.stream()
.max(Comparator.comparingDouble(ProfitGenerating::getProfit));
The answer by Mạnh Quyết Nguyễn is good. But it does not account for the situation where you have multiple potential types T, which appears to be your situation.
So in that situation, just wrap your various classes with a single class and use his solution.
If you have a User class and an Ad class, then create a wrapper like so:
class ProfitMaker implements Comparable<ProfitMaker> {
User user;
Ad ad;
public int compare(ProfitMaker p) {
//check my profit and compare with profit of p
}
}
Use that class as the "T" when usign the getMax from Mạnh Quyết Nguyễn.
Alternatively, use an interface
interface ProfitMaker extends Comparable<ProfitMaker> {
int getProfit();
}
Make both your User and Ad classes implement that interface, and that use that interface as the "T" along with the getMax method from Mạnh Quyết Nguyễn.
Your three classes must be comparable to each other. For this they will need to implement Comparable<SomeX> where SomeX is their lowest common superclass. In the worst case, SomeX is Object.
If this is the case, you can simply do:
ls.stream().max(Comparator.naturalOrder())
Alternatively, instead of forcing your classes to implement Comparable<...>, you could capture comparison semantics in a Comparator<...> and then do:
ls.stream().max(comparator)
Using a comparator is better for cases where the order is not really "natural" for the type or where there may be different orders. I think this is the case here since you actually compare instances of different types. It is hard to argue that some order is "natural" for these instances as they don't even belong to one type.
If you compare your instances based on some property they share (like int getProfit()), it would make sense creating a common interface like Profitable. Then you could do:
ls.stream().max(Comparator.comparintInt(Profitable::getProfit))
Note that if you compare on privitive types, you should use comparingInt/comparingLong/comparingDouble instead of comparing to avoid unnecessary boxing and unboxing.
If you for some reason can't create and implement a common interface like Profitable, you can still use comparingInt and likes. You'll just have a much uglier lambda:
ls.stream().max(Comparator.comparintInt(l -> {
if (l instanceof Ad) { return ((Ad) l).getProfit(); }
else if (l instanceof Ransom) { return ((Ransom) l).getProfit(); }
// ...
else { throw new IllegalArgumentException(...); }
}))
I would in some way store many different type in a HashMap, but in a way that when i extract them they will be well typed (and not an object).
So i think about a wrapper that use generics
public class Value <T>
{
private T innerValue ;
public Value ( T _value )
{
innerValue = _value ;
}
public T read ()
{
return innerValue ;
}
}
but it does not work, for a test i made :
Value <Integer> va = new Value <Integer> ( 1 ) ;
Value vc = va ;
int restA = vc.read();
but i get a design time error, because vc.read() will return an Object() and not an Integer.
So what should i do to avoid this behaviour? (if possible i would a solution that prevent 'va' from losing information about T instead of other workaround)
Thanks in advance for any help.
You casted va to a raw Value, vc. When you use the raw form of a class, your T generic type parameter is replaced by Object. So you cannot assign an Object to an int.
If you just call va.read(), then it will return an Integer, which will be unboxed to an int upon assignment to restA.
I would in some way store many different type in a HashMap, but in a
way that when i extract them they will be well typed (and not an
object).
Short answer is: this is not possible. And type erasure is not the reason: it simply does not make much sense to have this information at compile time. Suppose that Java compiler had some kind of mechanism to keep track of the types of objects stuffed into a HashMap. Then it also would have to cope with something like this:
HashMap<Integer, Value<?>> myMap = new HashMap<Integer, Value<?>>;
if (Math.random() > 0.5) {
myMap.put(0, new Value<String>("hello world"));
} else {
myMap.put(0, new Value<MacaroniExtruder>(new MacaroniExtruder()));
}
[whatDoYouWantToWriteHere?] value = myMap.get(0);
What you want is probably rather something like "type-union". Unfortunately, it does not exist neither in Java, nor in Scala (where we have case-classes, which are almost just as good for that). So all you can do is basically:
A) Use polymorphism, define a proper interface, so that the concrete implementations become completely irrelevant, and work with that interface as second argument to your hash Map (preferred).
B) Use instanceof and long if-else switches (ugly)
I'm trying to create a custom class the creates matrices and, among other things, performs operations that add up all of the cells or multiply them all. However, I want to use generics so the matrices can be any type of number: float, double, int, etc. I have thus set up the class like this:
public class Matrix<num>
Upon initialization, the instantiation of this class creates a matrix based on user supplied data, stored in the instance's .matrix variable. Now, in the code where I want to add up all of the cells, I do something like this:
public num addMatrices(num[][] toAdd){
num result;
if (toAdd.length != this.rows && toAdd[0].length != this.columns){
System.out.println("Matrix mismatch. Try Again.");
return toAdd[0][0];
}
for (int i=0; i<rows; i++)
for (int j=0; j<rows; j++){
result = this.matrix[i][j] + toAdd[i][j];
}
}
I'm running into multiple problems, however. First of all, I can't initialize result to zero, which makes it hard to perform += operations. Secondly, when I try to add the cells of the two matrices, the compiler tells me that the + operator is undefined for the type num.
I thought the whole point of generics was to have a catchall type so I could do things like use floats in one case and ints in another, but if I need to specify the type for operators like +, I'm not sure where the advantage comes in...
You can't perform operations like + and - on Objects (some special cases excluded). Generics are all about Object types, so your use case for them isn't ideal.
That said, you can turn your declaration into something like public class Matrix<num extends Number>, which will let you pass in Integer, Double, BigInteger, etc. then you can then use something like num.longValue() or num.doubleValue() to get the long or double representations of your numbers. You would then need to return a double or long or whatever from your method instead of your generic type, though.
the other option would be to create a custom container class that has methods for add, subtract, etc. Then your class declaration can be public class Matrix<num extends Custom>. You would have to figure out how to account for adding longs to doubles and returning the Custom type.
The problem is that you num can be anything. So, for example, what would it need to do if you created a Matrix<Object>?
You could try to make your number extend from Number, but even then you won't be able to use + because java don't know what to cast this generic to.
You could create a method similar to your Matrix with generic that does that. Something like
public static <NUM extends Number> NUM add(NUM[][] matrixA, NUM[][] matrixB, NumFunction<NUM> function) {
// all equals to your add method, but the result you get with
result = function.apply(this.matrix[i][j], toAdd[i][j]);
}
public interface NumFunction<NUM extends Number> {
NUM apply(NUM operA, NUM operB);
}
You will need to duplicate NumFunction to every type of Number, or create one generic that checks what type of Number is with "instanceof". It's not very pretty :P
I have a hierarchy, which I'll simplify greatly, of implementations of interface Value. Assume that I have two implementations, NumberValue, and StringValue.
There is an average operation which only makes sense for NumberValue, with the signature
NumberValue average(NumberValue numberValue){
...
}
At some point after creating such variables and using them in various collections, I need to average a collection which I know is only of type NumberValue, there are three possible ways of doing this I think:
Very complicated generic signatures which preserve the type info in compile time (what I'm doing now, and results in hard to maintain code)
Moving the operation to the Value level, and: throwing an unsupportedOperationException for StringValue, and casting for NumberValue.
Casting at the point where I know for sure that I have a NumberValue, using slightly less complicated generics to insure this.
Does anybody have any better ideas, or a recommendation on oop best practices?
As #tafa said, it seems to me an interface would be a good choice. Based on your signature for average, I came up with the below.
AveragableValue
public interface AveragableValue<T> extends Value
{
public T average(T value);
}
NumberValue
public class NumberValue implements AveragableValue<NumberValue>
{
private int _n;
public NumberValue(int n)
{
this._n = n;
}
#Override
public void doSomething()
{
// from Value interface
}
#Override
public NumberValue average(NumberValue value)
{
return new NumberValue((this._n + value._n) / 2);
}
}
Then you can have your collection be of type AveragableValue. Already in your code you must have some kind of if/else clause somewhere to differentiate NumberValue and StringValue to figure out whether to call average or not. So I don't see how this would be more complicated. The hierarchy make sense - AveragableValues are a subtype of Value, and a NumberValue is a type of AveragableValue.
However, that signature for average doesn't look right. It only takes 2 values (this and the argument) and averages them. You then lose the total count of things that have been averaged before. So assuming integers as the values (as I did), something like this:
(new NumberValue(4)).average(new NumberValue(8)).average(new NumberValue(12));
would give you the value 9 instead of 8. Is this what you want? It makes it bad for many calculations done iteratively, as you may be doing with collections.
If you show us some of your code - how these classes are used, the collections holding them, how you are doing averaging right now - I can maybe give a better answer.
I would have create another interface IAveragable which contains the average operation which derives from Value . Then StringValue would implement just Value interface and NumberValue would implement IAveragable.
Then when it is required to use the average operation I would check if the object implements IAveragable.
I'm unable to comment, therefore I'll just post a new answer.
Create an interface for value:
public interface Value<T> {
public T getValue();
}
And one for averagable:
public interface Averagable<T> {
public T average(T value);
}
Then a number value would be something like:
public class NumberValue implements Averagable<Number>, Value<Number>{
public Number average(Number value) {
// do your stuff
}
public Number getValue() {
// do your stuff
}
}
There is no need to let Averagable extend from Value.