# Gutes Design mit statischen oder Member-Methoden



## samosa (3. Mrz 2011)

Hi,

ich habe eine Design-Frage. Angenommen wir haben folgende Beispielklasse:


```
public class Value {

    private double val;
    
    public Value(double val) {
        this.val = val;
    }

    public void add(Value value) {
        if(value != null) {
            this.val += val;
        }
    }
}
```

Betrachte den folgenden Code:


```
Value v = new Value(1);
Value[] values = {new Value(2), null, new Value(1)};
for(int i = 0; i < values.length; i++) {
    if(value[i]!= null) {
        values[i].add(v);
    }
}
```

Man stelle sich vor man hat weitere arithmetische Operationen und Arrays von values, die man manipulieren möchte. Mich stört hier, dass ich jedesmal wenn ich eine arithmetische Operation aufrufe, eine Abfrage machen muss, ob das entsprechende Array-Element ungleich 
	
	
	
	





```
null
```
 ist. Ein Ausweg wäre zusätzlich statische Methoden zu verwenden, etwa


```
public Value void add(Value u, Value v) {
    if(u != null) {
        return u.add(v);
    }
    return v;
}
```

Hier ist es hässlich, sowohl statische als auch Membermethoden mit der gleichen Funktionalität zu besiten. Würde ich komplett auf Membermethoden verzichten, so bräuchte ich statische Methoden, die das erste Argument verändern. 

Wie würde hier denn unter der Bedingung, dass man bei einer arithmetischen Operation kein neues Objekt erzeugt ein gutes Design aussehen?

Beste Grüße

samosa


----------



## maki (3. Mrz 2011)

Diese statische Alternative wäre imho nicht schön.

Dein Problem ist imho eher, dass du Arrays verwendest.
Nimm gleich eine Collection, und füge kein null ein.


----------



## samosa (3. Mrz 2011)

Danke für den Tip. Ich habe es eigentlich mit 2-dimensionalen und 3-dimensionalen Arrays zu tun.  Performancetests haben ergeben, dass mir Collections für mein Problem zu langsam sind. Geschwindigkeitsvorteile treten erst bei dünn bestzten Arrays auf.


----------



## Dow Jones (3. Mrz 2011)

Oder fange die Nullpointer Exception ab und ignoriere sie... 
Hmm, ein "schönes" Design würde hier aber glaube ich gar nicht erst mit Nullpointern arbeiten. Bestenfalls mit Nullobjekten, also einer Implementation des Value-Interfaces (das müsste dann natürlich erstellt werden), die ggf. keinerlei Funktionalität besitzt und nur dazu dient zwischen einem wirklichen Valueobjekt und einem nicht vorhandenen Valueobjekt (also dem, was z.Z. der Nullpointer ist) zu unterscheiden.


----------



## maki (3. Mrz 2011)

Darf man nach dem Performanceproblemen bzw. deinem Anwendungsfall fragen?

ArrayList sind Arrays von der Performace sehr ähnlich, beim entfernen von elementen allerdings... 
LinkedList wäre eine Alternative, ausser du brauchst wahlfreien (Indexbasierten) Zugriff.


----------



## samosa (3. Mrz 2011)

@Dow Jones
Ich bin mir nicht sicher ob ich das verstanden habe. Tausche ich da die null-Abfrage nicht durch eine 
	
	
	
	





```
instanceof
```
 Abfrage aus?


----------



## xehpuk (3. Mrz 2011)

Weißt du, was Generics sind?


----------



## samosa (3. Mrz 2011)

maki hat gesagt.:


> Darf man nach dem Performanceproblemen bzw. deinem Anwendungsfall fragen?



Matrizenmanipulationen, wobei Matrixelemente sparse double-Vektoren also Arrays von Values sind.


----------



## samosa (3. Mrz 2011)

xehpuk hat gesagt.:


> Weißt du, was Generics sind?



Ja. Was führst Du mit Generics im Schilde?


----------



## xehpuk (3. Mrz 2011)

Wofür genau brauchst du denn die Klasse? Matrizen würd ich dann wirklich mit double[][] machen.


----------



