# Rechenoperationen auf generische Datentypen



## leifg (29. Nov 2007)

Hallo zusammen,

ich suche eine Möglichkeit, wie ich 2 Zahlen addieren/subtrahieren/multiplizieren/dividieren kann. Also genauer gesagt, alle Zahlen die von der Klasse Number erben. Durch Boxing/Unboxing ist seit Java 5 ja folgendes möglich:


```
Float add(Float a, Float b)
{
 return a+b;
}

Integer add(Integer a, Integer b)
{
 return a+b;
}
...
```

Bisschen viel Schreibarbeit für alle Datentypen.

Folgendes funktioniert leider nicht:


```
public class fAdd2 < T extends Number >
{

public T sum( T a, T b )
{
 return a+b;
}
}
```

Was ist die eleganteste Lösung dieses Problem zu lösen, sodass ich eine Methode add habe die mir alle Formen von Zahlen addiert und als entsprechenden Datentyp wieder zurück liefert?


----------



## happy_robot (29. Nov 2007)

ein wenig tippen scheint schon notwendig, da Number wieder auf die basistypen zurückgeht.


```
public static<T extends Number> T add(T arg1, T arg2) {
		if(arg1 instanceof Integer) { return (T)new Integer(arg1.intValue()+arg2.intValue());	}
		if(arg1 instanceof Double) { return (T)new Double((double)arg1.doubleValue()+arg2.doubleValue());	}
		.....
	}
```

EDIT:

ausserdem würde ich persönlich von der nutzung der klassen-varianten der basis-typen abraten. 
da kann man sehr seltsame effekt mit erzeugen die als bugs fast nicht zu finden sind.


----------



## Marco13 (30. Nov 2007)

Und ich würde davon abraten, 5 Zeilen mit Methoden für verschiedene Typen durch 10 Zeilen mit lauter 'instanceof's zu ersetzen.....  :autsch:


----------



## happy_robot (30. Nov 2007)

Marco13 hat gesagt.:
			
		

> Und ich würde davon abraten, 5 Zeilen mit Methoden für verschiedene Typen durch 10 Zeilen mit lauter 'instanceof's zu ersetzen.....  :autsch:


genau dieses hatte er per aufgabenstellung ausgeschlossen!  :roll:


----------



## maki (30. Nov 2007)

> ch suche eine Möglichkeit, wie ich 2 Zahlen addieren/subtrahieren/multiplizieren/dividieren kann. Also genauer gesagt, alle Zahlen die von der Klasse Number erben.


Was stimmt denn nicht mit den standard Operatoren (+, -, /, *, %, ....)?

Falls das ein Beispiel sein sollte, finde ich es schlecht gewählt.


----------



## Marco13 (30. Nov 2007)

happy_robot hat gesagt.:
			
		

> Marco13 hat gesagt.:
> 
> 
> 
> ...


Hab ich auch nach erneutem Durchlesen nicht gefunden. Mein Beitrag bezog sich auch auf den ersten Lösungsvorschlag.


----------



## happy_robot (30. Nov 2007)

Marco13 hat gesagt.:
			
		

> Hab ich auch nach erneutem Durchlesen nicht gefunden. Mein Beitrag bezog sich auch auf den ersten Lösungsvorschlag.


nun denn. wenn du bei obiger aufgabenstellung von meiner lösung abrätst solltest du vielleicht  auch bessere alternativen aufzeigen können. ausserdem fehlt die begründung warum man das nicht machen sollte. das einzige was man anmeckern könnte ist das die methode wohl eine exception werfen sollte wenn sie für einen nicht unterstützten datentyp aufgerufen wird.

bin gespannt


----------



## Marco13 (30. Nov 2007)

Sowas wie 

```
Float add(Float a, Float b)
{
    return a+b;
}

Integer add(Integer a, Integer b)
{
    return a+b;
}
```
ist (objektiv) besser als

