Mehrere Aufrufe an eine Void-Methode, die den Listenparameter als Rückgabewert verwenden, sind besser als eine Methode, die eine List zurückgibt?

8

Kurz gesagt lautet meine Frage: Wenn eine Methode mehrere Male aufgerufen wird, ist es besser, wenn der Speicherverbrauch void ist und Sie eine Liste als Parameter verwenden seine Werte zurückgeben? Wenn es wirklich Speicher spart, ist es nicht eine schlechte Übung, da der Code schwerer zu lesen ist?

Lassen Sie mich ein Beispiel geben, um es klarer zu machen. Angenommen, ich habe eine Klasse Auto und jedes Auto muss einer Marke angehören. Ich habe eine Methode, die alle Autos aus einer Liste von Marken zurückgibt und diese Methode verwendet eine foreach und eine Methode, die alle Autos einer Marke abruft. Wie der folgende Code:

%Vor%

Ein Kollege von mir verteidigt, dass die Methode getCarsBySingleBrand neu geschrieben werden sollte void und eine Liste als Parameter verwenden sollte und diese Liste enthalten würde alle Autos, wie Sie unten sehen können:

%Vor%

Er argumentiert, dass auf diese Weise weniger Speicher verbraucht wird, da er nicht jedes Mal eine Liste erstellt, wenn die Methode getCarsBySingleBrand aufgerufen wird. Ich denke, das ist eine Art unnötige Optimierung und ist eine schlechte Übung, weil der Code schwerer zu verstehen ist.

    
gmauch 14.01.2015, 20:35
quelle

5 Antworten

8

Die zweite Option MIGHT ist optimaler.

Das Problem ist der erste Weg, nicht nur ein anderes List Objekt für jede Marke zu machen, welches dann einfach weggeworfen wird, sondern wenn es viele Autos für eine Marke gibt, wird Java die Größe der Liste ändern (was ist initialisiert auf die Standardgröße von 16) viele Male. Die Größenänderung erfordert das Kopieren des Arrays. Dies kann teuer werden, wenn Sie die Größe oft ändern.

Die zweite Option hat nur eine Liste, und da die Größenanpassung normalerweise die Kapazität verdoppelt, sollte sie sich weniger skalieren lassen als die erste Option.

Dies geht jedoch in Mikrooptimierungen über. Ich würde mich über so etwas nicht sorgen, es sei denn, Sie bemerken ein Performance-Problem und haben eine Analyse durchgeführt, um festzustellen, dass dies ein Engpass ist.

Wenn Sie sich Sorgen um den Methodennamen machen, denke ich, dass Sie das Wort "get" im Namen haben, weil Sie normalerweise etwas zurückgeben. Benenne es so etwas wie addBrandOfCarsTo() könnte es mehr wie ein Satz lesen:

%Vor%     
dkatzel 14.01.2015, 20:52
quelle
4

Beide Optionen sind gut und hängen hauptsächlich von Ihren Vorlieben ab:

  • einige Leute bevorzugen Klarheit (und jedes Volk hat seinen eigenen Stil).
  • andere bevorzugen die Vorform, wie klein sie auch sein mag.

In diesem Fall könntest du auch direkt zu retrieveCarsByBrand aufrufen und das Ergebnis verwenden:

%Vor%

Oder vereinfachen Sie getCarsBySingleBrand und verwenden Sie das Ergebnis:

%Vor%

oder machen Sie einen Kompromiss zwischen Klarheit und Leistung, indem Sie den Namen von getCarsBySingleBrand ändern:

%Vor%     
Narkha 14.01.2015 20:54
quelle
1

Ich denke du kannst beide Welten benutzen. Der einzige Vorteil in der zweiten ist, dass es weniger Speicher verbraucht. Wenn Sie eine funktionale Methode statt einer ungültigen Methode erstellen, wird die Klarheit verbessert, wie bereits erwähnt, und Sie werden beim Komponententest helfen (Sie können sich über den zurückgegebenen Wert lustig machen). Hier ist, wie ich es tun würde:

