2012-10-05 30 views
5

Das Szenario ist, dass ich mindestens zweimal auf einen Wert zugreifen muss. I.e. Ich benutze Logger, um zu verfolgen, was in der Anwendung passiert. Ich möchte den Namen des Objekts protokollieren, an dem diese Funktion arbeitet, und später etwas mit dem gleichen Namen (d. H. Prüfen, ob es eine Zeichenfolge enthält oder in ein Array einfügen).Verwenden von Variablen zum Speichern von Werten oder zum direkten Abrufen von Werten aus den Objekten?

in Variable den Namen speichern:

foo(Bar bar){ 
    String name = bar.getName(); 
    logger.info("I am working with "+name); 
    this.doSomethingWith(name); 
} 

Oder rufen getName() zweimal:

foo(Bar bar){ 
    logger.info("I am working with "+bar.getName()); 
    this.doSomethingWith(bar.getName()); 
} 

Ich verstehe, dass in dem ersten Szenario, werde ich einen neuen String erstellen, weisen einen Wert dazu und dann diesen Wert zweimal abrufen. Auf diese Weise verwende ich mehr Speicherressourcen, richtig?

Im zweiten Szenario greife ich zweimal auf die Objektleiste zu und dann zweimal auf ihren Namen. Ich nehme an, das ist kein DRY-Ansatz. Aber auf der anderen Seite wiederhole ich mich nicht in der Erinnerung, richtig?

Welcher Ansatz ist besser?

+0

In der ersten Methode erstellen Sie _not_ nicht einen neuen String. Beide Methoden sollten also den gleichen Speicherverbrauch haben. – Fildor

+0

Es könnte sich lohnen, den generierten Byte-Code mit einem Decompiler zu überprüfen, um festzustellen, ob Ihr Problem wirklich ein Problem ist. 'javac' könnte diesen Anwendungsfall erkennen und auf die eine oder andere Weise optimieren, egal wie Sie ihn in Java schreiben. – akaIDIOT

Antwort

1

Persönlich bevorzuge ich den zweiten Ansatz. Tatsächlich erstelle ich temporäre Variable normalerweise nur wenn nötig.

Auch Martin Fowler (http://en.wikipedia.org/wiki/Martin_Fowler) folgt dieser Richtlinie. Er bezieht sie sich in seinem Buch, das ich gelesen habe:

http://www.amazon.fr/Refactoring-Improving-Design-Existing-Code/dp/0201485672

Ein kostenloser Auszug aus seinem Buch zu diesem Thema finden Sie hier:

http://sourcemaking.com/refactoring/replace-temp-with-query

Einige Leute würden argumentieren, temporäre Variablen zu entfernen konnte zu Leistungsproblemen führen.

Wie Martin Fowler sagt:

Sie über die Leistung in diesem Fall betroffen sein kann. Wie bei anderen Leistungsproblemen lassen Sie es für den Moment gleiten. Neun Mal von zehn, wird es nicht darauf ankommen. Wenn es darauf ankommt, werden Sie das Problem während der Optimierung beheben.Mit Ihrem Code besser faktorisiert, werden Sie oft leistungsfähigere Optimierungen finden, die Sie ohne Refactoring verpasst hätten. Wenn es schlimmer wird, ist es sehr einfach, die Temperatur zurück zu setzen.

Aber wie auch immer, es ist Geschmackssache. Manche Menschen finden den ersten Ansatz besser lesbar, andere den zweiten. Ich bevorzuge die Sekunde, weil ich temporäre Variablen hasse, die keine echten Werte hinzufügen :)

+0

Dieser Martin Fowler Ansatz ... ist super! – user1581900

+0

@ user1581900 Sie sollten sein Buch lesen, ich liebte es :) Siehe auch Robert C Martin für "Clean Code" Buch :) – Mik378

1

Ihre Bar sollte unveränderliche Klasse (für die meisten Fälle). Für unveränderliche Klassen sind diese Ansätze die gleichen, also wählst du, was du willst.

Jedes echte Problem wird nur auftreten, wenn Bar veränderbar ist, so kann Wert von bar.name zwischen 2 Lesevorgänge ändern. Aber dieser Fall wird mit Bar als Domain-Objekt (was es scheint) sinnlos machen. Sie können solche Fälle umgehen, indem Sie eine lokale Kopie von bar oben auf foo() erstellen. Dann, wieder einmal, wenn Sie lokale Kopie des Originals bar haben, können Sie wählen, was auch immer Sie mehr mögen.

Also, das ist Geschmackssache. Ja, Sie könnte verschwenden ein kleines bisschen Speicher für lokale Referenz im ersten Fall, aber höchstwahrscheinlich wird JVM es weg optimieren, damit es wie 2. Weg auf Byte-Code-Ebene aussehen.

3

Sie verwenden nicht mehr Speicher im ersten Beispiel, weil String ein unveränderliches Objekt ist. Daher ist jede Bezugnahme auf eine Zeichenfolge einfach ein Zeiger auf dasselbe Objekt im Speicher.

Die letztere Option hat auch einige Probleme der Threadsicherheit, wo das Ergebnis von getName() zwischen den Aufrufen geändert werden kann. Obwohl möglicherweise unwahrscheinlich, ist es etwas, was Sie vielleicht in Betracht ziehen möchten.

In diesem Sinne würde ich die erste Option empfehlen, obwohl es "talky" ist.

Hinweis: Es ist auch möglich, dass getName() durch Berechnung generiert wird. In diesem Fall würden Sie tatsächlich mit der zweiten Methode enden, die mehr Speicher als die erste verwendet.

+0

So im ersten Szenario zeigen sowohl String-Name und bar.getName() auf den gleichen String im Speicher. Wenn ich bar.name ändere, ändere ich es nicht wirklich, sondern zeige es auf einen anderen String, während der String-Name immer noch auf den alten Wert zeigt. – user1581900

+1

Das ist richtig. Aus diesem Grund geben alle Methoden in java.lang.String einen neuen String zurück, anstatt das Objekt zu ändern, an dem sie aufgerufen werden. –

Verwandte Themen