Frage Unterschied in diesen beiden Ansatz zum Konvertieren von Sammlung zu Array-Objekt


Was ist der grundlegende Unterschied in diesen beiden folgenden Ansatz für die Umwandlung von Sammlung zu Array-Objekt

 ArrayList<String> iName = new ArrayList<String>();

 String[] array= iName.toArray(new String[iName.size()]);//1
 String[] array= iName.toArray(new String[0]);//2

Wann sollte Ansatz 1 und wann Ansatz 2 verwendet werden?


5
2018-05-18 12:13


Ursprung


Antworten:


Der Unterschied zwischen diesen beiden Ansätzen:

    String[] array = iName.toArray(new String[iName.size()]);
    String[] array = iName.toArray(new String[0]);

ist ganz anders, wenn es eine Möglichkeit gibt, dass die Quellensammlung (iName in diesem Fall) kann gleichzeitig geändert werden. Wenn keine Möglichkeit der Parallelität besteht, ist die erste Zeile vorzuziehen.

Dies trifft in Ihrem Beispiel, in dem sich die Quellensammlung befindet, nicht genau zu ArrayList, die nicht threadsicher ist. Wenn es sich bei der Quellensammlung jedoch um eine gleichzeitige Sammlung handelt, ist das Verhalten unter gleichzeitiger Änderung erheblich. In diesem Fall hat die erste Zeile eine Racebedingung. Der aufrufende Thread erhält zuerst die Größe; Ein anderer Thread könnte dann ein Element hinzufügen oder entfernen und seine Größe ändern. Aber dann weist der aufrufende Thread dem Array den Namen zu alt Größe und übergibt es an toArray.

Dies führt nicht zu einem Fehler. Die Fälle sind gut definiert, wenn Sie die Spezifikation von lesen Collection.toArray(T[]) vorsichtig. Wenn die Sammlung gewachsen wäre, würde ihr ein neues Array zugewiesen, wodurch die Array-Zuweisung des Anrufers überflüssig wird. Wenn die Sammlung geschrumpft wäre, würde das Ende des Arrays mit Nullelementen enden. Dies ist nicht notwendigerweise ein Fehler, aber jeder Code, der das resultierende Array konsumiert, muss bereit sein, Nullen zu behandeln, was unangenehm sein kann.

Durch die Übergabe eines Arrays der Länge Null werden diese Probleme vermieden, und zwar zu den möglichen Kosten der Zuweisung eines nutzlosen Arrays nullter Länge. (Man könnte eine zwischengespeicherte Version behalten, aber es fügt Unordnung hinzu.) Wenn die Sammlung leer ist, wird das Array der Länge Null einfach zurückgegeben. Wenn die Sammlung jedoch Elemente enthält, weist die Sammlung selbst das Array der richtigen Größe zu und füllt es. Dies vermeidet die Wettlaufsituation des Anrufers, der ein Array der "falschen" Größe eingibt.

In der Java 8-Streams-API ist die Stream.toArray Methode vermeidet dieses Problem, indem der Anrufer in einer Array-Factory übergeben wird. Auf diese Weise kann der Aufrufer den Typ angeben, die Sammlung kann jedoch die richtige Größe angeben. Dies wurde noch nicht nachgerüstet Collections obwohl. Dies wird durch eine RFE abgedeckt JDK-8060192.


2
2018-05-18 17:50



Der erste Ansatz ist besser, da Sie ein Array erstellen und toArray verwendet es, um die Elemente der Eingabeliste zu speichern. Der zweite Ansatz führt zu toArray Erstellen eines anderen Arrays, da es nichts in einem leeren Array speichern kann.

Sie werden auf ein anderes Verhalten stoßen, wenn Sie der Methode ein Array übergeben, dessen Länge größer ist als die Größe der Eingabeliste, da in diesem Fall die size's Element des Arrays (wo size ist die Größe der Eingabeliste) wird mit Null belegt.

Die einzige Zeit, die es sinnvoll wäre, ein Array, das kleiner als die Größe der Liste ist, an die Methode zu übergeben, ist, wenn Sie das Array beim Aufruf der Methode nicht instanziieren, sondern ein bereits bestehendes Array verwenden:

array = iName.toArray(array);

Hier wissen Sie nicht im Voraus, ob arraywird groß genug sein, um die Elemente von iName. Wenn nicht, toArray wird ein neues Array zurückgeben. Wenn es ist, toArray gibt das Eingabearray zurück.


4
2018-05-18 12:15



Wenn Sie sich die Implementierung ansehen, können Sie den Unterschied verstehen:

public <T> T[] toArray(T[] a) {
        if (a.length < size)
            // Make a new array of a's runtime type, but my contents:
            return (T[]) Arrays.copyOf(elementData, size, a.getClass());
        System.arraycopy(elementData, 0, a, 0, size);
        if (a.length > size)
            a[size] = null;
        return a;
    }

Wenn Sie ein Array angeben, das kleiner als die ArrayList ist, wird ein neues Array erstellt. Wenn das angegebene Array größer als die ArrayList ist, wird es zum Kopieren des Inhalts des Backing-Arrays der Liste verwendet.

In Bezug auf die Leistung wäre die beste Vorgehensweise die Verwendung des ersten Ansatzes (iName.toArray(new String[iName.size()])), aber die Strafe für den zweiten Ansatz ist nicht groß (ein 0-dimensioniertes Array wird erstellt).

Ich persönlich benutze den zweiten Ansatz, da ich denke, dass es den Code lesbarer macht.


0
2018-05-18 12:49



Grundsätzlich machen beide Ansätze das gleiche und produzieren identische Outputs, aber unter der Haube verhalten sie sich ein wenig anders.

Bei der ersten Annäherung, da die Größe des Arrays groß genug ist, kann List seine Elemente in das Array kopieren und das gleiche zurückgeben. Wenn Sie den zweiten Ansatz verwenden, entspricht die List-Klasse fast genau Ihrem ersten Ansatz: Erstellen Sie ein neues Array mit der richtigen Größe, um die Werte zu kopieren.

Aus der Effizienzperspektive: Beim ersten Ansatz wird ein Array erstellt und nicht verwendet, was nicht gut ist, selbst wenn das Erstellen eines Arrays nicht viel Zeit oder Verarbeitungsleistung benötigt, ist es redundant und sollte nicht ausgeführt werden. Wenn Sie die Größe der Liste kennen, wissen alle Sammlungen ihre Größe, sollten Sie den ersten Ansatz verwenden.


0
2018-05-18 12:43