## samosa (3. Mrz 2011)

xehpuk hat gesagt.:


> Wofür genau brauchst du denn die Klasse? Matrizen würd ich dann wirklich mit double[][] machen.



Das wären normale Matrizen mit rellwertigen Einträgen. Bei mir geht es um Matrizen deren Elemente Vektoren sind also von der Form double[][][]. Jedoch sind die Vektoren dünn besetzt. Deswegen betrachte ich die Klasse Value


```
class Value {

    double val;
    int index;

    Value(int index, double val) {...}
}
```

Einen Vektor der Form v = (1, 0, 3, 0, 0, 0, 2) kann ich dann durch einen Array der Form

Value[] v = {new Value(0, 1), new Value(2, 3), new Value(6, 2)}

repräsentieren. Da ich viel mit solchen Arrays arbeite definiere ich eine Klasse SparseVector die ein Value-Array als Attribut besitzt.

Meine Matrix ist dann von der Form SparseVector[][] wobei 0-Vektoren durch null repräsentiert werden.


----------



## Andi_CH (3. Mrz 2011)

```
public static void add(Value u, Value v) {
    if(u != null) {
        return u.add(v);
    }
    return v;
}
```

return irgendwas; in einer void-funktion? Das geht ja schon gar nicht.
Mir ist schleierhaft wozu du die static funktion überhaupt brauchst.

Aber was ich sagen wollte:


```
if (x != null)...
```
 ist wohl etwas vom schnellsten was es gibt.

Ich sehe minimes Optimierungspotential, wenn du den Wert zwischenspeicherst:


```
Value v = new Value(1);
Value[] values = {new Value(2), null, new Value(1)};
for(int i = 0; i < values.length; i++) {
    if(value[i]!= null) {
        values[i].add(v);
    }
}
```


```
Value v = new Value(1);
Value[] values = {new Value(2), null, new Value(1)};
Value vv;
for(int i = 0; i < values.length; i++) {
    vv = value[i];
    if(vv!= null) {
        vv.add(v);
    }
}
```

aber ob das messbar was bringt wage ich nicht zu beurteilen.


----------



## samosa (3. Mrz 2011)

Andi_CH hat gesagt.:


> ```
> public static void add(Value u, Value v) {
> if(u != null) {
> return u.add(v);
> ...



Sorry, copy and paste Fehler. Danke für den Hinweis. Habe das oben wieder korrigiert.


----------



## maki (3. Mrz 2011)

dann ist imho Dow Jones mit seinem NullOBject Tipp genau richtig 

Definiere eine Unterklasse Value Klasse die sich anders verhält, eine einzige Instanz dieser Kalsse reicht(statisch, aber bitte kein GoF Singleton), so dass es keine Unterscheidung zwischen null und echten Value Objekten mehr nötig sind.

Zum Verhalten des NullObject:
Ein add ist ja nicht schlimm wenn wirklich nur 0 & 0.0 geadded wird, wenn dir das zuviel Rechenarbeit ist, kannst du ja in Value prüfen ob es sich um das NullObject handelt und nur adden wenn dem nciht so ist.


----------



## Dow Jones (3. Mrz 2011)

samosa hat gesagt.:


> @Dow Jones
> Ich bin mir nicht sicher ob ich das verstanden habe. Tausche ich da die null-Abfrage nicht durch eine
> 
> 
> ...



Nicht direkt. Du erzeugst dir vielmehr ein Objekt, das du genauso behandeln kannst wie ein Valueobjekt (so daß du nicht mehr abfragen musst ob wirklich ein Objekt oder ein Nullpointer vorliegt), das aber keinerlei Auswirkungen auf dein Programm ausübt. Das könnte zum Beispiel so aussehen:


```
class NullValue implemens Value
{
    public NullValue(double val) {
        // mach nichts
    }
 
    public void add(Value value) {
        // mach nichts
    }
	
