Bucles en Java — ejercicios con vocales, notas hasta el -1 y primos en un rango (y el bucle que se me colgó a mí)
El primer bucle que escribí en Java se quedó colgado. No dio error ni excepción: la terminal empezó a llenarse de «Vuelta 0», «Vuelta 0», «Vuelta 0»… tan deprisa que no daba tiempo a leer, y el ventilador del portátil se puso a sonar como un secador. Tuve que pararlo con Ctrl + C. El fallo era una línea que no estaba: el i++ que hace avanzar el bucle. La condición i < 5 era verdadera al principio y seguía siéndolo para siempre, porque nada la cambiaba. Lo verás con su salida real (y un freno para que no llene la página) en «¿Qué falla aquí?».
Aquí tienes tres ejercicios de bucles en Java, de menos a más: contar las vocales de una frase (recorrer un texto con for y un switch dentro), pedir notas hasta que llegue un -1 (centinela, acumuladores, máximo y mínimo sin guardar las notas) y buscar los primos de un rango (bucles anidados con break). Como en la práctica de bucles, todo lo que se teclea viene del Scanner y no hay arrays. Al final tienes el cuestionario tipo examen y el chuletario.
Tabla de Contenidos
Cómo usar este artículo
- Lee el enunciado y la salida esperada de cada ejercicio. La salida es real: si tu programa imprime lo mismo con los mismos datos, vas bien.
- Inténtalo sin mirar nada al menos 15 minutos. Si te atascas, abre la pista.
- Antes de las soluciones, haz «¿Qué falla aquí?»: tres fragmentos con un error cada uno. Predice qué imprimen antes de leer la explicación.
- Compara tu solución con la comentada. Haz una tabla de traza con dos o tres vueltas: es la forma más rápida de encontrar dónde se separan las dos.
Las salidas son de una única ejecución con Java 21 en un equipo en español: los decimales se teclean con coma (7,5) y lo que aparece detrás de cada pregunta es lo que se tecleó. En el entorno de Java de la web lo tecleado va en la pestaña Entrada, una línea por dato.
Todos los temas de Java de FP2, en orden y con su cuestionario, están en los ejercicios de Java resueltos.
Nivel básico
Ejercicio 1 — Contador de vocales
Escribe ContadorVocales: pide una palabra o frase y cuenta cuántas veces aparece cada vocal, el total y cuál es la más repetida (en caso de empate, la primera en el orden a, e, i, o, u). Da igual que estén en mayúscula, y las vocales con tilde cuentan como su vocal (á es una a). Si no hay ninguna, lo dice.
Salida esperada con programacion:
=== CONTADOR DE VOCALES === Palabra o frase: programacion --- Resultado --- a: 2 e: 0 i: 1 o: 2 u: 0 Total de vocales: 5 La más repetida: a (2 veces)
Con mayúsculas y tildes:
=== CONTADOR DE VOCALES === Palabra o frase: Programación en Java --- Resultado --- a: 4 e: 1 i: 1 o: 2 u: 0 Total de vocales: 8 La más repetida: a (4 veces)
Sin vocales:
=== CONTADOR DE VOCALES === Palabra o frase: FP2 xyz 2026 --- Resultado --- a: 0 e: 0 i: 0 o: 0 u: 0 Total de vocales: 0 No hay vocales.
Pasa el texto a minúsculas una vez, antes del bucle. Recorre con for (int k = 0; k < texto.length(); k++) (la i te la vas a querer quedar para el contador de la vocal i) y dentro, un switch sobre texto.charAt(k) con flechas: case 'a', 'á' -> a++;. Para la más repetida, empieza suponiendo que es la a y compárala con las demás usando >. Comprueba a mano: en «programacion» hay dos o, dos a y una i.
Nivel intermedio
Ejercicio 2 — Notas con valor centinela
Escribe NotasCentinela: pide notas una a una (con decimales) hasta que se teclee -1, que no es una nota sino la señal de que se ha terminado. Las notas fuera de 0-10 se rechazan con un aviso y no cuentan. Al terminar, muestra cuántas notas hay y cuántas aprobadas, la media con dos decimales, la máxima y la mínima, sin guardar las notas (todavía no hemos visto los arrays). Si no se ha metido ninguna, avisa y no calcula la media.
Salida esperada con 6, 8, 11 (no vale), 4, 9 y 7,5:
=== NOTAS DE LA ASIGNATURA === Escribe las notas una a una (de 0 a 10). Escribe -1 para terminar. Nota: 6 Nota: 8 Nota: 11 No vale: va de 0 a 10. Nota: 4 Nota: 9 Nota: 7,5 Nota: -1 --- Resumen --- Notas: 5 (aprobadas: 4) Media: 6,90 Máxima: 9.0 Mínima: 4.0
Si la primera es el -1:
=== NOTAS DE LA ASIGNATURA === Escribe las notas una a una (de 0 a 10). Escribe -1 para terminar. Nota: -1 --- Resumen --- No hay notas: no se puede calcular la media.
Un do-while (true) que pide la nota y sale con break cuando es -1; para las notas fuera de rango, aviso y continue. Necesitas un contador, otro de aprobadas y un acumulador suma, todos fuera del bucle y empezando en 0. La máxima y la mínima no pueden empezar en 0: dales el valor de la primera nota válida (la vuelta en la que el contador pasa a 1). La media es suma / cuantas, y solo si cuantas > 0.
Desafío final
Ejercicio 3 — Números primos en un rango
Escribe PrimosEnRango: pide un inicio y un final y muestra los primos que hay entre los dos (incluidos), en filas de cinco. Al final, el total de primos y cuántas divisiones se han hecho para encontrarlos. Si el inicio es mayor que el final, avisa y termina. El 0 y el 1 no son primos: si el inicio es menor que 2, se empieza en 2.
Salida esperada de 10 a 30:
=== NÚMEROS PRIMOS EN UN RANGO === Desde: 10 Hasta: 30 --- Primos encontrados --- 11 13 17 19 23 29 Total: 6 primos (38 divisiones)
De 1 a 100:
=== NÚMEROS PRIMOS EN UN RANGO === Desde: 1 Hasta: 100 --- Primos encontrados --- 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 Total: 25 primos (236 divisiones)
Con el rango al revés:
=== NÚMEROS PRIMOS EN UN RANGO === Desde: 30 Hasta: 10 Rango no válido: «desde» tiene que ser menor o igual que «hasta».
El bucle de fuera recorre cada candidato n del rango; el de dentro prueba divisores d desde 2. Para cada candidato, una bandera esPrimo = true que el bucle de dentro pone a false si encuentra un divisor (y entonces break: ya no hace falta seguir). No hace falta probar hasta n - 1: basta con que d * d <= n. Para las filas de cinco, acumula los primos en un String e imprímelo cada vez que el total sea múltiplo de 5; al terminar, imprime lo que haya quedado.
¿Qué falla aquí?
Antes de las soluciones, tres fragmentos con un error cada uno: los tres compilan sin avisos. Lee cada uno y predice qué imprime antes de mirar la salida.
Error 1
public class Vueltas {
public static void main(String[] args) {
int i = 0;
int freno = 0; // freno de emergencia: NO forma parte del error
while (i < 5) {
System.out.println("Vuelta " + i);
freno++;
if (freno == 6) {
System.out.println("(freno: 6 vueltas y sigue)");
break;
}
}
}
}
¿Cuántas vueltas da? Salida real:
Vuelta 0 Vuelta 0 Vuelta 0 Vuelta 0 Vuelta 0 Vuelta 0 (freno: 6 vueltas y sigue)
Sin el freno, no terminaría nunca: es mi bucle colgado. La condición es i < 5, pero dentro del cuerpo nadie cambia i: vale 0 en la primera vuelta, en la segunda y en la millonésima. El freno (freno == 6) no forma parte del error: lo he puesto para que la salida quepa en la página.
Un while cuya condición depende de una variable que el cuerpo no modifica. El for lo hace más difícil porque el avance está en la cabecera (i++), pero en un while es responsabilidad tuya. Antes de ejecutar, señala con el dedo qué línea del cuerpo cambia la condición.
Arreglo:
public class Vueltas {
public static void main(String[] args) {
int i = 0;
while (i < 5) {
System.out.println("Vuelta " + i);
i++; // la variable de la condición tiene que cambiar
}
}
}
Vuelta 0 Vuelta 1 Vuelta 2 Vuelta 3 Vuelta 4
Error 2
public class BuscarPareja {
public static void main(String[] args) {
// Quiero la PRIMERA pareja (a, b) de 1 a 6 con a * b == 12
for (int a = 1; a <= 6; a++) {
for (int b = 1; b <= 6; b++) {
if (a * b == 12) {
System.out.println("Encontrada: " + a + " x " + b);
break;
}
}
}
System.out.println("Fin de la búsqueda");
}
}
Se quiere la primera pareja a × b = 12. Salida real:
Encontrada: 2 x 6 Encontrada: 3 x 4 Encontrada: 4 x 3 Encontrada: 6 x 2 Fin de la búsqueda
El break solo sale del bucle en el que está, el de dentro (b). El de fuera no se entera y pasa a a = 3, encuentra 3 × 4, sale de esa fila, pasa a la 4… En total, cuatro parejas.
Pensar que break sale de todos los bucles. Sale solo del más cercano. Para cortar también el de fuera hace falta una bandera en su condición (o una etiqueta, break busqueda;, como viste en la teoría).
Arreglo con bandera:
public class BuscarPareja {
public static void main(String[] args) {
boolean encontrada = false;
for (int a = 1; a <= 6 && !encontrada; a++) { // la bandera también para el de fuera
for (int b = 1; b <= 6; b++) {
if (a * b == 12) {
System.out.println("Encontrada: " + a + " x " + b);
encontrada = true;
break;
}
}
}
System.out.println("Fin de la búsqueda");
}
}
Encontrada: 2 x 6 Fin de la búsqueda
Error 3
import java.util.Scanner;
public class MinimaMal {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
double minima = 0;
System.out.print("Nota: ");
double nota = sc.nextDouble();
while (nota != -1) {
if (nota < minima) {
minima = nota;
}
System.out.print("Nota: ");
nota = sc.nextDouble();
}
System.out.println("Mínima: " + minima);
}
}
Con las notas 6, 8, 4 y 9, ¿cuál es la mínima? Salida real:
Nota: 6 Nota: 8 Nota: 4 Nota: 9 Nota: -1 Mínima: 0.0
minima empieza en 0, y ninguna nota real es menor que 0, así que el if no entra nunca y la «mínima» se queda en un 0 que nadie ha tecleado. El mismo fallo, al revés, haría que una máxima empezada en 100 no cambiara nunca.
Inicializar un mínimo (o un máximo) con un valor que «parece neutro». Para una suma, 0 es neutro; para un mínimo, no. O lo inicializas con el primer dato real, o con un valor que cualquier dato supere (Double.MAX_VALUE para un mínimo).
Arreglo con Double.MAX_VALUE:
import java.util.Scanner;
public class MinimaMal {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
double minima = Double.MAX_VALUE; // cualquier nota real será menor
System.out.print("Nota: ");
double nota = sc.nextDouble();
while (nota != -1) {
if (nota < minima) {
minima = nota;
}
System.out.print("Nota: ");
nota = sc.nextDouble();
}
System.out.println("Mínima: " + minima);
}
}
Nota: 6 Nota: 8 Nota: 4 Nota: 9 Nota: -1 Mínima: 4.0
Soluciones comentadas
Solución Ejercicio 1
import java.util.Scanner;
/**
* Contador de vocales: un for recorre la frase y un switch suma a la vocal que toque.
* Las vocales con tilde cuentan como su vocal (á → a) y da igual la mayúscula.
*/
public class ContadorVocales {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("=== CONTADOR DE VOCALES ===");
System.out.print("Palabra o frase: ");
String texto = sc.nextLine().toLowerCase(); // una sola conversión, fuera del bucle
int a = 0, e = 0, i = 0, o = 0, u = 0; // un contador por vocal, todos a 0
for (int k = 0; k < texto.length(); k++) { // k: la i ya es el contador de la vocal i
switch (texto.charAt(k)) {
case 'a', 'á' -> a++;
case 'e', 'é' -> e++;
case 'i', 'í' -> i++;
case 'o', 'ó' -> o++;
case 'u', 'ú', 'ü' -> u++;
default -> { } // consonantes, espacios, dígitos: nada
}
}
int total = a + e + i + o + u;
System.out.println("--- Resultado ---");
System.out.println("a: " + a + " e: " + e + " i: " + i + " o: " + o + " u: " + u);
System.out.println("Total de vocales: " + total);
if (total == 0) {
System.out.println("No hay vocales.");
} else {
// La más repetida: se empieza suponiendo la a y se compara con las demás (> y no >=: en empate gana la primera)
char masRepetida = 'a';
int maximo = a;
if (e > maximo) { masRepetida = 'e'; maximo = e; }
if (i > maximo) { masRepetida = 'i'; maximo = i; }
if (o > maximo) { masRepetida = 'o'; maximo = o; }
if (u > maximo) { masRepetida = 'u'; maximo = u; }
System.out.println("La más repetida: " + masRepetida + " (" + maximo + " veces)");
}
sc.close();
}
}
Por qué está hecho así:
toLowerCase()una vez, fuera del bucle. Si lo hicieras dentro (Character.toLowerCase(c)en cada vuelta) también funcionaría, pero así elswitchsolo tiene que mirar minúsculas y no hay nada que repetir.- El índice se llama
k. Los contadoresa,e,i,o,ullevan el nombre de su vocal, yiya está ocupada. Si elforusaraint i,javacdiríavariable i is already defined in method main(String[]). switchcon flechas y varios valores por caso.case 'a', 'á' -> a++;junta la vocal con su tilde. Eldefault -> { }vacío deja claro que el resto de caracteres se ignoran a propósito.>y no>=para la más repetida. Con «programacion» laay laoempatan a 2. Con>, laono supera a laay gana la primera (como pide el enunciado). Con>=, ganaría la última de las empatadas.
k | carácter | caso | a | i | o |
|---|---|---|---|---|---|
| 2 | o | 'o' | 0 | 0 | 1 |
| 5 | a | 'a' | 1 | 0 | 1 |
| 7 | a | 'a' | 2 | 0 | 1 |
| 9 | i | 'i' | 2 | 1 | 1 |
| 10 | o | 'o' | 2 | 1 | 2 |
(Las vueltas de las consonantes van al default y no cambian nada; total: 2 + 1 + 2 = 5.)
Solución Ejercicio 2
import java.util.Scanner;
/**
* Notas con valor centinela: se piden notas hasta que llegue -1. Acumulador para la media,
* contadores y máximo/mínimo SIN guardar las notas (sin arrays).
*/
public class NotasCentinela {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("=== NOTAS DE LA ASIGNATURA ===");
System.out.println("Escribe las notas una a una (de 0 a 10). Escribe -1 para terminar.");
int cuantas = 0, aprobadas = 0;
double suma = 0;
double maxima = 0, minima = 0; // se sobrescriben con la primera nota válida
double nota;
do {
System.out.print("Nota: ");
nota = sc.nextDouble();
if (nota == -1) {
break; // el centinela no es una nota: no se cuenta
}
if (nota < 0 || nota > 10) {
System.out.println(" No vale: va de 0 a 10.");
continue; // do-while: salta a la condición del final
}
cuantas++;
suma += nota;
if (nota >= 5) {
aprobadas++;
}
if (cuantas == 1) { // la primera nota es a la vez la máxima y la mínima
maxima = nota;
minima = nota;
} else if (nota > maxima) {
maxima = nota;
} else if (nota < minima) {
minima = nota;
}
} while (true); // solo se sale con el break del centinela
System.out.println("--- Resumen ---");
if (cuantas == 0) {
System.out.println("No hay notas: no se puede calcular la media.");
} else {
System.out.println("Notas: " + cuantas + " (aprobadas: " + aprobadas + ")");
System.out.printf("Media: %.2f%n", suma / cuantas);
System.out.println("Máxima: " + maxima + " Mínima: " + minima);
}
sc.close();
}
}
Por qué está hecho así:
do-while (true)conbreak. Hay que pedir la nota antes de poder saber si es el centinela, así que el cuerpo se ejecuta al menos una vez. La salida está en medio del cuerpo (en elbreak), no en la condición: por eso la condición estrue.- El centinela no se cuenta. El
breakva antes decuantas++ysuma += nota. Si fuera después, el -1 entraría en la media. continueen las notas fuera de rango. En undo-while, salta a la condición del final (true), así que se vuelve a pedir otra nota sin contar el 11.- Máxima y mínima con la primera nota. Cuando
cuantaspasa a 1, esa nota es a la vez la máxima y la mínima; a partir de ahí, solo se cambian si una nota las supera. Elelse ifes seguro: una nota no puede ser a la vez mayor que la máxima y menor que la mínima. - Las cuentas. Notas válidas: 6, 8, 4, 9 y 7,5. Suma: 6 + 8 + 4 + 9 + 7,5 = 34,5. Media: 34,5 / 5 = 6,90. Aprobadas: todas menos el 4, es decir, 4. La máxima y la mínima salen con punto (
9.0,4.0) porque las imprime+con undouble; la media sale con coma porque esprintf.
| Tecleado | ¿Cuenta? | cuantas | suma | maxima | minima |
|---|---|---|---|---|---|
| 6 | Sí | 1 | 6 | 6 | 6 |
| 8 | Sí | 2 | 14 | 8 | 6 |
| 11 | No: continue | 2 | 14 | 8 | 6 |
| 4 | Sí | 3 | 18 | 8 | 4 |
| 9 | Sí | 4 | 27 | 9 | 4 |
| 7,5 | Sí | 5 | 34,5 | 9 | 4 |
| -1 | No: break | 5 | 34,5 | 9 | 4 |
Solución Ejercicio 3
import java.util.Scanner;
/**
* Primos en un rango: el bucle de fuera recorre los números y el de dentro busca un divisor
* hasta la raíz cuadrada (d * d <= n), cortando con break en cuanto lo encuentra.
*/
public class PrimosEnRango {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("=== NÚMEROS PRIMOS EN UN RANGO ===");
System.out.print("Desde: ");
int desde = sc.nextInt();
System.out.print("Hasta: ");
int hasta = sc.nextInt();
if (desde > hasta) {
System.out.println("Rango no válido: «desde» tiene que ser menor o igual que «hasta».");
return;
}
if (desde < 2) {
desde = 2; // ni el 0 ni el 1 son primos: se empieza en 2
}
System.out.println("--- Primos encontrados ---");
int total = 0, divisiones = 0;
String fila = "";
for (int n = desde; n <= hasta; n++) { // bucle de fuera: cada candidato
boolean esPrimo = true; // se reinicia en CADA candidato
for (int d = 2; d * d <= n; d++) { // bucle de dentro: divisores hasta la raíz
divisiones++;
if (n % d == 0) {
esPrimo = false;
break; // sale solo del bucle de dentro
}
}
if (esPrimo) {
total++;
fila += n + " ";
if (total % 5 == 0) { // cada 5 primos, una línea
System.out.println(fila.trim());
fila = "";
}
}
}
if (!fila.isEmpty()) {
System.out.println(fila.trim()); // la última línea, si quedó a medias
}
System.out.println("Total: " + total + " primos (" + divisiones + " divisiones)");
sc.close();
}
}
Por qué está hecho así:
esPrimo = truedentro del bucle de fuera. Cada candidato empieza siendo «primo hasta que se demuestre lo contrario». Si se declarara fuera, en cuanto un número no fuera primo la bandera se quedaría enfalsepara todos los siguientes.d * d <= nen lugar ded < n. Los divisores van por parejas: si 28 = 2 × 14, al probar el 2 ya lo has encontrado. Si un número tuviera un divisor mayor que su raíz, su pareja sería menor y habría salido antes. Así se ahorra la mayoría de las divisiones:
breaksale solo del bucle de dentro, que es justo lo que queremos aquí: dejar de probar divisores de este candidato y pasar al siguiente. Es el mismobreakque daba problemas en el error 2; la diferencia es lo que se quería hacer.- Las filas de cinco.
total % 5 == 0es verdadero con el 5.º, el 10.º… primo. Lo que queda a medias (el 29 en el rango 10-30) se imprime después del bucle. - Las cuentas del rango 10-30. Primos: 11, 13, 17, 19, 23 y 29, seis. Divisiones: 38. Por ejemplo, el 29 prueba 2, 3, 4 y 5 (4 divisiones); con
d < nhabrían sido 27.
n | divisores probados | ¿Primo? | divisiones acumuladas |
|---|---|---|---|
| 10 | 2 (10 % 2 = 0, break) | No | 1 |
| 11 | 2, 3 (4 × 4 = 16 > 11, para) | Sí | 3 |
| 12 | 2 (break) | No | 4 |
| 13 | 2, 3 | Sí | 6 |
Cuestionario tipo examen
Ahora ponte a prueba como en el examen. El cuestionario de Java de FP2 es así: 15 preguntas en 15 minutos sobre todo el temario de Java, de las que te tocan unas pocas de cada tema. Aquí tienes las de bucles: contesta sin ejecutar nada, corrige y lee la explicación de las que falles. Estas preguntas son también el banco del simulacro de teoría de FP2.
¿Qué número imprime este fragmento?
int n = 0; for (int i = 10; i > 0; i -= 3) n++; System.out.println(n);
Solución
Respuesta: 4
i toma los valores 10, 7, 4 y 1: cuatro vueltas. Después pasa a −2, la condición i > 0 es falsa y el bucle termina. Contar los valores de i uno a uno es la forma segura de no equivocarse en uno.
En Python tienes for i in range(10, 0, -2):. Completa el bucle de Java que hace lo mismo:
for (int i = ____; i ____ 0; i ____ 2)
Palabras:
- 0
- 10
- +=
- <
- -=
- >=
- >
Solución
for (int i = 10; i > 0; i -= 2)
range(10, 0, -2) empieza en 10, baja de 2 en 2 y no incluye el 0: 10, 8, 6, 4, 2. Por eso la condición es i > 0 (con >= se colaría el 0). El tercer argumento de range es el paso: aquí, restar 2.
¿Qué imprime este fragmento?
int k = 5;
do {
System.out.print(k);
k++;
} while (k < 3);
System.out.println();Solución
Respuesta: 5
El do-while comprueba la condición al final, así que el cuerpo se ejecuta al menos una vez aunque 5 < 3 sea falso desde el principio. Con un while normal no se imprimiría nada.
¿Qué imprime este fragmento?
for (int i = 1; i <= 6; i++) {
if (i % 2 == 0) continue;
if (i == 5) break;
System.out.print(i);
}
System.out.println();Solución
Respuesta: 13
Los pares se saltan con continue (pasan a la siguiente vuelta sin imprimir). Se imprimen el 1 y el 3; al llegar al 5, break corta el bucle entero, así que el 5 no sale.
¿Qué imprime este fragmento?
int[] v = {1, 2, 3};
for (int x : v) x = x * 10;
System.out.println(v[0] + v[1] + v[2]);660123- No compila
Solución
Respuesta: 6
En un for-each, la variable recibe una copia del valor de cada elemento (con primitivos). Para modificar el array necesitas su índice: for (int i = 0; i < v.length; i++) v[i] *= 10;.
¿Qué número imprime este fragmento?
int c = 0;
for (int i = 0; i < 4; i++)
for (int j = i; j < 4; j++)
c++;
System.out.println(c);Solución
Respuesta: 10
El bucle interno empieza en i, así que da 4 vueltas cuando i = 0, 3 cuando i = 1, 2 y 1: 4 + 3 + 2 + 1 = 10. Es el patrón de recorrer solo la mitad de una matriz (o comparar cada pareja una vez).
Indica si es verdadero o falso:
- El cuerpo de un
do-whilese ejecuta al menos una vez. - El for-each te da en cada vuelta el índice del elemento.
- Una variable declarada en la cabecera del
forno existe después del bucle. while (true)con unbreakdentro es un bucle válido.for (;;)no compila porque le faltan las tres partes.
Solución
- V — El cuerpo de un
do-whilese ejecuta al menos una vez. - F — El for-each te da en cada vuelta el índice del elemento.
- V — Una variable declarada en la cabecera del
forno existe después del bucle. - V —
while (true)con unbreakdentro es un bucle válido. - F —
for (;;)no compila porque le faltan las tres partes.
El for-each da el valor, no la posición: si necesitas el índice, usa un for clásico. Las tres partes del for son opcionales: for (;;) es un bucle infinito, igual que while (true).
¿Qué número imprime este fragmento?
int suma = 0; for (int i = 1; i <= 10; i += 2) suma += i; System.out.println(suma);
25303655
Solución
Respuesta: 25
Con paso 2 desde el 1, i vale 1, 3, 5, 7 y 9; al pasar a 11 la condición falla. La suma de los impares es 25.
Ordena lo que hace un for (inicio; condición; actualización) en sus primeras vueltas:
- Ejecuta la inicialización (una sola vez)
- Vuelve a comprobar la condición
- Ejecuta el cuerpo
- Comprueba la condición
- Ejecuta la actualización
Solución
Orden correcto:
- Ejecuta la inicialización (una sola vez)
- Comprueba la condición
- Ejecuta el cuerpo
- Ejecuta la actualización
- Vuelve a comprobar la condición
La inicialización va una sola vez al principio. Después se repite: condición → cuerpo → actualización. Si la condición es falsa desde el principio, el cuerpo no se ejecuta nunca.
Relaciona cada situación con el bucle más adecuado:
| Repetir un número de veces que ya conoces | |
| Pedir un dato hasta que sea válido (al menos una vez) | |
| Recorrer todos los elementos sin necesitar su posición | |
| Repetir mientras se cumpla algo que puede ser falso desde el principio |
Definiciones:
- switch
- while
- for-each
- do-while
- for
Solución
- Repetir un número de veces que ya conoces → for
- Pedir un dato hasta que sea válido (al menos una vez) → do-while
- Recorrer todos los elementos sin necesitar su posición → for-each
- Repetir mientras se cumpla algo que puede ser falso desde el principio → while
El for es para contar; el do-while, para «hazlo una vez y repite si hace falta» (validar entradas); el for-each, para recorrer; y el while, para condiciones que no dependen de un contador. switch no es un bucle.
¿Qué imprime este fragmento?
String s = "";
int i = 3;
while (i > 0) {
s = s + i;
i--;
}
System.out.println(s + i);Solución
Respuesta: 3210
En cada vuelta se pega i al final de s: "3", "32", "321". Cuando i llega a 0 el bucle termina, pero i sigue existiendo (se declaró fuera) y vale 0, así que se imprime 3210.
Míralo paso a paso en Python Tutor
Python Tutor (pythontutor.com) ejecuta el código línea a línea y enseña cómo cambian las variables. Elige Java en el desplegable y pega este programa, la búsqueda de primos de 10 a 15:
public class TutorPrimos {
public static void main(String[] args) {
int total = 0;
for (int n = 10; n <= 15; n++) {
boolean esPrimo = true;
for (int d = 2; d * d <= n; d++) {
if (n % d == 0) {
esPrimo = false;
break;
}
}
if (esPrimo) {
total++;
System.out.println(n + " es primo");
}
}
System.out.println("Total: " + total);
}
}
Salida:
11 es primo 13 es primo Total: 2
Qué observar paso a paso:
- Con
n = 10, el bucle de dentro da una sola vuelta:10 % 2 == 0,esPrimopasa afalsey elbreaklo saca enseguida. - Con
n = 11, pruebad = 2yd = 3; cond = 4,4 * 4 = 16ya no es<= 11y el bucle termina sinbreak:esPrimosigue entrue. - Fíjate en que
esPrimovuelve atrueal empezar cada candidato: se crea de nuevo en cada vuelta de fuera. totalsolo sube con 11 y 13: termina en 2.
Resumen
- Un bucle tiene que tener una forma de terminar: alguna variable de su condición cambia en cada vuelta (o hay un
breakque se alcanza seguro). - Recorrer un texto:
for (int k = 0; k < texto.length(); k++), con<. - Centinela: pedir, comprobar si es el valor de salida con
breaky, si no, procesarlo. El centinela nunca se cuenta. - Acumuladores y contadores, fuera del bucle y a 0; máximo y mínimo, con el primer dato real (o con
Double.MAX_VALUE/-Double.MAX_VALUE). breaksale solo del bucle más cercano; para cortar el de fuera, una bandera en su condición o una etiqueta.- En bucles anidados, lo que se reinicia en cada vuelta de fuera (como
esPrimo) se declara dentro del bucle de fuera.
Chuletario: bucles en Java
Lo esencial en 30 segundos: si sabes cuántas vueltas, for; si depende de lo que pase, while; si hay que hacerlo al menos una vez, do-while. Las posiciones van de 0 a length() - 1, así que <. Algo de la condición tiene que cambiar en cada vuelta. break sale del bucle más cercano y continue salta a la siguiente vuelta. Los acumuladores empiezan en 0; los máximos y mínimos, con el primer dato.
| Quiero… | Código | Resultado |
|---|---|---|
| Recorrer un texto | for (int k = 0; k < t.length(); k++) | posiciones 0 a length() - 1 |
| Recorrerlo al revés | for (int k = t.length() - 1; k >= 0; k--) | de la última a la 0 |
| Solo los caracteres | for (char c : t.toCharArray()) | sin índice |
| Dos índices a la vez | for (int i = 0, j = n - 1; i < j; i++, j--) | se cruzan a mitad |
| Repetir mientras se cumpla | while (intentos < MAX && !acertado) | puede no entrar nunca |
| Repetir al menos una vez | do { … } while (opcion != 0); | entra siempre |
| Leer hasta un centinela | do { x = sc.nextInt(); if (x == -1) break; … } while (true); | el -1 no se procesa |
| Saltar un dato malo | if (malo) { continue; } | vuelve a la condición |
| Salir de dos bucles | bandera en la condición de fuera, o break etiqueta; | corta los dos |
| Mínimo sin datos previos | double min = Double.MAX_VALUE; | cualquier dato es menor |
| ¿Es primo? | for (int d = 2; d * d <= n; d++) | hasta la raíz |
Plantillas de los ejercicios:
| Ejercicio | Patrón | Con estos datos | Sale |
|---|---|---|---|
| Vocales | for + switch con flechas, un contador por vocal | programacion | total 5, más repetida a (2) |
| Centinela | do-while (true) + break + continue, máx/mín con el primer dato | 6, 8, 11, 4, 9, 7,5, -1 | 5 notas, media 6,90, 9.0 / 4.0 |
| Primos | anidados, bandera reiniciada, d * d <= n + break | de 10 a 30 | 6 primos, 38 divisiones |
| Síntoma | Causa probable |
|---|---|
| El programa no termina | nada cambia la variable de la condición (falta el i++) |
StringIndexOutOfBoundsException: Index N out of bounds for length N | <= en lugar de < |
| La media incluye el -1 | el break del centinela va después de sumar |
| El mínimo sale 0 (o el máximo no cambia) | se inicializó con 0 en lugar del primer dato |
| Salen varios resultados y se quería uno | break solo sale del bucle de dentro |
| Después del primer no-primo, ninguno es primo | la bandera se declaró fuera del bucle de fuera |
variable i is already defined | el mismo nombre en dos bucles anidados (o en un contador) |
Antes de entregar, pregúntate:
- ¿Qué línea del cuerpo cambia la condición de cada bucle?
- ¿He probado el caso vacío (el -1 a la primera, un texto sin vocales, un rango sin primos)?
- ¿Mis acumuladores están fuera del bucle y lo que se reinicia, dentro?
- ¿Cada
breaksale del bucle que yo creo?
Con esto cierras los bucles. El siguiente tema es métodos en Java: el bloque que repetías tres veces en el adivino, y la comprobación de primo, se convierten en un método con nombre que se llama desde donde haga falta.
Sigue aprendiendoTodos los artículos de Java¿Te ha servido este artículo? Así puedes apoyar SergioLearns →




Simulacro del examen práctico de IC2 — diagrama de flujo, fork e hilos en C (y las capturas que no pueden faltar)