flowchart TD
A([Inici]) --> B["1. Inicialització<br/>(preparar el comptador)"]
B --> C{"2. Condició<br/>certa?"}
C -->|Sí| D["Cos del bucle<br/>(què repetim)"]
D --> E["3. Actualització<br/>(avançar cap al final)"]
E --> C
C -->|No| F([Fi])
7 Estructures de repetició
Objectius
- Entendre què és un bucle i per què evita repetir codi.
- Escollir entre
while,do-whileiforsegons la situació. - Controlar l’execució amb
breakicontinue. - Combinar bucles amb condicions per resoldre problemes.
- Escriure bucles aniuats per treballar amb estructures de dues dimensions.
- Generar nombres aleatoris per a jocs i simulacions.
- Reconèixer i evitar els bucle infinits.
Fins ara els nostres programes s’executaven de dalt a baix, una instrucció rere l’altra, i com a molt triaven un camí o un altre amb un if. Però moltes tasques consisteixen a fer el mateix moltes vegades: sumar cent nombres, demanar dades fins que siguin correctes, dibuixar una graella… Copiar i enganxar la mateixa instrucció cent vegades no és una opció. Per això existeixen les estructures de repetició o bucles.
7.1 Què és un bucle?
Un bucle és una estructura que executa un bloc d’instruccions diverses vegades mentre es compleix una condició.
El bloc que es repeteix s’anomena cos del bucle, i cada repetició s’anomena iteració.
Tot bucle té tres components que has de tenir sempre al cap. Si en falta un, el bucle no funcionarà bé:
- Inicialització: preparem una variable de control abans d’entrar (per exemple,
int i = 1). - Condició: una expressió booleana que es comprova abans de cada iteració.
- Actualització: dins del cos, canviem alguna cosa perquè, tard o d’hora, la condició deixi de ser certa.
Si oblides l’actualització, la condició sempre serà certa i el bucle no acabarà mai: és un bucle infinit.
7.2 El bucle while
El while és el bucle més senzill i directe: repeteix el cos mentre la condició sigui certa.
while (condició) {
// Cos: instruccions que es repeteixen
}Primer comprova la condició. Si és certa, executa el cos i torna a comprovar-la.
Si és falsa, surt del bucle sense executar el cos ni una vegada.
Exemple: comptar de l’1 al 5.
int i = 1; // 1. Inicialització
while (i <= 5) { // 2. Condició
System.out.println("Comptem: " + i);
i = i + 1; // 3. Actualització
}
System.out.println("Fet!");Aquest programa escriu “Comptem: 1” fins a “Comptem: 5” i després “Fet!”.
La variable i comença a 1, i a cada volta creix en 1. Quan arriba a 6, la condició i <= 5 es torna falsa i el bucle acaba.
Si t’oblides d’actualitzar la variable de control, el bucle no acaba mai:
int i = 1;
while (i <= 5) {
System.out.println("Comptem: " + i);
// Ens hem deixat i = i + 1; → i sempre val 1 i generem un bucle INFINIT!
}El programa es queda “penjat” escrivint “Comptem: 1” per sempre.
Si això et passa, atura’l amb Ctrl + C a la consola. Comprova sempre que alguna cosa dins del cos acosta la condició cap a fals.
Escriu un while que escrigui els nombres parells del 2 al 20 (2, 4, 6, …).
Pista: pots avançar de dos en dos amb i = i + 2.
7.3 El bucle do-while
A vegades volem que el cos s’executi almenys una vegada, i comprovar la condició després.
Per exemple, un menú que sempre s’ha de mostrar un cop abans de decidir si el tornem a mostrar. Per a això fem servir do-while:
do {
// Cos: s'executa com a mínim una vegada
} while (condició); La línia on expressem la condició acaba amb un punt i coma final.
Exemple: demanar un nombre positiu i no parar fins que l’usuari l’introdueixi bé:
Scanner sc = new Scanner(System.in);
int edat;
do {
System.out.print("Introdueix la teva edat (positiva): ");
edat = sc.nextInt();
} while (edat <= 0);
System.out.println("Gràcies! Edat: " + edat);Com que la pregunta s’ha de fer sí o sí un primer cop, do-while hi encaixa millor que while.
La diferència clau entre tots dos és quan es comprova la condició:
%%{init: {"flowchart": {"nodeSpacing": 120}}}%%
flowchart LR
subgraph while
W1{"Condició?"} -->|Sí| W2["Cos"]
W2 --> W1
W1 -->|No| W3([Fi])
end
subgraph do-while
D1["Cos"] --> D2{"Condició?"}
D2 -->|Sí| D1
D2 -->|No| D3([Fi])
end
while ~~~ do-while
classDef noBox fill:none,stroke:none;
class while,do-while noBox;
Amb while, si la condició és falsa d’entrada, el cos no s’executa cap vegada.
Amb do-while, el cos s’executa sempre almenys una vegada.
El do-while acaba amb punt i coma després del while (condició);.
Si te’l deixes, el compilador es queixarà. És l’únic bucle que porta punt i coma al final.
7.4 El bucle for
Quan sabem quantes vegades volem repetir (o tenim un comptador clar), el for és l’opció més neta.
Reuneix els tres components del bucle en una sola línia:
for (inicialització; condició; actualització) {
// Cos
}Exemple: el mateix comptador que hem vist abans, però amb for:
for (int i = 1; i <= 5; i++) {
System.out.println("Comptem: " + i);
}Es llegeix així: “comença amb i = 1; mentre i <= 5, executa el cos; i després de cada volta, fes i++”.
L’operador i++ és una manera curta d’escriure i = i + 1.
Compara les dues formes d’escriure el mateix bucle:
| Aspecte | while |
for |
|---|---|---|
| Els 3 components | Escampats pel codi | Junts a la capçalera |
| Quan usar-lo | No saps quantes voltes faràs | Saps quantes voltes o tens comptador |
Àmbit de i |
Viu fora del bucle | Viu només dins del bucle |
| Llegibilitat de comptadors | Més verbós | Més compacte |
Tots dos són igual de potents: qualsevol for es pot reescriure com un while i a l’inrevés.
Tria el que faci el codi més clar.
for
Usos habituals del bucle for:
// Endavant: 0, 1, 2, 3, 4
for (int i = 0; i < 5; i++) { ... }
// Enrere: 10, 9, 8, ..., 1
for (int i = 10; i >= 1; i--) { ... }
// De dos en dos: 0, 2, 4, 6, 8
for (int i = 0; i < 10; i += 2) { ... }En programació és molt habitual començar a comptar des de 0. Ho entendràs del tot quan arribem als arrays.
És facilíssim equivocar-se en un < per un <=. Aquest bucle fa 6 voltes (de 0 a 5), no 5:
for (int i = 0; i <= 5; i++) { ... } // 0,1,2,3,4,5 → 6 voltes!Si volies exactament 5 voltes començant des de 0, la condició ha de ser i < 5.
Aquest error té nom propi perquè és dels més comuns del món: off-by-one.
Escriu un for que calculi la suma de tots els nombres de l’1 al 100 i la mostri per pantalla.
Pista: fes servir una variable suma inicialitzada a 0 abans del bucle.
7.5 Controlar el bucle: break i continue
A vegades cal alterar el flux normal del bucle des de dins:
break: surt del bucle immediatament, encara que la condició fos certa.continue: salta la resta del cos i passa directament a la iteració següent.
Exemple de break. Buscar el primer múltiple de 7 més gran que 50 i parar en trobar-lo:
for (int i = 51; i <= 100; i++) {
if (i % 7 == 0) {
System.out.println("Trobat: " + i);
break; // No cal seguir buscant
}
}Exemple de continue. Escriure només els nombres senars de l’1 al 10:
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) {
continue; // Si és parell, salta l'escriptura
}
System.out.println(i); // Només s'arriba aquí si és senar
}breakés sortir del gimnàs a mitja sessió i tancar la porta: s’ha acabat.continueés saltar-te un exercici concret però continuar amb la rutina: passes al següent.
break
break i continue són útils, però si n’omples el codi es fa difícil de seguir.
Sovint una condició ben pensada a la capçalera del bucle és més clara que un break amagat al mig. Fes-los servir amb mesura.
7.6 Bucles aniuats
Un bucle pot contenir un altre bucle dins del seu cos: en diem bucles aniuats. El bucle de fora fa una volta, i per cada volta seva el de dins fa totes les seves. Són imprescindibles per treballar amb graelles, taules i estructures de dues dimensions. Ho necessitarem més endavant.
Exemple: les taules de multiplicar de l’1 al 3.
for (int taula = 1; taula <= 3; taula++) {
System.out.println("--- Taula del " + taula + " ---");
for (int n = 1; n <= 10; n++) {
System.out.println(taula + " x " + n + " = " + (taula * n));
}
}El bucle extern tria la taula; per a cada taula, el bucle intern recorre del multiplicand 1 al 10.
En total s’executen 3 × 10 = 30 línies de multiplicació.
Escriu dos bucles niats que dibuixin un triangle d’asteriscs com aquest (5 files):
*
**
***
****
*****
Pista: a la fila número i, imprimeix i asteriscs. Pots imprimir sense salt de línia amb System.out.print("*") i fer el salt amb System.out.println() al final de cada fila.
7.7 Nombres aleatoris
Per a jocs, simulacions o barrejar dades, necessitem atzar. Java ens el dona amb la classe Random.
Primer l’hem d’importar a dalt del fitxer i després en creem un objecte i li demanem nombres:
import java.util.Random;
...
Random atzar = new Random();
int daus = atzar.nextInt(6) + 1; // Enter de 1 a 6 (com un dau)
int nota = atzar.nextInt(11); // Enter de 0 a 10
double x = atzar.nextDouble(); // Decimal de 0.0 (inclòs) a 1.0 (exclòs)
boolean cara = atzar.nextBoolean(); // True o false (llançar moneda)El mètode nextInt(n) retorna un enter entre 0 (inclòs) i n (exclòs).
Per obtenir un dau (1 a 6) sumem 1 al resultat de nextInt(6), que dona de 0 a 5.
Exemple complert. Joc d’endevinar un nombre. Uneix tot el que hem après (bucle, condicions, aleatoris).
import java.util.Random;
import java.util.Scanner;
public class Endevina {
public static void main(String[] args) {
Random atzar = new Random();
Scanner sc = new Scanner(System.in);
int secret = atzar.nextInt(100) + 1; // 1 a 100
int intent;
int intents = 0;
do {
System.out.print("Endevina el nombre (1-100): ");
intent = sc.nextInt();
intents++;
if (intent < secret) {
System.out.println("Massa baix!");
} else if (intent > secret) {
System.out.println("Massa alt!");
}
} while (intent != secret);
System.out.println("Encertat en " + intents + " intents!");
}
}nextInt(6) dona d’1 a 6
nextInt(6) dona 0, 1, 2, 3, 4 o 5 (mai el 6). Si vols un dau real, no oblidis el + 1.
Confondre els límits inclòs/exclòs és una font d’errors molt habitual.
Simula el llançament de dos daus 10 vegades i escriu, a cada tirada, els dos valors i la seva suma. Compta quantes vegades surt una suma de 7.
7.8 Quin bucle triar?
Amb tres bucles disponibles, com decideixes? Aquesta guia ràpida t’ajudarà:
flowchart TD
A{"Saps quantes<br/>vegades es repetirà?"} -->|Sí| B["Fes servir <b>for</b>"]
A -->|No| C{"El cos s'ha d'executar<br/>almenys una vegada?"}
C -->|Sí| D["Fes servir <b>do-while</b>"]
C -->|No| E["Fes servir <b>while</b>"]
No és una regla sagrada: qualsevol dels tres pot resoldre qualsevol problema. Però seguir aquest criteri farà que el teu codi sigui més natural de llegir.
7.9 Resum
- Un bucle repeteix un bloc d’instruccions mentre es compleix una condició. Cada repetició és una iteració.
- Tot bucle necessita inicialització, condició i actualització. Si falta l’actualització, tens un bucle infinit.
- Comparativa ràpida de bucles:
while: comprova la condició abans; pot no executar-se cap vegada.do-while: comprova la condició després; s’executa almenys una vegada (i porta;al final).for: reuneix els tres components a la capçalera; ideal quan tens un comptador.
breaksurt del bucle;continuesalta a la iteració següent.- Els bucles aniuats permeten treballar amb graelles i taules.
- La classe
Randomgenera atzar; recorda quenextInt(n)dona de 0 a n-1. - Vigila el desajust d’una unitat (off-by-one) i el bucle infinit: són els errors més freqüents.
7.10 Per practicar
- Compte enrere. Demana un nombre
ni escriu la seqüència denfins a 0, i després “Enlaire!”. - Factorial. Calcula el factorial d’un nombre (
5! = 5·4·3·2·1 = 120) amb unfor. - Validació robusta. Amb
do-while, demana una nota entre 0 i 10 i no acceptis res fora d’aquest rang. - Piràmide. Amb bucles niats, dibuixa una piràmide centrada d’asteriscs d’alçada
n. - Endevina millorat. Amplia el joc d’endevinar per limitar-lo a 7 intents màxim, fent servir
break. - Pedra, paper, tisora. Fes que l’ordinador jugui a l’atzar amb
Randomi porti el marcador de partides al millor de 5. - Nombres primers. Escriu tots els nombres primers menors que 100 (pista: un
forextern per als candidats i un d’intern per comprovar divisors).