    public void zeichneValueInDiagramm() {
        // mach nichts
    }
}
```

Im Idealfall müsstest du dich in deinem gesamten Programm gar nicht darum kümmern ob du es mit wirklichen Values oder nur diesen Dummyobjekten zu tun hast. (Ja, die Praxis sieht zwar meistens nicht so ideal aus, aber ein schöner Entwurf ist es trotzdem  ).

Siehe auch Nullobjekt (Entwurfsmuster) ? Wikipedia


----------



## Andi_CH (3. Mrz 2011)

Hm da stellt sich die Frage ob in die Dummyfunktion verzweigt wird - vermutlich schon und das ist dann auch nicht schneller als die 
	
	
	
	





```
if (x!=null)
```
 Abfrage, aber das Aufrufende Kontext sieht wesentlich eleganter aus.


----------



## samosa (3. Mrz 2011)

@ANDI_CH

Es geht bei der Frage nicht so sehr um Optimierung des Codes, sondern mehr darum, wie man das vernünftig programmiert, ohne Collections zu verwenden. Mich stören im Code die ständigen Abfragen, ob das Objekt ungleich null ist. Würde ich statische Methoden verwenden, dann kann ich die null-Abfrage ein für alle male in der statischen Methoden implementieren und brauch mir um Null-Referenzen dann keine Gedanken machen.

Allerdings möchte ich dass bei statischen Methoden das erste Argument geändert wird, weil ich keine Kopien erzeugen möchte.


----------



## maki (3. Mrz 2011)

Der Vorteil vom NullObject ist, dass man sich die null Abfragen sparen kann und sie deswegen auch nciht vergessen kann, also eine fehlerquelle eleminieren während man gleichzeitig weniger redundanten Code hat (null Abfragen quer über die Anwendung verstreut).

Beispiele aus der Java Collections API:
Collections.EMPTY_LIST
Collections.EMPTY_MAP
Collections.EMPTY_SET 

Für typsichere Generics bieten die Methoden eine Alternative:
Collections.emptyList()
Collections.emptyMap()
Collections.emptySet()

Ist natürlich blöd wenn jemand versucht diese NullObjekte zu verändern


----------



## samosa (3. Mrz 2011)

@maki und Dow Jones

Ich bin mir unsicher ob ich das verstanden habe. Bedeutet das, dass ich in meinem Value-Array die null-Referenzen durch NullObjekte ersetzen müsste, also künstliche Objekte erzeugen müsste?


----------



## Andi_CH (3. Mrz 2011)

samosa hat gesagt.:


> Mich stören im Code die ständigen Abfragen, ob das Objekt ungleich null ist. Würde ich statische Methoden verwenden, dann kann ich die null-Abfrage ein für alle male in der statischen Methoden implementieren und brauch mir um Null-Referenzen dann keine Gedanken machen.
> 
> Allerdings möchte ich dass bei statischen Methoden das erste Argument geändert wird, weil ich keine Kopien erzeugen möchte.



Jetzt verwirrst du mich:

```
static.add(v1, v2)
```
 mach rein gar nichts anderes als 
	
	
	
	





```
v1.add(v2)
```
Nach dem Aufruf ist das eine Objekt verändert und es gibt exakt gleich viele 
	
	
	
	





```
if (x!=null)...
```
 Abfragen ob die nun in der static Prozedur sind oder nicht, aber das Thema null-Abfrage ist mit dem Vorschlag von Dow jones ja erledigt. Übrigens sehr elegant wie ich finde.


----------



## maki (3. Mrz 2011)

samosa hat gesagt.:


> @maki und Dow Jones
> 
> Ich bin mir unsicher ob ich das verstanden habe. Bedeutet das, dass ich in meinem Value-Array die null-Referenzen durch NullObjekte ersetzen müsste, also künstliche Objekte erzeugen müsste?


Du brauchst nur ein einziges NullObjekt (statisch, aber kein GoF Singleton), soll ja keine Zustände speichern und Immutable sein, die Referenz kannst du immer wieder anstatt null verwenden.


----------



## samosa (3. Mrz 2011)

@ANDI_CH

Das ist richtig, die statische Methode macht das gleiche wie die null-Abfrage plus gleichnamige Membermethode.

Der Unterschied aber ist, dass ich bei Verwendung der statischen Abfrage nicht mehr null-Abfragen hinschreiben muss, weil diese bereits in der statischen Methode steckt. 

Du musst Dir vorstellen, dass ich haufenweise Operationen auf Matrizen schreibe und jedesmal diese lästige null-Abfrage einbauen muss.


----------



## samosa (3. Mrz 2011)

@maki

jetzt habe ich verstanden. darauf wäre ich nie gekommen. danke euch!


----------



## Andi_CH (3. Mrz 2011)

Noch zum Abschluss - es dauerte halt einige Minuten:


```
public class TestNull {

