1. Array do tipo String
E, em poucas palavras, vamos falar sobre o array do tipo String.
Como já dissemos, um array pode ser de qualquer tipo. Isso significa que podemos criar um array do tipo String. Veja como seria o código se precisássemos escrever um programa que “lê do teclado 10 linhas e as imprime na tela em ordem inversa”.
String[] array = new String[10]; // Criamos um objeto-array com 10 elementos
for (int i = 0; i < 10; i++) // Laço de 0 a 9
{
array[i] = console.nextLine(); // Lemos uma linha do teclado e a salvamos na célula do array
}
for (int i = 9; i >= 0; i--) // Laço de 9 até 0
{
System.out.println(array[i]); // Imprimimos na tela o próximo elemento do array
}
O código praticamente não mudou! Só foi preciso trocar o tipo int por String ao criar o array. No resto, é tudo igual!
Conhecendo o null
Eis um enigma — o que há nas células de cada um desses arrays logo após a criação?
int[] numbers = new int[10];
String[] strings = new String[10];
User[] users = new User[10];
Pensando bem, é bem provável que as posições de numbers contenham 0. Correto.
Então, pela mesma lógica, as posições de strings deveriam estar preenchidas com strings vazias — "". Vamos supor.
E com o que estão preenchidas as posições do array users? Com User vazios?
Aí é que está o truque: nem todo tipo de dado tem um “valor padrão”. Por isso, os criadores do Java inventaram uma constante especial — null. null é uma referência vazia. Quando se cria uma variável de um tipo de objeto, seu valor inicial é null: referência para lugar nenhum, ausência de referência.
String name; // name contém null
name = "Alex"; // name contém uma referência ao objeto/string "Alex"
name = null; // name contém null
Trabalhando com null
Não se pode chamar métodos em um objeto se a referência para ele é null — o objeto simplesmente não existe! Neste código, o programa terminará com erro:
String name; // name contém null
String upperName = name.toUpperCase(); // Vai ocorrer NullPointerException: name == null
Quanto ao nosso “enigma”, a resposta é a seguinte:
int[] numbers = new int[10]; // {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
String[] strings = new String[10]; // {null, null, null, null, null, null, null, null, null, null}
User[] users = new User[10]; // {null, null, null, null, null, null, null, null, null, null}
Apenas os tipos primitivos têm “valor padrão”. Todos os demais tipos, por padrão, têm o valor null. O valor inicial de String não é uma string vazia. É assim que é.
2. Array do tipo String na memória
Figura 1. Como um objeto String é disposto na memória:

Observe que o texto da string não é armazenado diretamente na variável: para ele é alocado um bloco de memória separado. E na variável do tipo String é armazenado o endereço (referência) para o objeto com o texto.
Figura 2. Como um array de inteiros é disposto na memória:

Você também já viu esta figura.
Figura 3. Como um array de strings é disposto na memória:

À esquerda vemos a variável-array do tipo String[] (guarda o endereço do objeto-array).
No meio — o objeto-array do tipo String.
E à direita — os objetos string, que armazenam alguns textos.
Nas posições do objeto-array do tipo String não ficam as próprias strings (textos), mas sim seus endereços (referências). Exatamente como nas variáveis do tipo String ficam os endereços das strings (do texto).
3. Inicialização rápida de arrays em Java
Arrays são muito úteis, por isso os desenvolvedores do Java tentaram tornar o trabalho com eles o mais conveniente possível. E a primeira coisa que fizeram foi simplificar a inicialização do array, o preenchimento com valores iniciais.
Muitas vezes, além dos dados que o programa lê de algum lugar, ele também precisa de dados internos próprios. Por exemplo, precisamos armazenar em um array os números de dias de todos os meses. Como esse código pode ficar:
int[] months = new int[12];
months[0] = 31; // janeiro
months[1] = 28; // fevereiro
months[2] = 31; // março
months[3] = 30; // abril
months[4] = 31; // maio
months[5] = 30; // junho
months[6] = 31; // julho
months[7] = 31; // agosto
months[8] = 30; // setembro
months[9] = 31; // outubro
months[10] = 30; // novembro
months[11] = 31; // dezembro
Mas há um modo mais curto de escrever — obrigado aos criadores do Java:
// número de dias dos meses do ano
int[] months = new int[] { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
Você pode simplesmente listar, separados por vírgula, todos os valores do array!
Acontece que o compilador pode determinar o tipo do container (objeto-array) com base no tipo da variável-array. E para determinar o comprimento do array — basta contar a quantidade de elementos escritos entre chaves.
Por isso, dá para escrever esse código de forma ainda mais curta:
// número de dias dos meses do ano
int[] months = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
Não é bonito? 🙂 Esse tipo de escrita se chama “inicialização rápida do array”. E, aliás, funciona não só para o tipo int...
// nomes dos meses do ano
String[] months = { "Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro" };
4. Laço for-each
Percorrer todos os elementos de um array é uma operação tão comum que foi criado um laço especial para isso — for-each. Ele é escrito assim:
for (int score : scores)
{
System.out.println("Pontos: " + score);
}
Aqui o laço percorre os elementos sozinho — sem índice manual. Mas não é possível alterar os elementos diretamente (a variável do laço guarda apenas uma cópia do valor); por outro lado, é muito prático apenas “percorrer” o array.
O compilador transforma o código do laço for-each no código abaixo:
for (int i = 0; i < scores.length; i++)
{
int score = scores[i];
System.out.println("Pontos: " + score);
}
Nada de magia. Agora também fica claro por que você não pode alterar os elementos do array por meio da variável score.
Vamos escrever mais um exemplo: vamos encontrar a soma de todos os pontos.
int sum = 0;
for (int score : scores)
{
sum += score;
}
System.out.println("Soma de todos os pontos: " + sum);
Quando usar qual laço?
- Se precisar de índice ou for necessário alterar elementos — use o laço for.
- Se for apenas para percorrer os valores — for-each é mais rápido e limpo.
5. Alterando elementos do array
E se precisarmos aumentar cada nota em 1 ponto (por exemplo, por bom comportamento)? Aqui é necessário o for clássico com índice, pois só assim podemos modificar os valores no array.
Exemplo: aumentar cada elemento em 1
for (int i = 0; i < grades.length; i++) {
grades[i] = grades[i] + 1;
}
Após a execução desse código, o array grades terá novos valores.
Por que não dá para fazer isso com for-each?
for (int grade : grades) {
grade = grade + 1; // Não funciona!
}
Esse código não altera o array, porque grade é uma cópia do valor do array, e não uma referência ao próprio elemento.
6. Cálculos com base em um array
Arrays são usados com frequência para cálculos: soma, média, máximo, mínimo e assim por diante.
Exemplo: soma de todos os elementos do array
int sum = 0;
for (int i = 0; i < grades.length; i++) {
sum += grades[i]; // o mesmo que sum = sum + grades[i];
}
System.out.println("Soma das notas: " + sum);
Exemplo: busca do valor máximo
int max = grades[0]; // comece pelo primeiro elemento
for (int i = 1; i < grades.length; i++) {
if (grades[i] > max) {
max = grades[i];
}
}
System.out.println("Nota máxima: " + max);
Exemplo: busca do valor mínimo
int min = grades[0]; // comece pelo primeiro elemento
for (int i = 1; i < grades.length; i++) {
if (grades[i] < min) {
min = grades[i];
}
}
System.out.println("Nota mínima: " + min);
Exemplo: cálculo da média aritmética
int sum = 0;
for (int i = 0; i < grades.length; i++) {
sum += grades[i];
}
double average = (double) sum / grades.length; // é obrigatório fazer cast para double!
System.out.println("Média das notas: " + average);
Atenção: para obter um número fracionário em vez de inteiro, é preciso converter explicitamente a soma para double antes da divisão.
7. Tarefas práticas
Leitura de um array pelo teclado
Muitas vezes é preciso preencher um array com valores informados pelo usuário. Para isso, usamos a classe Scanner e um laço.
Scanner console = new Scanner(System.in);
int n = 5; // tamanho do array
int[] numbers = new int[n];
System.out.println("Digite " + n + " números:");
for (int i = 0; i < n; i++) {
numbers[i] = console.nextInt();
}
System.out.println("Você digitou:");
for (int i = 0; i < n; i++) {
System.out.println(numbers[i]);
}
Impressão do array em ordem inversa
Às vezes é preciso imprimir os elementos do array do fim para o começo (por exemplo, para saber quem entrou por último na sala).
for (int i = grades.length - 1; i >= 0; i--) {
System.out.println("Nota nº " + (i + 1) + ": " + grades[i]);
}
8. Erros típicos ao trabalhar com arrays unidimensionais
Erro nº 1: acesso fora dos limites do array
O problema mais comum é tentar acessar um elemento inexistente. Em Java, isso leva à exceção ArrayIndexOutOfBoundsException. Lembre-se: o último índice válido é arr.length - 1.
int[] arr = new int[5];
System.out.println(arr[5]); // Erro! Índices de 0 a 4.
Erro nº 2: esquecer de inicializar o array
Declarou a variável, mas não criou o array:
int[] arr;
arr[0] = 5; // Erro! O array não foi criado.
É obrigatório criar o array com new:
arr = new int[10];
Erro nº 3: tentar alterar elementos do array via for-each
No laço for-each, a variável é uma cópia do valor, não uma referência ao elemento:
for (int x : arr) {
x = 100; // Não altera o array!
}
Para alterar valores, use um for com índice.
Erro nº 4: uso incorreto do comprimento do array
Às vezes se confunde o comprimento do array com o último índice:
for (int i = 0; i <= arr.length; i++) { // Erro! Deve ser i < arr.length
// ...
}
Esse código levará a acesso fora dos limites.
Erro nº 5: conversão de tipos implícita
Se o array é do tipo int, não é possível atribuir diretamente um valor do tipo double:
int[] arr = new int[3];
arr[0] = 3.14; // Erro! 3.14 é double.
GO TO FULL VERSION