%Vor%     
Marcelo Ribeiro 15.01.2015 12:08
quelle
0

Er ist vielleicht richtig.

Lassen Sie uns WARUM erklären.

Im ersten Beispiel für jede Marke erstellen Sie eine neue Liste in der Methode getCarsBySingleBrand . Dann müssen Sie Autos aus der neu erstellten Liste in der Ergebnisliste hinzufügen, die sich in getCarsByBrands .

%Vor%

In dieser Zeile erhalten Sie nur eine Liste von getCarsBySingleBrand und fügen alle diese Elemente hinzu.

Aber im zweiten Fall fügen Sie Autos direkt zu getCarsByBrands Liste hinzu, damit Sie weniger Operationen ausführen.

Es ist auch richtig zu sagen, dass das erste Beispiel etwas mehr Speicher verbraucht. Aber ich denke, mehr Problem hier ist nur Operationen, keine Erinnerung.

Fazit :

Meiner Meinung nach ist die zweite Methode nicht wirklich ein schlechter Stil. Sie können also solche Optimierungen vornehmen, wenn sie benötigt werden.

    
Ioane Sharvadze 14.01.2015 20:44
quelle
0

Wie @dkatzel sagte, könnte die zweite Option besser sein. Aber das liegt nur daran, dass Sie in der ersten Option in der Methode getCarsBySingleBrand(Brand brand) unnötigerweise retrieveCarsByBrand(brand) result in ein neues neues ArrayList kopieren. Dies bedeutet, dass 3 verschiedene Listen existieren, bevor die Methode getCarsBySingleBrand(Brand brand) zurückgibt:

  • Derjenige, der das Endergebnis enthält
  • Die Unterliste mit den Autos einer einzelnen Marke, zurückgegeben von retrieveCarsByBrand(brand)
  • Das neue ArrayList , das Sie verwenden, um die von retrieveCarsByBrand(brand) zurückgegebene Liste zu kopieren

Wenn Sie, wie von @Narkha vorgeschlagen, in der ersten Option die Methode getCarsBySingleBrand(brand) vereinfacht haben, indem Sie die von retrieveCarsByBrand(brand) zurückgegebene Liste der Autos nicht in eine neue ArrayList kopiert haben, oder indem Sie nur retrieveCarsByBrand(brand) method inline eingefügt haben Dann wären beide Optionen in Bezug auf den Speicherverbrauch gleich . Dies liegt daran, dass in beiden Ansätzen die Liste der für eine einzelne Marke abgerufenen Fahrzeuge in die Liste kopiert wird, die das Endergebnis einmal pro Marke enthält. Dies bedeutet, dass nur 2 Listen gleichzeitig existieren:

  • Derjenige, der das Endergebnis enthält
  • Die Unterliste mit den Autos einer einzelnen Marke, zurückgegeben von retrieveCarsByBrand(brand)

Wie von anderen gesagt, wird diese Art von Optimierung kaum jemals benötigt. Sie sollten jedoch wissen, dass es eine bessere Möglichkeit gibt, dies zu tun, wenn Sie Guava verwenden (Sie sollten das tun!) .

%Vor%

Diese Lösung speichert eine Liste von Unterlisten von Autos, wobei jede Unterliste die Autos jeder Marke enthält, und am Ende die Liste der Unterlisten von Autos in ein einziges Prozent der Autos dekoriert. Wenn Sie wirklich, Iterable anstelle von List zurückgeben müssen, können Sie die letzte Zeile wie folgt ändern:

%Vor%

Das Schlüsselwort hier ist dekoriert , was bedeutet, dass keine tatsächliche Kopie einer Unterliste ausgeführt wird. Stattdessen wird ein spezieller Iterator erzeugt, der jedes Element der ersten Unterliste durchläuft und am Ende automatisch und transparent zum ersten Element der zweiten Unterliste "springt", bis es sein Ende erreicht und so weiter an, bis es das letzte Element der letzten Unterliste erreicht. Weitere Informationen finden Sie in Guavas Iterables.concat (...) Methodendokumentation für weitere Details.

    
quelle

Tags und Links