	private static class Value {
		public String toString() {
			return "Ich bin echt";
		}
	}

	private static class NullValue extends Value {
		public String toString() {
			return "Ich bin leer";
		}
	}

	private Value[] arr;

	private TestNull() {
		arr = new Value[5];
		Value nullValue = new NullValue();
		for(int i=0; i<arr.length; i++) {
			arr[i] = nullValue;
		}
	}
	
	private void add(Value v,int pos) {
		arr[pos] = v;
	}

	public void print() {
		for(int i=0; i<arr.length; i++)
			System.out.println(""+arr[i]);
	}

	public static void main(String[] args) {
		TestNull tn = new TestNull();
		tn.add(new Value(), 3);
		tn.print();
	}
}
```


----------



## samosa (3. Mrz 2011)

@ANDI_CH

Danke für das anschauliche Beispiel. 

Das Design mit dem NullObjekt sieht elegant aus. Einziger Wermutstropfen, ich muss die ganze Matrix durchlaufen und erst mal alles mit NullObjekten füllen. Wenn man 1000de solcher Matrizen moderater Größe hat, könnte das dauern.


----------



## Marco13 (3. Mrz 2011)

Die Strutktur der Matrix ist mir nicht ganz klar, hab's aber auch nicht konzetriert gelesen (eine dünn besetzte Matrix, deren Elemente 3D(!)-double-arrays sind?! Klingt schräg). 
Das mit den NullObjects ist zwar oft eine elegante Lösung (Collections#emptyList usw. wurden schon genannt) aber wenn es da um was zeitkritisches (und bei dünn besetzen Matrizen vermutlich auch Speicherkritisches) geht, macht das ja keinen Sinn: So eine Matrix liefert doch normalerweise automatisch 0 (oder eben null) an den nicht besetzten Stellen, und wenn man die mit Null-Objekten auffüllt, ist sie nicht mehr Sparse ... Worum geht's eigentlich: Um die "Effizienz" der if(null)-Abfrage, oder um die Ästhetik?


----------



## samosa (3. Mrz 2011)

@marco

die matrix besteht aus elementen, die dünn besetzte vektoren sind. die matrix selbst kann je nach anwendung sparse sein, muss es aber nicht. deswegen ist das nullobjekt in manchen fällen, so wie du sagst, zwar elegant aber störend.

mir geht es um die ästhetik aber auch um die lästige schreibarbeit. ich will die null-Abfrage möglichst elegant loswerden.


----------



## Dow Jones (3. Mrz 2011)

Marco13 hat gesagt.:


> So eine Matrix liefert doch normalerweise automatisch 0 (oder eben null) an den nicht besetzten Stellen, und wenn man die mit Null-Objekten auffüllt, ist sie nicht mehr Sparse ...


Ich muss zwar zugeben das ich die konkrete Anwendung hier auch nicht wirklich nachvollzogen habe, aber spricht denn etwas dagegen das die spärlich besetzte Matrix/Vektor statt 0 (oder eben null) das Nullobjekt zurückliefert? Dazu müsste man die Matrix doch nicht mit Nullobjekten auffüllen; genausowenig wie man sie ansonsten vorher mit 0/null auffüllt. 
Übersehe ich da etwas? :bahnhof:


----------



## maki (3. Mrz 2011)

Nachdem ich mir Marcos Post durchgelesen ahbe, sehe ich ein warum er immer sagt dass OOAD nicht unbedingt für jedes Mathematische Problem geeignet ist... 

Nachdem erstellen des Arrays wäre erstmal alles mit null vorbelegt... man müsste dann im Nachhinein die verbliebenen null Elemente durch das NullObject austauschen....

Wäre es eigentlich auch eine Option in der add Methode auf null zu prüfen?


----------



## samosa (3. Mrz 2011)

@Dow Jones

Ich versuche das Problem weiter zu vereinfachen. Angenommen wir haben folgende Datenstruktur 
	
	
	
	





```
String[][] tabelle
```
. In einer Anwendung sollen tausende Tabellen verarbeitet werden. Dabei kommt es vor, dass man elementweise Operationen auf die Einträge der String-Matrix durchführen muss (z.B append(), equals(), substring()). Man müsste dann jedesmal überprüfen, ob der Tabelleneintrag keine Nullreferenz ist. Das sieht nicht nur eklig aus sondern ist auch Schreibarbeit ;-)

Der Ausweg mit NullObjekten ist elegant, bedeutet aber, dass ich alle Elemente von tausenden von Tabellen initialisieren muss. Wenn ich eine Tabelle kopiere, muss ich ebenfalls alle Elemente der Matrix durchlaufen. Es gibt noch weitere Operationen, die den Zeitaufwand aufblähen.


----------



## samosa (3. Mrz 2011)

@Maki

Wenn die add-Methode eine Membermethode ist, erhalte ich einen Laufzeitfehler bei null-Referenzen. Deswegen die Überlegung mit statischen Methoden. Dort kann ich das dann machen und mein Problem wäre gelöst.

Meine Frage ist nun: Ist das sauber eine Klasse mit lauter statischen Methoden wie add(), mult(), usw zu schreiben, wobei die statischen Methoden die übergebenen Parameter verändern (ich will Kopien vermeiden).


----------



## slawaweis (3. Mrz 2011)

NullObject's beinhalten das Problem, dass der Array/List Producer und Consumer sich auch daran halten muss. Falls das System eine Blackbox ist, muss man das NullObject nach Außen sichtbar machen oder ständig null durch NullObject und umgekehrt ersetzen, was eine weitere Fehlerquelle sein kann.

Das eleganteste an dieser Stelle ist tatsächlich if(x != null). Was die statischen Funktionen angeht, man kann es machen, aber nicht in der Datenklasse, sondern in einer Utility-Klasse, welche nur statische Funktionen enthält. Da kann man auch gleich ein paar Funktionen/Fälle mehr einfügen, damit man keinen redundanten Code im Hauptteil schreiben muss:


```
public class ValueUtils
{
 public static Value add(Value u, Value v) {
    if(u != null) {
        return u.add(v);
    }
    return v;
 }

