ArrayList<String> para String[]: não se deixe enganar
\n\nOlá, amigo! Se você está lendo isto, significa que já se deparou com a tarefa clássica — transformar um ArrayList<String> em um array comum String[]. Parece simples, não é? Você pega o método toArray(), chama e pronto. Mas não é bem assim! Java é uma linguagem traiçoeira, e até mesmo uma operação tão simples pode se tornar uma dor de cabeça se você não conhecer as armadilhas.
No Stack Overflow, essa pergunta tem milhares de visualizações, e não é à toa. Reunimos os 5 principais erros que até mesmo desenvolvedores experientes cometem e mostraremos como evitá-los. Vamos lá!
\n\nPor que simplesmente list.toArray() não funciona?
\n\nVamos direto ao ponto. Você tem uma lista:
\n\nArrayList<String> list = new ArrayList<>();\nlist.add("Java");\nlist.add("Python");\nlist.add("C++");\n\nVocê quer obter um array de strings. O primeiro pensamento é chamar list.toArray(). Veja o que acontece:
Object[] objectArray = list.toArray(); // Funciona, mas retorna Object[]\n// String[] stringArray = list.toArray(); // Erro de compilação!\n\nErro nº 1: esquecer a conversão de tipos. O método toArray() sem argumentos retorna Object[], não String[]. O compilador não permitirá que você simplesmente atribua um Object[] a uma variável do tipo String[]. É necessário um cast explícito:
String[] stringArray = (String[]) list.toArray(); // ClassCastException em tempo de execução!\n\nÉ aqui que a coisa fica interessante. O segundo erro é pensar que o cast vai resolver. Você receberá um ClassCastException, porque internamente o toArray() cria um array do tipo Object[], não String[]. O cast não altera o tipo do objeto — ele apenas diz ao compilador: "Confie em mim, é uma string". E o Java, em tempo de execução, verifica e lança a exceção.
O caminho correto: toArray(new String[0])
\n\nA maneira mais comum e correta é passar um array vazio do tipo desejado para o toArray():
String[] stringArray = list.toArray(new String[0]);\n\nPor que isso funciona? Porque o método toArray(T[] a) é um método genérico. Ele recebe um array do tipo T e retorna um array do mesmo tipo. Se o array passado não for grande o suficiente, o método cria um novo array do tipo correto usando reflexão. Se o tamanho for adequado, ele o preenche.
Erro nº 3: passar um array de tamanho incorreto. Alguns iniciantes escrevem:
\n\nString[] stringArray = list.toArray(new String[list.size()]);\n\nIsso também funciona, mas vamos analisar o que é melhor. Quando passamos um array de tamanho list.size(), o método o preenche e o retorna. Se passarmos new String[0], um novo array é criado. Parece que estamos perdendo tempo criando um novo array, certo? Na verdade, a JVM otimiza a criação de um array vazio, e na maioria dos casos new String[0] é mais rápido do que new String[list.size()]. Por quê? Porque no segundo caso, o array é criado, depois preenchido com nulls e, em seguida, sobrescrito. Trabalho extra.
JVM modernas (Java 8+) frequentemente otimizam new String[0] para uma constante, tornando-o mais rápido. Mas se você estiver trabalhando com Java 6 ou 7, a diferença pode ser perceptível. De qualquer forma, a melhor prática é usar new String[0], a menos que seja necessária performance ultra-alta. Para trechos de código críticos em velocidade, teste ambas as opções.
A armadilha: sincronização e concorrência
\n\nErro nº 4: conversão em ambiente multithread sem sincronização. Imagine: você tem um ArrayL