Zasadniczo użycie pętli do iteracji ArrayList
jest jedyną opcją:
NIE używaj tego kodu, kontynuuj czytanie na dole tej odpowiedzi, aby zobaczyć, dlaczego nie jest pożądane, i który kod należy zastosować zamiast tego:
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);
W rzeczywistości konkatenacja łańcuchów będzie w porządku, ponieważ javac
kompilator zoptymalizuje konkatenację łańcuchów jako serię append
operacji StringBuilder
. Oto część demontażu kodu bajtowego z for
pętli z powyższego programu:
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;
Jak widać, kompilator optymalizuje tę pętlę za pomocą a StringBuilder
, więc wydajność nie powinna być dużym problemem.
(OK, na drugi rzut oka StringBuilder
instancja jest tworzona przy każdej iteracji pętli, więc może nie być najbardziej wydajnym kodem bajtowym. Tworzenie instancji i używanie jawnego StringBuilder
prawdopodobnie poprawiłoby wydajność.)
W rzeczywistości myślę, że posiadanie jakiegokolwiek wyjścia (czy to na dysk, czy na ekran) będzie co najmniej o rząd wielkości wolniejsze niż martwienie się o wydajność konkatenacji łańcuchów.
Edycja: Jak wskazano w komentarzach, powyższa optymalizacja kompilatora rzeczywiście tworzy nowe wystąpienie StringBuilder
każdej iteracji. (Które zauważyłem wcześniej.)
Najbardziej zoptymalizowaną techniką do zastosowania będzie odpowiedź Paula Tomblina , ponieważ tworzy ona tylko pojedynczy StringBuilder
obiekt poza for
pętlą.
Przepisanie powyższego kodu do:
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());
Utworzy tylko StringBuilder
jedną instancję poza pętlą i wykona tylko dwa wywołania append
metody wewnątrz pętli, jak pokazano w tym kodzie bajtowym (który pokazuje instancję StringBuilder
i pętlę):
// 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
Rzeczywiście, optymalizacja ręki powinna być lepsza, ponieważ wnętrze for
pętli jest krótsze i nie ma potrzeby tworzenia wystąpienia StringBuilder
przy każdej iteracji.