 public static void add(Value [] values, Value v) {
   // ...
 }

 public static void add(List<Value> values, Value v) {
   // ...
 }

 public static List<Value> add2Copy(List<Value> values, Value v) {
   // ...
 }
}
```

Slawa


----------



## Marco13 (4. Mrz 2011)

Dow Jones hat gesagt.:


> ...spricht denn etwas dagegen das die spärlich besetzte Matrix/Vektor statt 0 (oder eben null) das Nullobjekt zurückliefert? Dazu müsste man die Matrix doch nicht mit Nullobjekten auffüllen; genausowenig wie man sie ansonsten vorher mit 0/null auffüllt.
> Übersehe ich da etwas? :bahnhof:



Nö, das würde ggf. auch gehen, aber ... es stimmt schon: Der Kontext wäre hier wichtig, vielleicht morgen nochmal durchlesen....


----------



## Andi_CH (4. Mrz 2011)

samosa hat gesagt.:


> @ANDI_CH
> 
> Danke für das anschauliche Beispiel.
> 
> Das Design mit dem NullObjekt sieht elegant aus. Einziger Wermutstropfen, ich muss die ganze Matrix durchlaufen und erst mal alles mit NullObjekten füllen. Wenn man 1000de solcher Matrizen moderater Größe hat, könnte das dauern.



Wenn du Millionen von Einträgen hast wirst du es vielleicht bemerken - Java ist zwar schnell aber sicher nicht die schnellste aller Sprachen. Wenn es darauf ankommt müsstest du etwas nehmen das *nicht* auf eine VM läuft.
Also vergiss den Wermutstropen ;-)

So nebenbei, wie messe ich möglichst präzise die Laufzeit eines Codeteiles?
Wie lange dauert es auf einem durchschnittlichen PC, einen Array mit einer Million Elementen zu setzen?

EDIT:

Konsturktor abgeändert:

```
private TestNull(int length) {
		arr = new Value[length];
		Value nullValue = new NullValue();
		start = System.currentTimeMillis();
		for(int i=0; i<arr.length; i++) {
			arr[i] = nullValue;
		}
		stop = System.currentTimeMillis();
	}