```
public static<T extends Number> T add(T arg1, T arg2) 
{
      if(arg1 instanceof Integer) 
      { 
          return (T)new Integer(arg1.intValue()+arg2.intValue());   
      }
      if(arg1 instanceof Double) 
      { 
          return (T)new Double((double)arg1.doubleValue()+arg2.doubleValue());   
      }
}
```
weil die erste Lösung weniger Schreibarbeit ist (was ein Hauptgrund für die ursprüngliche Frage zu sein schien), und 'typsicherer" ist (d.h. ohne instanceof und potentielle Exceptions auskommt). Außerdem ist sie (subjektiv) besser lesbar und leichter verständlich. 

Wenn du einen Grund nennen kannst, warum deine Lösung (objektiv) "besser" sein sollte, würde mich der auch interessieren.

Die Frage, warum nicht einfach die Standardoperatoren verwendet werden, ist aber nach wie vor ungeklärt.


----------



## happy_robot (30. Nov 2007)

Marco13 hat gesagt.:
			
		

> weil die erste Lösung weniger Schreibarbeit ist (was ein Hauptgrund für die ursprüngliche Frage zu sein schien), und 'typsicherer" ist (d.h. ohne instanceof und potentielle Exceptions auskommt). Außerdem ist sie (subjektiv) besser lesbar und leichter verständlich.


ich würde die andere variante auch vorziehen. alle anderen punkte sind aber durchaus streitbar. wenn ich zum beispiel alle additionen loggen will ist die generic-variante sicherlich weniger schreibaufwendig und nicht redundant. dadurch würde es dann auch besser lesbar (da nur 1x vorhanden). die frage des besseren verständnisses kann ich hier leider nicht beantworten.  
mein vorschlag sollte auch nur ein vorschlag sein. bislang gibt es aber scheinbar keinerlei alternativen und alle anderen vorschläge zielen an der aufgabenstellung vorbei (ob sie hierbei sinn macht oder nicht ist doch auch egal). 



			
				Marco13 hat gesagt.:
			
		

> Wenn du einen Grund nennen kannst, warum deine Lösung (objektiv) "besser" sein sollte, würde mich der auch interessieren.


sie ist weder besser noch ansatzweise gut. allerdings entspricht sie seinen anforderungen. ob die anforderungen dabei sinnvoll sind interessiert imho auch nicht.



			
				Marco13 hat gesagt.:
			
		

> Die Frage, warum nicht einfach die Standardoperatoren verwendet werden, ist aber nach wie vor ungeklärt.


diese variante garantiert ihm daß er immer additionen gleichen typs durchführt und sich nicht vielleicht die addition eines int + double oder so einschleicht. daher ist es vielleicht für seinen anwendungsfall typsicherer als das nutzen der standardoperatoren. ich kenne den "anwendungsfall" aber nicht.


----------



## Beni (30. Nov 2007)

Die Lösung mit mehreren Methoden funktioniert nicht, wenn man die Typen in der aufrufenden Methode nicht zur Kompilierzeit kennt.

Ich bin ja bekannt für meine komplizierten Lösungen... deshalb mal meine Inspiration:

Ein bisschen Vorbereiten

```
interface Operators<N>{
  N add( N a, N b );
  ...
}

class DoubleOperators extends Operators<Double>{
  public Double add( Double a, Double b ){
    return a + b;
  }
  ...
}
```

Der Algorithmus den man tatsächlich schreiben will

```
public <N> N doSomething( N a, N b, N c, Operators<N> ops ){
  return ops.mul( ops.add( a, b ), c );
}
```

Und so wird der Algorithmus aufgerufen:

```
doSomething( 1.0, 2.0, 3.0, new DoubleOperators() );
```


----------



## happy_robot (30. Nov 2007)

Beni hat gesagt.:
			
		

> Ich bin ja bekannt für meine komplizierten Lösungen... deshalb mal meine Inspiration:


sei mir nicht böse, aber da ziehe ich die unschöne instanceof-variante immer noch klar vor.   
diese lösung schaut zwar schlau aus, ist aber imho weder transparent noch performant.

wie auch immer, die etwas aufwendigere "klassische" version von Marco13 ist sicherlich die wohl sinvollste und wohl auch die die hier jeder vorziehen würde.


----------

