Java Laços Aninhados
O corpo de um laço pode ter qualquer instrução, inclusive outro laço. Isso se chama laços aninhados (como ninhos, um dentro do outro). É o jeito de trabalhar com coisas que têm duas dimensões: linhas e colunas, fileiras e cadeiras, dias e horários, a tabela de multiplicação inteira.
- Como um laço dentro de outro funciona, volta por volta.
- A regra que resolve quase todo exercício: o de fora são as linhas, o de dentro são as colunas.
- Desenhar retângulos, triângulos e pirâmides com
*. - Montar a tabela de multiplicação de 1 a 10.
- Contar quantas vezes o corpo de dentro roda, e por que isso cresce rápido.
- Os erros mais comuns: mesmo nome de variável, passo trocado,
printlnno lugar deprint.
Os exemplos rodam no terminal da Ana (máquina fictícia notebook, pasta ~/java, JDK 25) com java Main.java. Usamos o for em quase todos, mas a ideia vale para qualquer laço.
A ideia antes do código
Pense num relógio. O ponteiro das horas anda uma vez; enquanto isso, o ponteiro dos minutos dá uma volta inteira (60 passos). Só então as horas andam de novo, e os minutos começam outra volta completa.
Laços aninhados são exatamente isso:
- O laço de fora é o ponteiro das horas: anda devagar.
- O laço de dentro é o ponteiro dos minutos: a cada passo do de fora, ele recomeça do zero e vai até o fim.
Veja um relógio simplificado, de 15 em 15 minutos, por duas horas:
public class Main {
public static void main(String[] args) {
for (int h = 0; h <= 1; h++) {
for (int m = 0; m < 60; m += 15) {
System.out.println(h + "h" + m + "min");
}
}
}
}
$ java Main.java 0h0min 0h15min 0h30min 0h45min 1h0min « o laço das horas andou; os minutos recomeçaram do 0 1h15min 1h30min 1h45min
Volta por volta
Para enxergar a ordem exata, vamos fazer cada laço "se apresentar". O de dentro tem um recuo de quatro espaços na mensagem, só para ficar visível:
public class Main {
public static void main(String[] args) {
for (int i = 1; i <= 2; i++) {
System.out.println("Laço de fora: i = " + i);
for (int j = 1; j <= 3; j++) {
System.out.println(" laço de dentro: i = " + i + ", j = " + j);
}
}
System.out.println("Fim");
}
}
$ java Main.java
Laço de fora: i = 1
laço de dentro: i = 1, j = 1
laço de dentro: i = 1, j = 2
laço de dentro: i = 1, j = 3
Laço de fora: i = 2
laço de dentro: i = 2, j = 1 « o j recomeçou do 1
laço de dentro: i = 2, j = 2
laço de dentro: i = 2, j = 3
Fim
Três fatos para guardar:
- Para cada volta do de fora, o de dentro roda inteiro (aqui, 3 voltas).
- O
jrecomeça do 1 a cada volta do de fora. Isso acontece porque oint j = 1está no cabeçalho do laço de dentro, e esse cabeçalho é executado de novo cada vez que o programa chega nele. - O de dentro enxerga o
ido de fora (ele aparece na mensagem), mas o de fora não enxerga oj: ele só existe dentro do laço de dentro (veja o escopo em for).
Linhas e colunas
O uso mais comum: o laço de fora escolhe a linha, o de dentro escreve as colunas dessa linha. A sala de cinema da cidade tem as fileiras A, B e C, com 4 cadeiras cada:
public class Main {
public static void main(String[] args) {
for (char fileira = 'A'; fileira <= 'C'; fileira++) {
for (int cadeira = 1; cadeira <= 4; cadeira++) {
System.out.print(fileira + "" + cadeira + " ");
}
System.out.println();
}
}
}
$ java Main.java A1 A2 A3 A4 B1 B2 B3 B4 C1 C2 C3 C4
| Linha | O que faz |
|---|---|
for (char fileira = 'A'; fileira <= 'C'; fileira++) | Laço de fora: uma volta por fileira (A, B, C). Um char pode contar, veja char e boolean. |
for (int cadeira = 1; cadeira <= 4; cadeira++) | Laço de dentro: uma volta por cadeira da fileira atual. |
System.out.print(fileira + "" + cadeira + " "); | print, sem "ln": escreve a cadeira e fica na mesma linha. O "" no meio força a junção como texto (sem ele, 'A' + 1 seria a soma do código da letra com 1; veja Concatenação). |
System.out.println(); | Está no laço de fora, depois do de dentro: terminada a fileira, pula para a próxima linha. |
Laço de fora = linhas. Laço de dentro = o que vai em cada linha, com print. Depois do laço de dentro, um println() para fechar a linha. Com essa receita você desenha qualquer figura dos exercícios clássicos.
Desenhando com *
Retângulo
3 linhas, 5 estrelas em cada:
public class Main {
public static void main(String[] args) {
for (int linha = 1; linha <= 3; linha++) {
for (int coluna = 1; coluna <= 5; coluna++) {
System.out.print("*");
}
System.out.println();
}
}
}
$ java Main.java ***** ***** *****
Missão: desenhe um retângulo de 4 linhas com 6 símbolos # em cada. Mantenha os dois laços.
public class Main {
public static void main(String[] args) {
for (int linha = 1; linha <= 3; linha++) {
for (int coluna = 1; coluna <= 5; coluna++) {
System.out.print("*");
}
System.out.println();
}
}
}
public class Main {
public static void main(String[] args) {
for (int linha = 1; linha <= 4; linha++) {
for (int coluna = 1; coluna <= 6; coluna++) {
System.out.print("#");
}
System.out.println();
}
}
}
Triângulo
Agora a linha 1 tem 1 estrela, a linha 2 tem 2, e assim por diante. O truque é um só: o limite do laço de dentro deixa de ser um número fixo e passa a ser a variável do laço de fora:
public class Main {
public static void main(String[] args) {
for (int linha = 1; linha <= 5; linha++) {
for (int coluna = 1; coluna <= linha; coluna++) {
System.out.print("*");
}
System.out.println();
}
}
}
$ java Main.java * ** *** **** *****
linha | O de dentro vai de 1 até… | Estrelas |
|---|---|---|
| 1 | 1 | * |
| 2 | 2 | ** |
| 3 | 3 | *** |
| 4 | 4 | **** |
| 5 | 5 | ***** |
Triângulo de cabeça para baixo
Basta o laço de fora contar para baixo, de 5 até 1. O de dentro continua igual:
public class Main {
public static void main(String[] args) {
for (int linha = 5; linha >= 1; linha--) {
for (int coluna = 1; coluna <= linha; coluna++) {
System.out.print("*");
}
System.out.println();
}
}
}
$ java Main.java ***** **** *** ** *
Pirâmide
Uma pirâmide centralizada precisa de dois laços de dentro, um depois do outro: primeiro os espaços da esquerda, depois as estrelas. Na linha linha de uma pirâmide de altura 4, há 4 - linha espaços e 2 * linha - 1 estrelas (1, 3, 5, 7):
public class Main {
public static void main(String[] args) {
int altura = 4;
for (int linha = 1; linha <= altura; linha++) {
for (int espaco = 1; espaco <= altura - linha; espaco++) {
System.out.print(" ");
}
for (int estrela = 1; estrela <= 2 * linha - 1; estrela++) {
System.out.print("*");
}
System.out.println();
}
}
}
$ java Main.java * *** ***** *******
Os dois laços de dentro estão lado a lado, não um dentro do outro: a cada linha, primeiro roda o dos espaços inteiro, depois o das estrelas inteiro. Trocar altura por 10 desenha uma pirâmide maior sem mexer em mais nada.
A tabela de multiplicação
Na aula de for, um laço fez a tabuada de um número. Com dois laços, saem todas, de 1 a 10, numa tabela: a linha é o i, a coluna é o j, e cada célula é i * j. Para alinhar as colunas, cada número é seguido de um "\t", o caractere de tabulação (o Tab, veja Caracteres Especiais):
public class Main {
public static void main(String[] args) {
for (int i = 1; i <= 10; i++) {
for (int j = 1; j <= 10; j++) {
System.out.print(i * j + "\t");
}
System.out.println();
}
}
}
$ java Main.java 1 2 3 4 5 6 7 8 9 10 2 4 6 8 10 12 14 16 18 20 3 6 9 12 15 18 21 24 27 30 4 8 12 16 20 24 28 32 36 40 5 10 15 20 25 30 35 40 45 50 6 12 18 24 30 36 42 48 54 60 7 14 21 28 35 42 49 56 63 70 8 16 24 32 40 48 56 64 72 80 9 18 27 36 45 54 63 72 81 90 10 20 30 40 50 60 70 80 90 100
Aqui i * j + "\t" funciona sem parênteses porque a multiplicação vem antes da soma (veja Precedência): primeiro i * j vira um número, depois ele é juntado com o "\t". Para alinhar com mais controle, existe o printf, que você verá em Formatar Texto.
Do jeito "livro": uma tabuada embaixo da outra
O laço de dentro não precisa escrever na mesma linha. Aqui, o de fora escreve um título e o de dentro escreve cinco linhas:
public class Main {
public static void main(String[] args) {
for (int n = 1; n <= 3; n++) {
System.out.println("Tabuada do " + n + ":");
for (int i = 1; i <= 5; i++) {
System.out.println(" " + n + " x " + i + " = " + (n * i));
}
}
}
}
$ java Main.java Tabuada do 1: 1 x 1 = 1 1 x 2 = 2 1 x 3 = 3 1 x 4 = 4 1 x 5 = 5 Tabuada do 2: 2 x 1 = 2 2 x 2 = 4 2 x 3 = 6 2 x 4 = 8 2 x 5 = 10 Tabuada do 3: 3 x 1 = 3 3 x 2 = 6 3 x 3 = 9 3 x 4 = 12 3 x 5 = 15
Contando as voltas
Quantas vezes o corpo de dentro roda? Vamos perguntar ao próprio programa, com um contador:
public class Main {
public static void main(String[] args) {
int voltas = 0;
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 4; j++) {
voltas++;
}
}
System.out.println("O corpo de dentro rodou " + voltas + " vezes");
}
}
$ java Main.java O corpo de dentro rodou 12 vezes
3 voltas de fora × 4 de dentro = 12. A regra geral: quando os limites são fixos, multiplique. Foi assim que a tabela de multiplicação escreveu 10 × 10 = 100 números.
No triângulo, o de dentro roda cada vez mais. Comparando os dois formatos com n = 10:
public class Main {
public static void main(String[] args) {
int n = 10;
int quadrado = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
quadrado++;
}
}
int triangulo = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= i; j++) {
triangulo++;
}
}
System.out.println("n = " + n);
System.out.println("Quadrado (j até n): " + quadrado + " voltas");
System.out.println("Triângulo (j até i): " + triangulo + " voltas");
}
}
$ java Main.java n = 10 Quadrado (j até n): 100 voltas Triângulo (j até i): 55 voltas « 1 + 2 + 3 + ... + 10
Laços aninhados crescem rápido. Com n = 10, o quadrado dá 100 voltas; com n = 1000, dá um milhão; com três laços aninhados de 1000, um bilhão. Quando um programa com laços aninhados fica lento com muitos dados, é por isso. Por enquanto, basta lembrar: cada laço a mais multiplica o trabalho.
break e continue nos laços aninhados
Dentro de laços aninhados, break e continue agem só no laço onde estão escritos (o mais de dentro). Para sair dos dois de uma vez, use um rótulo, como break externo;. Tudo isso está explicado com exemplos reais em break e continue.
Formas diferentes
Qualquer laço pode ficar dentro de qualquer outro. Os mais comuns:
| Combinação | Exemplo de uso |
|---|---|
for dentro de for | Figuras, tabelas, as linhas e colunas de uma matriz. |
| for-each dentro de for-each | Para cada turma, para cada aluno da turma. |
for dentro de while | Enquanto o usuário quiser continuar, desenhar uma linha de N estrelas. |
| Dois laços de dentro lado a lado | A pirâmide: espaços e depois estrelas, na mesma linha. |
| Três laços | Raros: horas, minutos e segundos; cubos de dados. Cuidado com o número de voltas. |
Quando dá errado
public class Main {
public static void main(String[] args) {
for (int i = 1; i <= 3; i++) {
for (int i = 1; i <= 4; i++) {
System.out.print("*");
}
System.out.println();
}
}
}
$ java Main.java
Main.java:4: error: variable i is already defined in method main(String[])
for (int i = 1; i <= 4; i++) {
^
1 error
error: compilation failed
O que quer dizer: "a variável i já foi definida no método main". O i do laço de fora ainda está vivo dentro do laço de dentro, então não dá para criar outro com o mesmo nome.
Como consertar: use um nome diferente no de dentro: j (a tradição) ou, melhor ainda, nomes que digam o que contam: linha e coluna.
public class Main {
public static void main(String[] args) {
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 4; i++) {
System.out.print("*");
}
System.out.println();
}
}
}
$ java Main.java ************************************************************ « … uma linha só, sem fim … $ echo $? « depois do Ctrl+C 130
O que aconteceu: o laço de dentro testa j, mas o passo soma em i (copiar e colar o cabeçalho do laço de fora é a causa clássica). O j fica 1 para sempre, a condição j <= 4 nunca fica falsa e o programa escreve estrelas sem parar, todas na mesma linha (o println nunca é alcançado). Em um segundo, foram mais de 200 mil estrelas até a Ana apertar Ctrl+C.
Como consertar: confira as três partes do cabeçalho de dentro: todas devem usar a mesma variável (j = 1; j <= 4; j++).
println no lugar de print
public class Main {
public static void main(String[] args) {
for (int linha = 1; linha <= 3; linha++) {
for (int coluna = 1; coluna <= 5; coluna++) {
System.out.println("*");
}
}
}
}
$ java Main.java * * * * * * * * * * * * * * *
O que aconteceu: as 15 estrelas estão certas (3 × 5), mas cada println pula a linha. O retângulo virou uma coluna.
Como consertar: dentro do laço de dentro, print; depois dele, no laço de fora, um println() para fechar a linha.
Confira o lugar do println(): se ele estiver dentro do laço de dentro, cada estrela fica numa linha; se estiver fora dos dois laços, tudo sai numa linha só. O lugar certo é dentro do de fora, logo depois do } do de dentro. Uma boa indentação (o recuo das linhas) mostra isso de relance; mantenha cada laço quatro espaços mais para dentro que o anterior.
Referência
| Padrão | Laço de fora | Laço de dentro | Voltas do de dentro (total) |
|---|---|---|---|
| Retângulo L × C | linha de 1 a L | coluna de 1 a C | L × C |
| Triângulo | linha de 1 a N | coluna de 1 a linha | 1 + 2 + … + N |
| Triângulo invertido | linha de N a 1 | coluna de 1 a linha | N + … + 2 + 1 |
| Pirâmide de altura A | linha de 1 a A | A - linha espaços, depois 2*linha - 1 estrelas | A² estrelas |
| Tabela de multiplicação | i de 1 a 10 | j de 1 a 10, mostra i * j | 100 |
Exercícios
1. O limite do triângulo
Complete o laço de dentro para desenhar um triângulo (1, 2, 3… estrelas por linha):
2. Fechar a linha
Complete a instrução que vai logo depois do laço de dentro, para cada linha do desenho terminar:
3. Quantas voltas?
Quantas vezes o print roda em for (int i = 0; i < 4; i++) for (int j = 0; j < 6; j++) System.out.print("*");?
4. Em dois laços aninhados, quando o laço de dentro "recomeça do início"?
5. Qual figura este código desenha? for (int l = 3; l >= 1; l--) { for (int c = 1; c <= l; c++) System.out.print("*"); System.out.println(); }
6. Com três laços aninhados, cada um de 1 a 100, quantas vezes o corpo mais de dentro roda?
Missão final: desenhe um triângulo de números com 4 linhas: a linha 1 mostra 1 , a linha 2 mostra 1 2 , a linha 3 mostra 1 2 3 e a linha 4 mostra 1 2 3 4 (cada número seguido de um espaço). Dica: é o triângulo de estrelas, trocando "*" pela variável do laço de dentro.
public class Main {
public static void main(String[] args) {
for (int linha = 1; linha <= 4; linha++) {
// laço de dentro aqui
System.out.println();
}
}
}
public class Main {
public static void main(String[] args) {
for (int linha = 1; linha <= 4; linha++) {
for (int coluna = 1; coluna <= linha; coluna++) {
System.out.print(coluna + " ");
}
System.out.println();
}
}
}
Resumo
- Um laço dentro de outro: para cada volta do de fora, o de dentro roda inteiro, recomeçando do início.
- Para figuras e tabelas: o de fora são as linhas, o de dentro são as colunas (com
print), e umprintln()fecha cada linha. - Triângulo: o limite do de dentro é a variável do de fora (
coluna <= linha). - Total de voltas com limites fixos = multiplicação dos limites. Cada laço a mais multiplica o trabalho.
- Use nomes diferentes em cada laço (
i/j, ou melhor,linha/coluna) e confira se as três partes de cada cabeçalho usam a mesma variável. breakecontinueagem no laço mais de dentro; para sair dos dois, use um rótulo (break e continue).