```
und aus dem Hauptprogramm die Differenz ausgegeben.

Aus Eclipse gestartet:


```
Start = 1299229508764
Stop  = 1299229508858
Zeitaufwand um 100000000 Elemente zu setzen ist 94 Millisekunden
```


----------



## maki (4. Mrz 2011)

> So nebenbei, wie messe ich möglichst präzise die Laufzeit eines Codeteiles?


Mit einem Profiler, zB. VisualVM, gibt auch das TPTP Projekt von Eclipse.
Allerdings kann sich die Laufzeit eines Codeteiles rapide ändern wenn der JIT Compiler der HotSpot VM zuschlägt.


----------



## Andi_CH (4. Mrz 2011)

maki hat gesagt.:


> Mit einem Profiler, zB. VisualVM, gibt auch das TPTP Projekt von Eclipse.
> Allerdings kann sich die Laufzeit eines Codeteiles rapide ändern wenn der JIT Compiler der HotSpot VM zuschlägt.



Hab gerade oben editiert 

Ich glaube nicht dass der Loop der die 100'000'000 Elemente setzt durch den GC unterbrochen wird ;-)

Aber dein Einwand sollte für den TO erst recht Motivation sein, *nicht* über die wenigen Millisekunden Aufwand nachzudenken die das braucht


----------



## Marco13 (4. Mrz 2011)

Es könnte in diesem Fall auch um den Speicher gehen. Oben war dann ja davon die Rede, die Matrix "mit NUllObjects zu füllen" - was ja keinen Sinn machen würde, wenn man davon ausgeht, dass die Matrix als CRS, CCS oder sonstwas gespeichert ist. An den nicht gefüllten Stellen automatisch ein NullObject zurückzugeben würde die null-Abfrage ja nur vom "Client" in die Matrix verschieben, deswegen die Frage, ob es da um Effizienz oder Schönheit geht.


----------



## Andi_CH (4. Mrz 2011)

Aehm - es geht um Arrays in denen Referenzen auf Objekte liegen und es geht darum nicht überall 
	
	
	
	





```
if (xx[i]!=null)
```
 hinschreiben zu müssen. (Obwohl ich das hemmungslos getan hätte, denn das "überall" beschränkte sich auf eine Methode)


EDIT:

Es gibt schon Ausreisser:

```
Start = 1299231621860
Stop  = 1299231621969
Zeitaufwand um 100000000 Elemente zu setzen ist 109 Millisekunden
```

Da ging sogar sehr kurzfristig in kleines popup auf, das ich aber nicht erkennen konnte...

EDIT:

1000 mal geloopt : die Verteilung der Zeiten:
78 Millisekunden kam 189 mal vor
79 Millisekunden kam 24 mal vor
93 Millisekunden kam 138 mal vor
94 Millisekunden kam 394 mal vor
109 Millisekunden kam 48 mal vor
110 Millisekunden kam 20 mal vor
111 Millisekunden kam 1 mal vor
125 Millisekunden kam 85 mal vor
126 Millisekunden kam 2 mal vor
140 Millisekunden kam 25 mal vor
141 Millisekunden kam 48 mal vor
156 Millisekunden kam 15 mal vor
157 Millisekunden kam 11 mal vor


und der GC kam immer mal wieder dazwischen (so nach 4 - 5 Kontruktoraufrufen und das dauerte geschätzt bis zu einer Sekunde bevor Eclipse wieder "rannte")


----------



## slawaweis (4. Mrz 2011)

ich habe den Benchmark auf einem Atom Z520 laufen lassen, mit -Xms512m -Xmx1024m:


```
for(int i=0; i<arr.length; i++) {
            arr[i] = nullValue;
        }
