Java Percorrer Arrays
Um array só mostra o seu valor quando você passa por ele, elemento por elemento: para mostrar, somar, achar a maior nota, procurar um nome. Isso se chama percorrer (ou iterar sobre) o array. Nesta aula você aprende as receitas clássicas, todas com as notas da turma da professora Ana. São padrões que você vai usar a vida toda, em qualquer linguagem.
- As duas formas de percorrer (
forcom índice e for-each) e quando usar cada uma. - Somar e tirar a média, sem cair na divisão inteira.
- Achar o maior e o menor (e a posição deles).
- Contar quantos elementos passam num teste.
- Buscar um valor e saber se ele existe.
- Percorrer de trás para frente e inverter o array.
- Preencher um array com um laço e usar dois arrays "paralelos" (nomes e notas).
Os exemplos rodam no terminal da Ana (máquina fictícia notebook, pasta ~/java, JDK 25) com java Main.java. Esta aula junta duas anteriores: Arrays e os laços for e for-each.
As duas formas de percorrer
Quase todos os exemplos usam o mesmo array, as notas de 5 alunos:
int[] notas = {7, 9, 5, 10, 6};
1. for com índice
O contador i anda pelos índices, de 0 até length - 1, e notas[i] é o elemento da vez:
public class Main {
public static void main(String[] args) {
int[] notas = {7, 9, 5, 10, 6};
for (int i = 0; i < notas.length; i++) {
System.out.println("Aluno " + (i + 1) + ": nota " + notas[i]);
}
}
}
$ java Main.java Aluno 1: nota 7 Aluno 2: nota 9 Aluno 3: nota 5 Aluno 4: nota 10 Aluno 5: nota 6
- int i = 0;
- Começa no primeiro índice, que é 0.
- i < notas.length;
- Continua enquanto
ifor um índice válido. Com 5 notas, para quandoichega a 5. É<, e nunca<=. - i++
- Próximo índice.
- notas[i]
- O elemento na posição
i. - (i + 1)
- Para gente, o primeiro aluno é o "1", não o "0". Somamos 1 só na hora de mostrar.
2. for-each
Quando a posição não importa, o for-each entrega cada valor direto, sem índice:
public class Main {
public static void main(String[] args) {
int[] notas = {7, 9, 5, 10, 6};
for (int nota : notas) {
System.out.print(nota + " ");
}
System.out.println();
}
}
$ java Main.java 7 9 5 10 6
| Preciso… | Use |
|---|---|
| Só ler os valores (somar, contar, achar o maior) | for-each: mais curto, sem risco de errar o índice |
| Saber a posição (mostrar "Aluno 3", achar onde está o maior) | for com índice |
| Mudar os valores do array | for com índice (no for-each a variável é uma cópia; veja for-each) |
| Ir de trás para frente, pular, ou usar dois arrays juntos | for com índice |
Mostrar com vírgulas, sem a última sobrando
Um detalhe que aparece em todo lugar: mostrar 7, 9, 5, 10, 6 sem uma vírgula no fim. A vírgula só vai se não for o último, e para saber isso precisamos do índice:
public class Main {
public static void main(String[] args) {
int[] notas = {7, 9, 5, 10, 6};
for (int i = 0; i < notas.length; i++) {
System.out.print(notas[i]);
if (i < notas.length - 1) {
System.out.print(", ");
}
}
System.out.println();
}
}
$ java Main.java 7, 9, 5, 10, 6
(Se for só para conferir o conteúdo, Arrays.toString(notas) já faz isso, com colchetes: veja A Classe Arrays.)
Somar e tirar a média
O acumulador que você viu em for: começa em zero, antes do laço, e recebe cada elemento:
public class Main {
public static void main(String[] args) {
int[] notas = {7, 9, 5, 10, 6};
int soma = 0;
for (int nota : notas) {
soma += nota;
}
System.out.println("Soma: " + soma);
System.out.println("Média (errada): " + soma / notas.length);
System.out.println("Média: " + (double) soma / notas.length);
}
}
$ java Main.java Soma: 37 Média (errada): 7 « 37 / 5 entre inteiros: o ",4" foi jogado fora Média: 7.4
A soma deu 37, e 37 ÷ 5 = 7,4. Mas a linha "errada" mostrou 7: soma e notas.length são int, e divisão de int por int no Java dá int, cortando as casas decimais (veja Operadores Aritméticos). O (double) na frente da soma a converte em double antes da divisão, e aí o resultado mantém os decimais (veja Conversão de Tipos). Outra saída é já declarar double soma = 0;.
Se o array tiver 0 elementos, a média vira uma divisão por zero: com double, o resultado é NaN ("não é um número"); com int, o programa para com ArithmeticException: / by zero. Num programa de verdade, teste if (notas.length > 0) antes.
Achar o maior e o menor
A ideia: comece achando que o primeiro elemento é o maior (e o menor). Depois passe pelos outros: cada vez que aparecer um maior, ele passa a ser o "campeão".
public class Main {
public static void main(String[] args) {
int[] notas = {7, 9, 5, 10, 6};
int maior = notas[0];
int menor = notas[0];
for (int nota : notas) {
if (nota > maior) {
maior = nota;
}
if (nota < menor) {
menor = nota;
}
}
System.out.println("Maior nota: " + maior);
System.out.println("Menor nota: " + menor);
}
}
$ java Main.java Maior nota: 10 Menor nota: 5
| Nota da vez | É maior que maior? | maior fica | É menor que menor? | menor fica |
|---|---|---|---|---|
| (início) | 7 | 7 | ||
| 7 | não | 7 | não | 7 |
| 9 | sim | 9 | não | 7 |
| 5 | não | 9 | sim | 5 |
| 10 | sim | 10 | não | 5 |
| 6 | não | 10 | não | 5 |
Por que começar com notas[0] e não com 0?
Começar com 0 parece natural e funciona com notas… até o dia em que os números são negativos. As temperaturas de uma semana fria na serra:
public class Main {
public static void main(String[] args) {
int[] temperaturas = {-3, -8, -1, -5};
int maior = 0;
for (int t : temperaturas) {
if (t > maior) {
maior = t;
}
}
System.out.println("Mais quente: " + maior);
}
}
$ java Main.java Mais quente: 0 « 0 nem está no array!
Nenhuma temperatura é maior que 0, então o "campeão" inicial nunca foi trocado. Com int maior = temperaturas[0]; a resposta fica certa:
$ java Main.java Mais quente: -1
Regra: o valor inicial do maior (ou do menor) deve ser um elemento do próprio array.
A posição do maior
Às vezes você quer saber onde está o maior, e não só quanto ele vale. Guarde o índice do campeão em vez do valor; aí o for com índice é obrigatório:
public class Main {
public static void main(String[] args) {
int[] notas = {7, 9, 5, 10, 6};
int posicao = 0;
for (int i = 1; i < notas.length; i++) {
if (notas[i] > notas[posicao]) {
posicao = i;
}
}
System.out.println("Maior nota: " + notas[posicao] + ", no índice " + posicao);
}
}
$ java Main.java Maior nota: 10, no índice 3
O laço começa em i = 1 porque o índice 0 já é o campeão inicial; não precisa comparar ele com ele mesmo.
Contar
Quantos alunos foram aprovados (nota 7 ou mais)? Um contador que só sobe quando o teste passa:
public class Main {
public static void main(String[] args) {
int[] notas = {7, 9, 5, 10, 6};
int aprovados = 0;
for (int nota : notas) {
if (nota >= 7) {
aprovados++;
}
}
System.out.println("Aprovados: " + aprovados + " de " + notas.length);
}
}
$ java Main.java Aprovados: 3 de 5
Missão: mude o programa para contar quantos alunos ficaram em recuperação (nota menor que 7) e mostrar Em recuperação: 2.
public class Main {
public static void main(String[] args) {
int[] notas = {7, 9, 5, 10, 6};
int aprovados = 0;
for (int nota : notas) {
if (nota >= 7) {
aprovados++;
}
}
System.out.println("Aprovados: " + aprovados);
}
}
public class Main {
public static void main(String[] args) {
int[] notas = {7, 9, 5, 10, 6};
int recuperacao = 0;
for (int nota : notas) {
if (nota < 7) {
recuperacao++;
}
}
System.out.println("Em recuperação: " + recuperacao);
}
}
Buscar um valor
A Carla está na turma? E em que posição? A busca percorre o array comparando cada elemento; quando acha, guarda a posição e para com break (veja break e continue). O valor -1, que nunca é um índice válido, significa "não achei":
public class Main {
public static void main(String[] args) {
String[] alunos = {"Ana", "Bruno", "Carla", "Davi", "Eva"};
String procurado = "Carla";
int posicao = -1;
for (int i = 0; i < alunos.length; i++) {
if (alunos[i].equals(procurado)) {
posicao = i;
break;
}
}
if (posicao == -1) {
System.out.println(procurado + " não está na turma");
} else {
System.out.println(procurado + " está no índice " + posicao);
}
}
}
$ java Main.java Carla está no índice 2
Trocando "Carla" por "Fábio", o laço vai até o fim sem achar, e posicao continua -1:
$ java Main.java Fábio não está na turma
Para textos, compare com equals, nunca com == (veja Strings). Esse tipo de busca, que olha um por um, se chama busca linear. Num array ordenado existe uma busca bem mais rápida, a Arrays.binarySearch, em A Classe Arrays.
De trás para frente e inverter
Só mostrar ao contrário
Comece no último índice (length - 1), vá até o 0 e diminua:
public class Main {
public static void main(String[] args) {
int[] notas = {7, 9, 5, 10, 6};
for (int i = notas.length - 1; i >= 0; i--) {
System.out.print(notas[i] + " ");
}
System.out.println();
}
}
$ java Main.java 6 10 5 9 7
Inverter o array de verdade
Para que o próprio array fique invertido, troque o primeiro com o último, o segundo com o penúltimo, e assim por diante, até o meio. Para trocar dois valores, você precisa de uma variável auxiliar, como quem troca o conteúdo de dois copos usando um terceiro copo vazio:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] notas = {7, 9, 5, 10, 6};
for (int i = 0; i < notas.length / 2; i++) {
int j = notas.length - 1 - i;
int guarda = notas[i];
notas[i] = notas[j];
notas[j] = guarda;
}
System.out.println(Arrays.toString(notas));
}
}
$ java Main.java [6, 10, 5, 9, 7]
| Linha | O que faz |
|---|---|
i < notas.length / 2 | Vai só até a metade (5 / 2 = 2: as voltas 0 e 1). Se fosse até o fim, cada par seria trocado duas vezes e o array voltaria ao normal. O do meio (índice 2) fica onde está. |
int j = notas.length - 1 - i; | O "par" do i do outro lado: com i = 0, j = 4; com i = 1, j = 3. |
int guarda = notas[i]; | O copo vazio: guarda o valor da esquerda. |
notas[i] = notas[j]; | A esquerda recebe o da direita. |
notas[j] = guarda; | A direita recebe o que estava guardado. |
Preencher e mudar com um laço
O laço também serve para escrever no array. Aqui, cada posição recebe o quadrado do seu índice:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] quadrados = new int[6];
for (int i = 0; i < quadrados.length; i++) {
quadrados[i] = i * i;
}
System.out.println(Arrays.toString(quadrados));
}
}
$ java Main.java [0, 1, 4, 9, 16, 25]
E para mudar só alguns: a escola decidiu que nenhuma nota fica abaixo de 6. As menores viram 6:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] notas = {7, 9, 5, 10, 6};
for (int i = 0; i < notas.length; i++) {
if (notas[i] < 6) {
notas[i] = 6;
}
}
System.out.println(Arrays.toString(notas));
}
}
$ java Main.java [7, 9, 6, 10, 6]
Para preencher com o que o usuário digita, use o mesmo laço com um Scanner lendo cada valor (veja Ler do Teclado).
Dois arrays juntos: nomes e notas
A professora quer o boletim com o nome de cada aluno. Uma forma simples é ter dois arrays paralelos: o aluno do índice 0 de alunos tem a nota do índice 0 de notas, e assim por diante. Como precisamos do mesmo índice nos dois, o for-each não serve:
public class Main {
public static void main(String[] args) {
String[] alunos = {"Ana", "Bruno", "Carla", "Davi", "Eva"};
double[] notas = {7.0, 9.5, 5.0, 10.0, 6.5};
for (int i = 0; i < alunos.length; i++) {
String situacao = notas[i] >= 7 ? "aprovado(a)" : "recuperação";
System.out.println(alunos[i] + ": " + notas[i] + " - " + situacao);
}
}
}
$ java Main.java Ana: 7.0 - aprovado(a) Bruno: 9.5 - aprovado(a) Carla: 5.0 - recuperação Davi: 10.0 - aprovado(a) Eva: 6.5 - recuperação
O ? : escolhe um dos dois textos conforme a condição (veja Operador Ternário). Arrays paralelos funcionam, mas exigem cuidado: os dois precisam ter o mesmo tamanho e a mesma ordem. No Nível 2 você vai aprender a juntar nome e nota num objeto só, com records ou classes.
Quando dá errado
ArrayIndexOutOfBoundsException no fim do laço: o <=
public class Main {
public static void main(String[] args) {
int[] notas = {7, 9, 5, 10, 6};
for (int i = 0; i <= notas.length; i++) {
System.out.println(notas[i]);
}
}
}
$ java Main.java 7 9 5 10 6 Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5 at Main.main(Main.java:5)
O que aconteceu: as 5 notas apareceram, e na sexta volta (i = 5) o programa pediu notas[5], que não existe. O <= deixou passar uma volta a mais.
Como consertar: i < notas.length. Ou use o for-each, que nunca erra o limite.
Divisão de int por int corta os decimais: 37 / 5 dá 7. Converta antes de dividir: (double) soma / notas.length. Cuidado com a posição dos parênteses: (double) (soma / notas.length) converte depois da divisão, e dá 7.0.
O valor inicial do "campeão" não era um elemento do array. Comece com int maior = notas[0];, como explicado em Achar o maior e o menor.
No for-each, a variável é uma cópia do elemento. Para mudar o array, use for com índice e escreva em notas[i]. Veja o exemplo real em for-each.
Referência: as receitas
| Tarefa | Antes do laço | Dentro do laço |
|---|---|---|
| Somar | int soma = 0; | soma += x; |
| Média | (a soma) | depois: (double) soma / a.length |
| Maior | int maior = a[0]; | if (x > maior) maior = x; |
| Menor | int menor = a[0]; | if (x < menor) menor = x; |
| Posição do maior | int pos = 0; | if (a[i] > a[pos]) pos = i; |
| Contar | int qtd = 0; | if (teste) qtd++; |
| Buscar | int pos = -1; | if (a[i] == alvo) { pos = i; break; } |
| De trás para frente | for (int i = a.length - 1; i >= 0; i--) | |
| Inverter | troca a[i] com a[a.length - 1 - i], até a metade |
Exercícios
1. O limite certo
Complete a condição para percorrer todo o array precos:
2. Começo do maior
Complete o valor inicial correto para achar o maior elemento de valores:
3. Média com decimais
Complete para a média não perder as casas decimais (soma é int):
4. Qual laço percorre a de trás para frente?
5. Numa busca, por que começar com posicao = -1?
6. int soma = 37; e o array tem 5 elementos. Quanto vale soma / 5?
Missão final: descubra quem tirou a maior nota e mostre Melhor aluno(a): Davi com 10.0. Dica: ache a posição da maior nota em notas e use essa posição nos dois arrays.
public class Main {
public static void main(String[] args) {
String[] alunos = {"Ana", "Bruno", "Carla", "Davi", "Eva"};
double[] notas = {7.0, 9.5, 5.0, 10.0, 6.5};
int melhor = 0;
// percorra o array aqui
System.out.println("Melhor aluno(a): " + alunos[melhor] + " com " + notas[melhor]);
}
}
public class Main {
public static void main(String[] args) {
String[] alunos = {"Ana", "Bruno", "Carla", "Davi", "Eva"};
double[] notas = {7.0, 9.5, 5.0, 10.0, 6.5};
int melhor = 0;
for (int i = 1; i < notas.length; i++) {
if (notas[i] > notas[melhor]) {
melhor = i;
}
}
System.out.println("Melhor aluno(a): " + alunos[melhor] + " com " + notas[melhor]);
}
}
Resumo
- Percorra com
for (int i = 0; i < a.length; i++)quando precisar do índice, e com for-each quando só precisar dos valores. - Acumuladores e contadores nascem antes do laço; o resultado é usado depois.
- Média: converta para
doubleantes de dividir, senão os decimais somem. - Maior e menor: comece com
a[0], nunca com 0. - Busca: comece com
-1, guarde o índice ao achar e pare combreak. - Ao contrário: de
length - 1até0. Inverter: troque os pares até a metade, com uma variável auxiliar. <=no lugar de<dáArrayIndexOutOfBoundsExceptionna última volta.