352 Stimmen

Der beste Weg, um eine ArrayList in eine Zeichenkette zu konvertieren

Ich habe eine ArrayList die ich vollständig als String ausgeben möchte. Im Wesentlichen möchte ich sie in der Reihenfolge ausgeben, in der die toString der einzelnen Elemente durch Tabulatoren getrennt. Gibt es eine schnelle Möglichkeit, dies zu tun? Sie könnten Schleife durch sie (oder entfernen Sie jedes Element) und verketten es zu einem String, aber ich denke, dies wird sehr langsam sein.

1191voto

Vitalii Fedorenko Punkte 103468

In Java 8 oder höher:

String listString = String.join(", ", list);

Für den Fall, dass die list nicht vom Typ String ist, kann ein Verbindungssammler verwendet werden:

String listString = list.stream().map(Object::toString)
                        .collect(Collectors.joining(", "));

426voto

JJ Geewax Punkte 9847

Wenn Sie dies auf Android tun, gibt es ein nettes Dienstprogramm für diese Aufgabe namens TextUtils die eine .join(String delimiter, Iterable) Methode.

List<String> list = new ArrayList<String>();
list.add("Item 1");
list.add("Item 2");
String joined = TextUtils.join(", ", list);

Offensichtlich nicht viel Verwendung außerhalb von Android, aber dachte, ich würde es zu diesem Thread hinzufügen...

382voto

coobird Punkte 155882

Java 8 führt eine String.join(separator, list) Methode; siehe Vitalii Federenko's Antwort .

Vor Java 8 wurde eine Schleife zur Iteration über die ArrayList war die einzige Möglichkeit:

Verwenden Sie diesen Code NICHT, lesen Sie weiter bis zum Ende dieser Antwort, um zu erfahren, warum er nicht erwünscht ist und welcher Code stattdessen verwendet werden sollte:

ArrayList<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");

String listString = "";

for (String s : list)
{
    listString += s + "\t";
}

System.out.println(listString);

Tatsächlich ist eine String-Verkettung genau richtig, da die javac Compiler optimiert die String-Verkettung als eine Reihe von append Operationen auf einer StringBuilder sowieso. Hier ist ein Teil der Disassemblierung des Bytecodes aus dem for Schleife aus dem obigen Programm:

   61:  new #13; //class java/lang/StringBuilder
   64:  dup
   65:  invokespecial   #14; //Method java/lang/StringBuilder."<init>":()V
   68:  aload_2
   69:  invokevirtual   #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   72:  aload   4
   74:  invokevirtual   #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   77:  ldc #16; //String \t
   79:  invokevirtual   #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   82:  invokevirtual   #17; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;

Wie man sieht, optimiert der Compiler diese Schleife durch die Verwendung einer StringBuilder Die Leistung sollte also kein großes Problem darstellen.

(OK, auf den zweiten Blick ist die StringBuilder wird bei jeder Iteration der Schleife instanziiert, so dass es sich möglicherweise nicht um den effizientesten Bytecode handelt. Die Instanziierung und Verwendung einer expliziten StringBuilder würde wahrscheinlich eine bessere Leistung bringen).

Ich denke, dass jede Art von Ausgabe (sei es auf die Festplatte oder auf den Bildschirm) mindestens um eine Größenordnung langsamer ist, als wenn man sich um die Leistung von String-Verkettungen kümmern muss.

Edita: Wie in den Kommentaren erwähnt, erzeugt die obige Compiler-Optimierung tatsächlich eine neue Instanz von StringBuilder bei jeder Iteration. (Was ich schon früher festgestellt habe.)

Die optimalste Technik ist die Antwort von Paul Tomblin da es nur eine einzige Instanzierung StringBuilder Objekts außerhalb der for Schleife.

Umschreiben des obigen Codes in:

ArrayList<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");

StringBuilder sb = new StringBuilder();
for (String s : list)
{
    sb.append(s);
    sb.append("\t");
}

System.out.println(sb.toString());

instanziiert nur die StringBuilder einmal außerhalb der Schleife und führen nur die beiden Aufrufe an die append Methode innerhalb der Schleife, wie in diesem Bytecode zu sehen ist (der die Instanziierung von StringBuilder und die Schleife):

   // Instantiation of the StringBuilder outside loop:
   33:  new #8; //class java/lang/StringBuilder
   36:  dup
   37:  invokespecial   #9; //Method java/lang/StringBuilder."<init>":()V
   40:  astore_2

   // [snip a few lines for initializing the loop]
   // Loading the StringBuilder inside the loop, then append:
   66:  aload_2
   67:  aload   4
   69:  invokevirtual   #14; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   72:  pop
   73:  aload_2
   74:  ldc #15; //String \t
   76:  invokevirtual   #14; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   79:  pop

Die Handoptimierung sollte also in der Tat besser funktionieren, da das Innere des for Schleife ist kürzer und es besteht keine Notwendigkeit, eine StringBuilder bei jeder Iteration.

256voto

Ravi Wallau Punkte 10137

Laden Sie die Apache Commons Lang herunter und verwenden Sie die Methode

 StringUtils.join(list)

 StringUtils.join(list, ", ") // 2nd param is the separator.

Sie können es natürlich auch selbst implementieren, aber ihr Code ist vollständig getestet und stellt wahrscheinlich die bestmögliche Implementierung dar.

Ich bin ein großer Fan der Apache-Commons-Bibliothek und halte sie für eine großartige Ergänzung der Java-Standardbibliothek.

141voto

Jon Skeet Punkte 1325502

Dies ist eine ziemlich alte Frage, aber ich denke, ich könnte auch eine modernere Antwort hinzufügen - verwenden Sie die Joiner Klasse von Guave :

String joined = Joiner.on("\t").join(list);

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X