```


```
Zeitaufwand um 100000000 Elemente zu setzen ist 2797 Millisekunden
```


```
for(int i=0; i<arr.length; i++) {
           if(arr[i] == null)
            arr[i] = nullValue;
        }
```


```
Zeitaufwand um 100000000 Elemente zu setzen ist 3029 Millisekunden
```

kommt eben auf den Prozessor an.

Slawa


----------



## maki (4. Mrz 2011)

Was passiert, wenn du zusätzlich zu Xms und Xmx auch noch [c]-server[/c] angibst?


----------



## slawaweis (4. Mrz 2011)

zwar dauert der gesamte Durchlauf des Programms etwas länger, aber an der gemessenen Stelle ergeben sich folgende Werte:


```
// ohne if(arr[i] == null)
Zeitaufwand um 100000000 Elemente zu setzen ist 875 Millisekunden

// mit if(arr[i] == null)
Zeitaufwand um 100000000 Elemente zu setzen ist 953 Millisekunden
```

Slawa


----------



## Marco13 (4. Mrz 2011)

Solche Microbenchmarks sind immer heikel. Die einzige Möglichkeit, auch nur den Hauch einer Aussage da raus zu ziehen, ist mit einem Muster wie

```
void test()
{
    for (int size=min; size<=max; size++)
    {
        for (int run=0; run<runs; run++)
        {
            testA(size);
            testB(size);
        }
    }
}
```
Abwechselnd beide Tests mit Zeitmessungen (am ehesten noch mit System.nanoTime) und steigender Eingabegröße, und das ganze ein paar mal wiederholt und die Zeiten ggf. gemittelt.


----------



## Dow Jones (4. Mrz 2011)

Andi_CH hat gesagt.:


> Aehm - es geht um Arrays in denen Referenzen auf Objekte liegen und es geht darum nicht überall
> 
> 
> 
> ...


Stimmt, würde ich auch. Man muss nicht jede 10-Zeilen-Methode nach dem Lehrbuch designen, in so kleinem Rahmen kann "Spaghetticode" durchaus die beste Lösung sein.

Wobei - wenn der TE nicht gerade unter Zeitdruck steht kann er diesen Fall ja zum Anlass nehmen sich mal in AOP einzuarbeiten. Dann hätte er seine schnellen Arrays und bräuchte nicht überall if-null-Abfragen hinzuschreiben.


----------



## fastjack (4. Mrz 2011)

Wenn Ihr jetzt noch weiter über Benchmarks redet, schreibe ich auch einen 

Das mit dem Nullobjekt ist schon gut, allerdings muß der Nutzer das auch wissen. Wenn Deine Methode sowieso null ignoriert, warum verbietest Du es dann nicht einfach, entweder per Konvention in der Doc, oder per Prüfung in der add()-Methode und werfen einer IllegalArgumentException. Ich würde zu Ersterem raten.

Wenn ich als Programmierer null adden will, bin ich selbst schuld  Aber das Schlimmste, was ich erwarten würde, ist, das es schweigend weggefiltert wird, oder durch ein Nullobjekt ersetzt wird. Um das zu verhindern, baue Dir eine Klasse die das Array ersetzt.


----------



## samosa (7. Mrz 2011)

Danke für Eure Kommentare, habe eine Menge gelernt von Euch.

Beste Grüße

samosa


----------



## Andi_CH (7. Mrz 2011)

slawaweis hat gesagt.:


> zwar dauert der gesamte Durchlauf des Programms etwas länger, aber an der gemessenen Stelle ergeben sich folgende Werte:
> 
> 
> ```
> ...



Was hab ihr bloss für Steinzeitmaschinen? Sogar mein IBM R51 (Jahrgang nicht mehr bekannt) schaffte es in knapp über 100mS


----------



## Marco13 (7. Mrz 2011)

Hängt wie schon andegeutet auch von JRE und Startparametern ab...


----------



## Dit_ (7. Mrz 2011)

