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.

Você vai aprender
  • As duas formas de percorrer (for com í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 i for um índice válido. Com 5 notas, para quando i chega 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 arrayfor 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 juntosfor 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;.

Array vazio

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)77
7não7não7
9sim9não7
5não9sim5
10sim10não5
6não10não5

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]
LinhaO que faz
i < notas.length / 2Vai 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.

A média deu um número "redondo" demais

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 maior deu 0 (ou o menor deu 0), e o 0 nem está no array

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.

Mudei a variável do for-each e o array não mudou

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

TarefaAntes do laçoDentro do laço
Somarint soma = 0;soma += x;
Média(a soma)depois: (double) soma / a.length
Maiorint maior = a[0];if (x > maior) maior = x;
Menorint menor = a[0];if (x < menor) menor = x;
Posição do maiorint pos = 0;if (a[i] > a[pos]) pos = i;
Contarint qtd = 0;if (teste) qtd++;
Buscarint pos = -1;if (a[i] == alvo) { pos = i; break; }
De trás para frentefor (int i = a.length - 1; i >= 0; i--)
Invertertroca 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:

for (int i = 0; ; i++)

2. Começo do maior

Complete o valor inicial correto para achar o maior elemento de valores:

int maior =

3. Média com decimais

Complete para a média não perder as casas decimais (soma é int):

double media =

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 double antes 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 com break.
  • Ao contrário: de length - 1 até 0. Inverter: troque os pares até a metade, com uma variável auxiliar.
  • <= no lugar de < dá ArrayIndexOutOfBoundsException na última volta.