2016-06-30 12 views
4

Wie empfiehlt es sich, ein ArrayList-Feld in Java zu initialisieren (um zu vermeiden, dass ein Nullwert getestet wird)?Bewährte Methode zum Initialisieren eines ArrayList-Felds in Java

Auf Erklärung, wie folgt aus:

private List<String> myList = new ArrayList<String>(); 

Oder im Getter, wie folgt aus:

public List<String> getMyList() { 
    if(myList == null) { 
     myList = new ArrayList<String>(); 
    } 
    return myList; 
} 

Oder im Konstruktor:

public Test(){ 
    myList = new ArrayList<String>(); 
} 

Vielleicht ist es das gleiche, aber ich bin neugierig zu wissen.

+1

Der erste. Lazy-Initialisierung wird massiv überbewertet und Thread-Sicherheitsprobleme sind viel wahrscheinlicher. –

+0

@ cricket_007 Ich habe meine Frage für die Konstruktoroption bearbeitet – JavaDev

Antwort

6

Die erste Option ermöglicht es Ihnen, eine

private final List<String> myList = new ArrayList<>(); 

So tun Sie verhindern, dass versehentlich später eine völlig neue Liste zu schaffen; Dies hilft bei (vielen, nicht allen) Multi-Threading-Problemen. Zusätzlich dazu kann der Compiler Ihnen jetzt helfen, sicherzustellen, dass Ihr Feld genau einmal initialisiert wird.

Darüber hinaus kann die zweite Option als "faul Initialisierung" angesehen werden. Und in diesem Sinne: Es kann als "Optimierungswahl" gesehen werden! Und von da an: Viele Menschen setzen sich dafür ein, eine vorzeitige Optimierung zu vermeiden!

Sie wissen, wenn Sie sich nicht darauf verlassen können, dass die Liste bereits erstellt wurde, kann das zu großen Problemen führen. Auch wenn Sie aus dieser Perspektive kommen, haben Sie ein anderes Argument, um Option 1 zu bevorzugen!

Bearbeiten, in Bezug auf die Compiler-Option: von einem Semantikpunkt sind Option 1 und 3 (mehr oder weniger) "gleich" [Hinweis: Wenn Sie feststellen, dass es einen Unterschied in Ihrem Code macht, wenn Sie Option1 oder Option3 wählen. .. das wäre ein guter Hinweis darauf, dass du in deinem Code etwas schrecklich falsch machst).

Dennoch ist die eine Sache, die einen Unterschied machen kann - wenn Sie eine „Dependency Injection“ Konstruktor haben, wie:

public YourClass() { this(new ArrayList<String>); } 
YourClass(List<String> incomingList) { myList = incomingList; } 

Diese Lösung Sinn für diese Art von Objekten macht, die Sie „Kontrolle“ müssen ; im Sinne von: Sie müssen Mocks an Ihre Klasse weitergeben, um Komponententests zu ermöglichen.

Lange Rede kurzer Sinn:

  • option1 Bevorzugen, wenn möglich: final
  • Verwendung option3 verwenden, wenn Dependency Injection erforderlich ist
  • Vermeiden option2, wenn Sie wirklich gute Gründe, es zu gehen
+1

Option 3 ermöglicht auch 'final' –

+0

können Sie erklären, warum für Option 1 final verwenden? – JavaDev

+1

@JavaDev Einfach gesprochen: weil du einfach all die Sachen bekommst, die ich dort kostenlos aufzähle? Entschuldigung, ich bekomme deine Frage nicht: Ich dachte, ich hätte einige Gründe dafür angeführt, warum Option 1 + Finale die "beste Wahl" ist. – GhostCat

0

Das hängt von der Verwendung ab, aber ich bevorzuge die erste Option.

private List<String> myList = new ArrayList<String>();

Die zweite Option kann einige Vorteile haben, wenn Ihre Klasse wird erwartet, dass die Arraylist zu erstellen, wenn der Benutzer der Klasse in der Lage ist, die myList Variable null einzustellen. Das scheint mir aber eine schlechte Übung zu sein.

1

Im Allgemeinen ist die faule Initialisierung im Getter schwieriger als es wert ist. Wenn Sie ein ernstes Problem haben, wo Sie den Speicher durch die Liste verwendet minimieren wollen (weil Sie es erwarten, in den meisten Fällen leer sein), können Sie es mit einer Anfangskapazität von Null initialisieren:

private List<String> myList = new ArrayList<String>(0); 

Es gibt kein praktischer Unterschied zwischen der Initialisierung in der Deklaration der Instanzvariablen und im Konstruktor, außer der Lesbarkeit. Es ist einfacher sicherzustellen, dass alles initialisiert wird, wenn Sie die Initialisierung auf die Instanzdeklaration setzen, wobei der Konstruktor die Initialisierungen im Konstruktor mit den Instanzvariablen vergleichen muss, um sicherzustellen, dass sie abgedeckt sind.

Eine Menge realer Code muss mit Bibliotheken und Frameworks von Drittanbietern arbeiten. Wenn Sie eine Klasse erstellen, die mit einer Bibliothek oder einem Framework wie Hibernate oder Spring arbeiten muss, kommt eine verzögerte Initialisierung im Getter nicht in Frage, entweder weil Spring diese Dinge für Sie übernimmt oder weil die Bibliothek, die Ihre Klasse verwendet, austauscht Ihre List-Implementierung aus verschiedenen Gründen für sich selbst (Hibernate wird dies implementieren, um lazy loading zu implementieren). Machen Sie daher Ihre Getter und Setter so einfach und direkt wie möglich, damit sie nicht die Annahmen außer Kraft setzen, die durch den Code von Drittanbietern, der sie verwendet, gemacht werden.

+0

Warum eine Kapazität von 0 einstellen? Standardmäßig ist eine leere Listengröße 0, oder? – JavaDev

+1

@JavaDev: Standard ist 10. Kapazität ist im Voraus zugewiesenen Speicherplatz, im Gegensatz zu Größe, die die Anzahl der Elemente in der Liste ist. –

Verwandte Themen