Basicamente, o uso de um loop para iterar sobre a ArrayList
é a única opção:
NÃO use esse código, continue lendo na parte inferior desta resposta para ver por que não é desejável e qual código deve ser usado:
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);
De fato, uma concatenação de strings será ótima, pois o javac
compilador otimizará a concatenação de strings como uma série de append
operações StringBuilder
. Aqui está uma parte da desmontagem do bytecode do for
loop do programa acima:
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;
Como pode ser visto, o compilador otimiza esse loop usando a StringBuilder
, portanto, o desempenho não deve ser uma grande preocupação.
(OK, à segunda vista, ele StringBuilder
está sendo instanciado em cada iteração do loop, portanto, pode não ser o bytecode mais eficiente. Instanciar e usar um explícito StringBuilder
provavelmente produziriam melhor desempenho.)
Na verdade, acho que ter qualquer tipo de saída (seja em disco ou na tela) será pelo menos uma ordem de magnitude mais lenta do que ter que se preocupar com o desempenho de concatenações de strings.
Edit: Como apontado nos comentários, a otimização do compilador acima está de fato criando uma nova instância StringBuilder
em cada iteração. (O que observei anteriormente.)
A técnica mais otimizada a ser usada será a resposta de Paul Tomblin , pois apenas instancia um único StringBuilder
objeto fora do for
loop.
Reescrevendo o código acima para:
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());
Instanciará apenas StringBuilder
uma vez fora do loop e fará apenas as duas chamadas para o append
método dentro do loop, conforme evidenciado neste bytecode (que mostra a instanciação StringBuilder
e o loop):
// 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
Portanto, a otimização manual deve ter um desempenho melhor, pois o interior do for
loop é mais curto e não é necessário instanciar um StringBuilder
em cada iteração.