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 javaccompilador otimizará a concatenação de strings como uma série de appendoperações StringBuilder. Aqui está uma parte da desmontagem do bytecode do forloop 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 StringBuilderestá sendo instanciado em cada iteração do loop, portanto, pode não ser o bytecode mais eficiente. Instanciar e usar um explícito StringBuilderprovavelmente 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 StringBuilderem 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 StringBuilderobjeto fora do forloop.
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 StringBuilderuma vez fora do loop e fará apenas as duas chamadas para o appendmétodo dentro do loop, conforme evidenciado neste bytecode (que mostra a instanciação StringBuildere 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 forloop é mais curto e não é necessário instanciar um StringBuilderem cada iteração.