Bucles en Java — práctica con un analizador de texto, el adivino que por fin repite y un generador de patrones (y la vuelta de más que me tumbó el programa)
En el laboratorio de FP2 nos pidieron contar las letras de una frase. Facilísimo, pensé: un for que vaya de 0 hasta la longitud y listo. Lo escribí con i <= frase.length(), porque «hasta la longitud» me sonaba a «incluida la longitud». El programa imprimió todas las letras, una por una, perfectas… y en la última vuelta reventó con un StringIndexOutOfBoundsException que ocupaba media pantalla. Me había sobrado una vuelta. Ese = de más es el error más típico de los bucles, y en esta práctica lo vas a provocar a propósito, con su mensaje real, antes de escribir el programa bien.
Si vienes de la teoría de bucles en Java, ya conoces el for de tres partes, el for-each, while, do-while, break y continue. Hoy los usamos en tres programas de nivel medio: un analizador de texto que recorre una frase de Laura carácter a carácter (con índice, hacia atrás y con dos índices a la vez), el adivino de la práctica de control de flujo reescrito con un while (la promesa de aquel artículo: el mismo juego sin copiar el bloque tres veces) y un generador de patrones con un menú do-while y bucles anidados. Los datos vienen del teclado y traen sorpresas: tildes, mayúsculas, números fuera de rango y opciones que no existen.
Como en la teoría, aquí no hay arrays: tienen su propio tema más adelante. Solo aparece toCharArray() para recorrer un texto con for-each, igual que allí.
Tabla de Contenidos
Antes de empezar
Conviene tener claro:
- Las tres partes del
for: inicio, condición y avance, y en qué orden se ejecutan. - Que las posiciones de un
Stringvan de0alength() - 1, y quecharAt(i)devuelve el carácter de la posicióni. - La diferencia entre
while(puede no ejecutarse nunca) ydo-while(se ejecuta al menos una vez). - Qué hacen
break(sale del bucle) ycontinue(se salta el resto de esa vuelta).
Si alguno te suena dudoso, repasa la teoría antes de seguir.
Crea una carpeta practica_bucles con un .java por programa. Las salidas de este artículo son reales, de una única ejecución con Java 21 en un equipo en español: lo que ves 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. Y si un bucle tuyo no termina, en la terminal se para con Ctrl + C.
Programa 1: Analizador de texto
Laura escribe una frase y el programa cuenta cuántos caracteres, letras, vocales (también con tilde), mayúsculas, dígitos y espacios tiene, la escribe al revés y dice si es un palíndromo (se lee igual en los dos sentidos sin contar espacios ni mayúsculas). Lo que lo complica: hay tres recorridos distintos de la misma frase, y cada uno pide un bucle diferente.
La idea
- Contar: un
forcon índice de0alength() - 1. En cada vuelta,charAt(i)y una cadena deifque decide qué contador sube. - Al revés: el mismo
for, pero empezando por el final (length() - 1) y bajando hasta0coni--. - Palíndromo: primero se construye una versión «limpia» (solo letras, en minúscula) con un for-each, porque aquí no hace falta saber la posición. Después, dos índices a la vez:
iempieza por el principio,jpor el final, y se comparan hasta que se cruzan.
Antes de programar, escribe en un papel las posiciones de una palabra corta («Java»: J en la 0, la última a en la 3). ¿Cuánto vale length()? ¿Y la última posición? Esa diferencia de uno es todo el programa.
El código
import java.util.Scanner;
/**
* Analizador de texto: recorre una frase carácter a carácter con for e índice y con for-each,
* cuenta lo que hay y mira si es un palíndromo comparando desde los dos extremos.
*/
public class AnalizadorTexto {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("=== ANALIZADOR DE TEXTO ===");
System.out.print("Frase: ");
String frase = sc.nextLine();
// 1. Contadores: todos empiezan en 0 y cada vuelta suma donde toque
int letras = 0, vocales = 0, digitos = 0, espacios = 0, mayusculas = 0;
for (int i = 0; i < frase.length(); i++) { // < y no <=: la última posición es length() - 1
char c = frase.charAt(i);
if (Character.isLetter(c)) {
letras++;
if ("aeiouáéíóúAEIOUÁÉÍÓÚ".indexOf(c) >= 0) { // ¿está c en la lista de vocales?
vocales++;
}
if (Character.isUpperCase(c)) {
mayusculas++;
}
} else if (Character.isDigit(c)) {
digitos++;
} else if (c == ' ') {
espacios++;
}
}
System.out.println("Caracteres: " + frase.length());
System.out.println("Letras: " + letras + " (vocales: " + vocales + ", mayúsculas: " + mayusculas + ")");
System.out.println("Dígitos: " + digitos + ", espacios: " + espacios);
// 2. Al revés: recorrer de la última posición a la 0
String alReves = "";
for (int i = frase.length() - 1; i >= 0; i--) {
alReves += frase.charAt(i);
}
System.out.println("Al revés: " + alReves);
// 3. Palíndromo: primero solo letras y en minúscula (for-each: aquí no hace falta la posición)
String limpia = "";
for (char c : frase.toLowerCase().toCharArray()) {
if (Character.isLetter(c)) {
limpia += c;
}
}
// Dos índices que se acercan: i desde el principio, j desde el final. Basta con llegar a la mitad.
boolean palindromo = true;
int comparaciones = 0;
for (int i = 0, j = limpia.length() - 1; i < j; i++, j--) {
comparaciones++;
if (limpia.charAt(i) != limpia.charAt(j)) {
palindromo = false;
break; // en cuanto falla una pareja, ya no lo es
}
}
System.out.println("Solo letras: " + limpia + " (" + limpia.length() + ")");
System.out.println("¿Palíndromo? " + (palindromo ? "sí" : "no") + " (parejas comparadas: " + comparaciones + ")");
sc.close();
}
}
Salida
Con el palíndromo clásico:
=== ANALIZADOR DE TEXTO === Frase: Anita lava la tina Caracteres: 18 Letras: 15 (vocales: 8, mayúsculas: 1) Dígitos: 0, espacios: 3 Al revés: anit al aval atinA Solo letras: anitalavalatina (15) ¿Palíndromo? sí (parejas comparadas: 7)
Y con una frase de Laura que tiene tildes, mayúsculas y números:
=== ANALIZADOR DE TEXTO === Frase: Laura aprobó FP2 en 2026 Caracteres: 24 Letras: 15 (vocales: 7, mayúsculas: 3) Dígitos: 5, espacios: 4 Al revés: 6202 ne 2PF óborpa aruaL Solo letras: lauraaprobófpen (15) ¿Palíndromo? no (parejas comparadas: 1)
Comprobamos la segunda a mano. «Laura aprobó FP2 en 2026» tiene 24 caracteres. Letras: Laura (5) + aprobó (6) + FP (2) + en (2) = 15. Vocales: a, u, a, a, o, ó, e = 7 (la ó cuenta porque está en la lista). Mayúsculas: L, F y P = 3. Dígitos: 2, 2, 0, 2 y 6 = 5. Espacios: 4. Y 15 + 5 + 4 = 24: no se ha quedado ningún carácter sin contar. En el palíndromo, la primera pareja ya falla (l frente a n), así que el break corta tras una sola comparación.
Preguntas que te puedes hacer
¿Por qué i < frase.length() y no <=? Porque las posiciones empiezan en 0. Este programa corto lo hace con <= para que veas qué pasa:
public class FueraDeRango {
public static void main(String[] args) {
String palabra = "Java";
for (int i = 0; i <= palabra.length(); i++) { // <= : una vuelta de más
System.out.println(i + ": " + palabra.charAt(i));
}
System.out.println("Fin");
}
}
Salida real:
0: J
1: a
2: v
3: a
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: Index 4 out of bounds for length 4
at java.base/jdk.internal.util.Preconditions$1.apply(Preconditions.java:55)
at java.base/jdk.internal.util.Preconditions$1.apply(Preconditions.java:52)
at java.base/jdk.internal.util.Preconditions$4.apply(Preconditions.java:213)
at java.base/jdk.internal.util.Preconditions$4.apply(Preconditions.java:210)
at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:98)
at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:106)
at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:302)
at java.base/java.lang.String.checkIndex(String.java:4822)
at java.base/java.lang.StringLatin1.charAt(StringLatin1.java:46)
at java.base/java.lang.String.charAt(String.java:1544)
at FueraDeRango.main(FueraDeRango.java:5)
Las cuatro letras salen bien y en la quinta vuelta, con i = 4, charAt(4) pide una posición que no existe. El mensaje lo dice claro: Index 4 out of bounds for length 4. Las líneas at java.base/… son el camino por dentro de Java; la que importa es la última, FueraDeRango.java:5, que señala tu línea. Y fíjate en que «Fin» no llega a imprimirse.
i <= texto.length() al recorrer un String (o cualquier cosa que empiece en 0). Compila sin avisos y falla en la última vuelta. Si el bucle empieza en 0, la condición casi siempre es <.
¿Cómo funciona el bucle del palíndromo? Zoom a ese trozo:
// Dos índices que se acercan: i desde el principio, j desde el final. Basta con llegar a la mitad.
boolean palindromo = true;
int comparaciones = 0;
for (int i = 0, j = limpia.length() - 1; i < j; i++, j--) {
comparaciones++;
if (limpia.charAt(i) != limpia.charAt(j)) {
palindromo = false;
break; // en cuanto falla una pareja, ya no lo es
}
}
El for admite dos variables en el inicio (int i = 0, j = …) y dos avances separados por coma (i++, j--). Con «anitalavalatina» (15 letras), las parejas son (0,14), (1,13)… hasta (6,8): siete comparaciones. La posición 7, la v del centro, no se compara con nadie porque cuando i vale 7, j también vale 7 y i < j ya es falso.
| Vuelta | i | j | limpia.charAt(i) | limpia.charAt(j) | ¿Iguales? |
|---|---|---|---|---|---|
| 1 | 0 | 14 | a | a | Sí |
| 2 | 1 | 13 | n | n | Sí |
| 3 | 2 | 12 | i | i | Sí |
| 4 | 3 | 11 | t | t | Sí |
| 5 | 4 | 10 | a | a | Sí |
| 6 | 5 | 9 | l | l | Sí |
| 7 | 6 | 8 | a | a | Sí |
| (fin) | 7 | 7 | 7 < 7 es falso |
¿Por qué for-each para la versión limpia y for con índice para lo demás? Para limpiar solo necesitas cada letra, no su posición: for-each es más corto y no hay índice que equivocar. Para escribir al revés o comparar dos posiciones sí necesitas el índice. La regla: ¿necesitas saber dónde estás? Índice. ¿Solo qué hay? for-each.
¿Es eficiente sumar letras con += a un String? Para una frase, de sobra. Cada += crea un String nuevo, así que con un texto de miles de caracteres se nota; para eso existe StringBuilder, que verás en el tema de Strings.
"aeiouáéíóúAEIOUÁÉÍÓÚ".indexOf(c) >= 0 es una forma corta de preguntar «¿está c en esta lista?» sin escribir diez comparaciones con ||.
Pruébalo tú
- Cuenta también las palabras: son los espacios + 1… salvo que la frase tenga espacios seguidos o al principio. ¿Cómo lo arreglarías?
- Cambia la frase limpia para que conserve los dígitos y prueba con «2002»: ¿es palíndromo?
Programa 2: Adivina el número con while
En la práctica de control de flujo el adivino tenía tres intentos y el mismo bloque copiado tres veces. Ahora lo escribimos una vez dentro de un while y damos 7 intentos. El secreto es el mismo (semilla 42, el 31) para que compares. Dos reglas nuevas: los números fuera de rango no gastan intento, y al acertar se da una valoración según los intentos usados.
La idea
- Un contador (
intentos) que solo sube con los intentos válidos. - Una bandera (
acertado) que empieza enfalsey se pone atrueal acertar. - La condición del
whilejunta las dos: seguir mientras queden intentos y no se haya acertado:intentos < MAX && !acertado. - Para los números fuera de rango,
continue: vuelve a la condición sin llegar aintentos++. - Al salir del bucle hay dos motivos posibles; la bandera dice cuál fue.
Antes de programar, responde: ¿cuándo tiene que terminar el bucle? Escribe las dos situaciones («ha acertado» o «no le quedan intentos») y niégalas para obtener la condición de seguir. Es De Morgan: no (A o B) = no A y no B.
El código
import java.util.Random;
import java.util.Scanner;
/**
* Adivina el número, ahora con while: el bloque se escribe UNA vez y se repite
* hasta acertar o gastar los 7 intentos. Mismo secreto que en Control de flujo (semilla 42).
*/
public class Adivina {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
Random azar = new Random(42);
int secreto = azar.nextInt(100) + 1;
final int MAX = 7; // con 7 intentos y búsqueda por la mitad, siempre se acierta
System.out.println("=== ADIVINA EL NÚMERO (1-100) ===");
System.out.println("Tienes " + MAX + " intentos. Los números fuera de rango no cuentan.");
int intentos = 0; // contador: cuántos intentos válidos llevas
boolean acertado = false; // bandera: ¿ya lo has adivinado?
while (intentos < MAX && !acertado) { // sigue mientras queden intentos Y no hayas acertado
System.out.print("Intento " + (intentos + 1) + ": ");
int n = sc.nextInt();
if (n < 1 || n > 100) {
System.out.println("Fuera de rango: no cuenta.");
continue; // vuelve a la condición sin sumar el intento
}
intentos++; // solo llegan aquí los intentos válidos
if (n == secreto) {
acertado = true; // la condición del while será falsa en la próxima comprobación
} else if (n < secreto) {
System.out.println("Más alto.");
} else {
System.out.println("Más bajo.");
}
}
// Al salir del while hay dos motivos posibles: la bandera dice cuál fue
if (acertado) {
String nivel = intentos <= 3 ? "¡Crack!" : (intentos <= 5 ? "Bien jugado." : "Por los pelos.");
System.out.println("Era el " + secreto + ". Lo has adivinado en " + intentos + " intentos. " + nivel);
} else {
System.out.println("Sin intentos. Era el " + secreto + ".");
}
sc.close();
}
}
Salida
Una partida con un número fuera de rango en medio:
=== ADIVINA EL NÚMERO (1-100) === Tienes 7 intentos. Los números fuera de rango no cuentan. Intento 1: 50 Más bajo. Intento 2: 25 Más alto. Intento 3: 150 Fuera de rango: no cuenta. Intento 3: 37 Más bajo. Intento 4: 31 Era el 31. Lo has adivinado en 4 intentos. Bien jugado.
Fíjate en que el «Intento 3» sale dos veces: el 150 no contó, así que el siguiente sigue siendo el tercero. El dibujo separa vueltas de intentos:
Y una partida perdida, subiendo de diez en diez:
=== ADIVINA EL NÚMERO (1-100) === Tienes 7 intentos. Los números fuera de rango no cuentan. Intento 1: 10 Más alto. Intento 2: 20 Más alto. Intento 3: 30 Más alto. Intento 4: 40 Más bajo. Intento 5: 45 Más bajo. Intento 6: 50 Más bajo. Intento 7: 60 Más bajo. Sin intentos. Era el 31.
Tras el séptimo intento válido, intentos < MAX es 7 < 7, falso: el while termina con acertado en false y se imprime el mensaje de derrota.
Preguntas que te puedes hacer
¿Por qué una bandera y no break al acertar? Las dos cosas funcionan. Con break, la condición del while solo diría intentos < MAX y el motivo de salida quedaría escondido dentro del cuerpo. Con la bandera, la condición dice exactamente cuándo se juega: «quedan intentos y no has acertado». Y después del bucle, la bandera te dice por qué terminó sin tener que adivinarlo.
¿Qué hace exactamente continue aquí? Salta el resto de esa vuelta y vuelve a evaluar la condición. Como intentos++ está después del continue, el 150 no gasta intento. Ojo: si el intentos++ estuviera antes del if del rango, el 150 sí contaría.
¿Por qué 7 intentos? Porque con búsqueda «por la mitad» (50, luego 25 o 75…) cada intento descarta la mitad de los números que quedan: 100 → 50 → 25 → 13 → 7 → 4 → 2 → 1. En 7 intentos siempre llegas a uno solo (2⁷ = 128, más que 100). En la partida perdida no se buscó por la mitad, y se nota.
¿Por qué el ternario anidado para la valoración? intentos <= 3 ? "¡Crack!" : (intentos <= 5 ? "Bien jugado." : "Por los pelos.") es un if/else if/else que devuelve un texto. Con 4 intentos, la primera condición es falsa y la segunda verdadera: «Bien jugado.». Si te cuesta leerlo, escríbelo con if; el resultado es el mismo.
¿Y comparado con la versión sin bucles? Aquella tenía tres copias de unas 12 líneas y solo 3 intentos. Esta tiene un bloque y 7 intentos; para 20, cambias un número: MAX = 20.
Poner intentos++ en el sitio equivocado. Antes del continue, los números fuera de rango gastan intento; fuera del while (o sin ponerlo), intentos < MAX es siempre verdadero y el bucle solo termina si aciertas. Antes de ejecutar, pregúntate: ¿qué variable de la condición cambia en cada vuelta?
Pruébalo tú
- Quita la semilla (
new Random()) y juega varias partidas buscando por la mitad: ¿pasas alguna vez de 7? - Reescribe el bucle con
while (true)ybreakal acertar o al gastar los intentos. ¿Cuál se lee mejor?
Programa 3: Generador de patrones con validación
Un menú dibuja tres patrones de tamaño n (de 1 a 9): un triángulo de asteriscos, un marco hueco y un tablero de ajedrez. El menú se repite hasta elegir 0. Lo que lo complica: hay tres bucles a la vez (el del menú, el de las filas y el de las columnas) y break y continue dentro de un do-while.
La idea
- El menú es un
do-while: tiene que enseñarse al menos una vez, antes de saber qué opción se elige. - La opción 0 sale con
break. Las opciones y los tamaños no válidos usancontinuepara volver al menú. - Cada patrón son dos bucles anidados: el de fuera da una vuelta por fila y el de dentro, una vuelta por columna de esa fila. Lo que cambia de un patrón a otro es solo qué se escribe en cada casilla
(fila, col).
Antes de programar, dibuja el patrón de tamaño 4 en una cuadrícula con las filas y columnas numeradas desde 1. ¿Qué tienen en común las casillas con asterisco? En el triángulo, col <= fila; en el marco, estar en la primera o la última fila o columna.
El código
import java.util.Scanner;
/**
* Generador de patrones: un menú con do-while (se enseña al menos una vez) y bucles anidados:
* el de fuera recorre las filas y el de dentro, las columnas de cada fila.
*/
public class GeneradorPatrones {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int opcion;
do {
System.out.println();
System.out.println("=== GENERADOR DE PATRONES ===");
System.out.println("1. Triángulo 2. Marco 3. Tablero 0. Salir");
System.out.print("Opción: ");
opcion = sc.nextInt();
if (opcion == 0) {
break; // sale del do-while sin pedir tamaño
}
if (opcion < 1 || opcion > 3) {
System.out.println("Opción no válida.");
continue; // en un do-while, continue salta a la condición del final
}
System.out.print("Tamaño (1-9): ");
int n = sc.nextInt();
if (n < 1 || n > 9) {
System.out.println("Tamaño no válido.");
continue;
}
for (int fila = 1; fila <= n; fila++) { // una vuelta por fila
String linea = "";
for (int col = 1; col <= n; col++) { // una vuelta por columna, en cada fila
if (opcion == 1) {
linea += (col <= fila) ? "* " : ""; // la fila 1 tiene 1 asterisco, la 2 tiene 2...
} else if (opcion == 2) {
boolean borde = fila == 1 || fila == n || col == 1 || col == n;
linea += borde ? "# " : " "; // dentro del marco, espacios
} else {
linea += ((fila + col) % 2 == 0) ? "# " : ". "; // suma par: casilla oscura
}
}
System.out.println(linea.stripTrailing()); // quita el espacio sobrante del final
}
} while (opcion != 0);
System.out.println("Hasta luego.");
sc.close();
}
}
Salida
Una sesión completa: triángulo de 4, tablero de 5, un tamaño no válido, marco de 4, una opción que no existe y salir.
=== GENERADOR DE PATRONES === 1. Triángulo 2. Marco 3. Tablero 0. Salir Opción: 1 Tamaño (1-9): 4 * * * * * * * * * * === GENERADOR DE PATRONES === 1. Triángulo 2. Marco 3. Tablero 0. Salir Opción: 3 Tamaño (1-9): 5 # . # . # . # . # . # . # . # . # . # . # . # . # === GENERADOR DE PATRONES === 1. Triángulo 2. Marco 3. Tablero 0. Salir Opción: 2 Tamaño (1-9): 12 Tamaño no válido. === GENERADOR DE PATRONES === 1. Triángulo 2. Marco 3. Tablero 0. Salir Opción: 2 Tamaño (1-9): 4 # # # # # # # # # # # # === GENERADOR DE PATRONES === 1. Triángulo 2. Marco 3. Tablero 0. Salir Opción: 7 Opción no válida. === GENERADOR DE PATRONES === 1. Triángulo 2. Marco 3. Tablero 0. Salir Opción: 0 Hasta luego.
Comprobamos el tablero: en la fila 1, columna 1, 1 + 1 = 2 es par, así que #; en la fila 1, columna 2, 1 + 2 = 3 es impar, .. Al bajar de fila la suma cambia de paridad, por eso cada fila empieza al revés que la anterior.
Preguntas que te puedes hacer
¿Cuántas veces se ejecuta la línea de dentro? Para un tamaño n, el bucle de fuera da n vueltas y, en cada una, el de dentro da otras n: n × n. Con el tablero de 5, 25 casillas. Este zoom es el corazón del programa:
for (int fila = 1; fila <= n; fila++) { // una vuelta por fila
String linea = "";
for (int col = 1; col <= n; col++) { // una vuelta por columna, en cada fila
if (opcion == 1) {
linea += (col <= fila) ? "* " : ""; // la fila 1 tiene 1 asterisco, la 2 tiene 2...
} else if (opcion == 2) {
boolean borde = fila == 1 || fila == n || col == 1 || col == n;
linea += borde ? "# " : " "; // dentro del marco, espacios
} else {
linea += ((fila + col) % 2 == 0) ? "# " : ". "; // suma par: casilla oscura
}
}
System.out.println(linea.stripTrailing()); // quita el espacio sobrante del final
fila | col recorre | col <= fila en… | Línea del triángulo |
|---|---|---|---|
| 1 | 1, 2, 3, 4 | 1 | * |
| 2 | 1, 2, 3, 4 | 1, 2 | * * |
| 3 | 1, 2, 3, 4 | 1, 2, 3 | * * * |
| 4 | 1, 2, 3, 4 | 1, 2, 3, 4 | * * * * |
¿Por qué linea se declara dentro del bucle de fuera? Porque cada fila empieza vacía. Si estuviera fuera, la fila 2 se escribiría pegada a la 1 y el triángulo se convertiría en una sola línea cada vez más larga.
¿Qué hace continue dentro de un do-while? Salta a la condición del final (while (opcion != 0)), no al principio del cuerpo. Con el tamaño 12, opcion vale 2: la condición es verdadera y el menú vuelve a salir. Por eso funciona sin pedir nada más.
¿Y por qué el 0 sale con break y no esperando a la condición? Porque después de leer la opción viene la pregunta del tamaño. Sin el break, al elegir 0 el programa preguntaría «Tamaño (1-9):» antes de salir. El break corta ahí mismo.
¿Para qué stripTrailing()? Cada casilla añade su carácter más un espacio, así que cada línea acaba en un espacio que no se ve pero existe. stripTrailing() lo quita antes de imprimir.
Usar la misma variable en los dos bucles (for (int i…) dentro de otro for (int i…)). Java no lo deja compilar: variable i is already defined in method main(String[]). Usa nombres que digan qué recorren: fila y col.
Pruébalo tú
- Añade la opción 4, un triángulo invertido (la fila 1 con
nasteriscos). Pista: cambia una sola condición. - Cuenta en una variable cuántos
#se han dibujado en la sesión entera e imprímelo al salir.
Errores típicos en esta práctica
<=en lugar de<al recorrer un texto. Una vuelta de más yStringIndexOutOfBoundsException.- Un bucle cuya condición nunca cambia. Si ninguna variable de la condición cambia dentro del cuerpo, el bucle no termina.
continueantes de actualizar el contador. La vuelta se salta la línea que hacía avanzar el bucle.- Declarar el acumulador en el sitio equivocado. Dentro del bucle se reinicia en cada vuelta; fuera, se arrastra de una fila a otra.
- Confundir
breakconcontinue. El primero termina el bucle; el segundo solo la vuelta actual. - El mismo nombre en dos bucles anidados. No compila; y si lo esquivas con otro bloque, te costará saber qué recorre cada uno.
Míralo paso a paso en Python Tutor
Python Tutor (pythontutor.com) ejecuta el código línea a línea y dibuja las variables. Elige Java en el desplegable y pega este programa, un triángulo de 3 filas con un contador de las vueltas del bucle de dentro:
public class TutorAnidados {
public static void main(String[] args) {
int vueltasDentro = 0;
for (int fila = 1; fila <= 3; fila++) {
String linea = "";
for (int col = 1; col <= fila; col++) {
linea += "*";
vueltasDentro++;
}
System.out.println(linea);
}
System.out.println("Vueltas del bucle de dentro: " + vueltasDentro);
}
}
Salida:
* ** *** Vueltas del bucle de dentro: 6
Qué observar paso a paso:
- Cada vez que entra en el bucle de dentro,
colvuelve a valer 1: elforde dentro se crea de nuevo en cada fila. - En la fila 1 el de dentro da 1 vuelta; en la 2, dos; en la 3, tres. Mira cómo crece
lineay se reinicia a""al cambiar de fila. vueltasDentrono se reinicia nunca (está fuera de los dos bucles): termina en 1 + 2 + 3 = 6.- Fíjate en el último paso de cada bucle: la condición se evalúa una vez más que el cuerpo (con
col = 2en la fila 1,2 <= 1es falso y sale).
Resumen y siguiente paso
- Para recorrer un texto con índice:
for (int i = 0; i < texto.length(); i++). La última posición eslength() - 1. - Para recorrerlo al revés: empezar en
length() - 1y bajar coni--mientrasi >= 0. - Dos índices que se acercan (
i++, j--mientrasi < j) comparan un texto consigo mismo en la mitad de vueltas. - Un
whilecon contador y bandera (intentos < MAX && !acertado) dice en su condición exactamente cuándo se sigue. continuesalta a la siguiente comprobación de la condición; en undo-while, a la del final.- En bucles anidados, la línea de dentro se ejecuta (vueltas de fuera) × (vueltas de dentro) veces.
Checklist: ¿lo has practicado?
- ¿Has ejecutado los tres programas y comprobado las salidas?
- ¿Sabes explicar por qué
i <= texto.length()falla en la última vuelta? - ¿Sabrías decir cuántas comparaciones hace el palíndromo con una palabra de 9 letras?
- ¿Sabes dónde tiene que ir
intentos++para que los números fuera de rango no cuenten? - ¿Has intentado los «Pruébalo tú» sin mirar la teoría?
Si has respondido que sí a casi todo, estás listo para los ejercicios de bucles en Java, donde ya no te doy el código hecho. ¡Nos vemos allí!
Siguiente paso: ejerciciosBucles en Java — ejercicios con vocales, notas hasta el -1 y primos en un rango (y el bucle que se me colgó a mí)¿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)