Ich hab mal gelern, dass bei Berechnung von Aufwand die if-Abfragen nicht berücksichtigt werden, da diese so gut wie "nichts kosten" ( ein Prozessortakt? ).

Ich würde lieber so lassen wie es ist, es ist sicher und hat fast keine Geschwindigkeitsnachteile. Selbst wenn ich zu 100% sicher bin, ich werde nie "null" übergeben, überpruefe ist trotzdem auf "null". Code wird zwar länger, aber es ist eine gute Gewohnheit, die bei sehr großen Projekte mit vielen Abhängigkeiten viel Ärger einspart.

Außerdem kann du immer noch


```
else {
System.err.println("dies haette nicht passieren dürfen: val ist null");
//oder
//Logger.....
```

hinzufuegen, hilft auch manchmal


----------



## tfa (7. Mrz 2011)

> Selbst wenn ich zu 100% sicher bin, ich werde nie "null" übergeben, überpruefe ist trotzdem auf "null". Code wird zwar länger, aber es ist eine gute Gewohnheit, die bei sehr großen Projekte mit vielen Abhängigkeiten viel Ärger einspart.


Warum? So behinderst du nur die Fehlersuche, wenn das Objekt trotz allem doch mal null wird. Wenn gleich eine NullpointerException fliegt, kann man die leicht an der richtigen Stelle ausfindig machen und beheben. Wenn du den Fehler verschleppst, tritt er vielleicht erst Stunden oder Tage später als falsch berechneter  Wert in der Datenbank hervor. Das macht Ärger.


----------



## Dit_ (7. Mrz 2011)

ich meine nur, dass ich immer einen Fehler erwarte und die Behandlung sofort (im else oder catch-block) implementiere ohne zu warten, dass der Fehler irgendwann auftritt, try-catch oder if-else ist ja egal. Ich gehe nur immer davon aus dass es zu Fehler kommt.

Ich ich es ist beser als eine "BitteKeinNullÜbergebenKonvention" 

gruß


----------



## tfa (7. Mrz 2011)

> ich meine nur, dass ich immer einen Fehler erwarte und die Behandlung sofort (im else oder catch-block) implementiere ohne zu warten, dass der Fehler irgendwann auftritt


Dann behebst du den Fehler nicht, sondern baust gleich einen Workaround in deinen Code ein. Das halte ich für prinzipiell schlechtes Design.


----------



## Dit_ (7. Mrz 2011)

wenn ich mit Workaround den Fehler logge, dann kann ich das Problem auch später entdecken, wenn die testphase abgeschlossen ist und ich keine Konsole die mit exception anzeigt habe, es sei denn jemand kann behaupten, dass sein Programm zu 100% getestet ist und fehlerfrei ist (für mehrere BSs zB), dann kann man sicher sein dass es nicht knallt, perfektes Design gelungen.

aber es ist glaube ein Sache des Geschmacks


----------



## slawaweis (7. Mrz 2011)

Andi_CH hat gesagt.:


> Was hab ihr bloss für Steinzeitmaschinen? Sogar mein IBM R51 (Jahrgang nicht mehr bekannt) schaffte es in knapp über 100mS


sagst Du das auch zu deinen Kunden?

Es war ein Netbook, 1,5 Jahre alt, JDK 1.6.0_20.

Slawa


----------



## Landei (7. Mrz 2011)

samosa hat gesagt.:


> Einen Vektor der Form v = (1, 0, 3, 0, 0, 0, 2) kann ich dann durch einen Array der Form
> 
> Value[] v = {new Value(0, 1), new Value(2, 3), new Value(6, 2)}
> 
> repräsentieren.



Spricht irgend etwas dagegen, statt einem Array aus Values einfach eine [c]Map<Integer,Integer>[/c] zu verwenden? Also obiges Beispiel als: 

```
Map<Integer,Integer> v = new TreeMap<Integer,Integer>();
v.put(0,1);
v.put(2,3);
v.put(6,2);
```

Das Ganze würde ich noch in eine nette Klasse verpacken, die automatisch 0 zurückliefert, wenn die Map den Wert nicht enthält.


----------

