Bucles en Java — práctica con texto, estadísticas y patrones
Hay un ejercicio del laboratorio de FP2 que parece trivial hasta que lo intentas: contar cuántas vocales tiene una frase. En Python era for c in texto: y ya está, sin pensar en nada más. En Java lo primero que haces, casi por instinto, es escribir for (char c : texto) y el compilador te devuelve un error que no entiendes: «for-each not applicable to type ‘String'». Ahí es cuando te acuerdas de que en Java un String no se puede recorrer directamente, y hay que buscar la vuelta.
Esa vuelta es justo el tema de esta práctica. Vamos a recorrer texto carácter a carácter de las dos formas que existen en Java, y de paso vas a escribir tres programas que combinan todo lo que ya sabes de bucles: for, for-each, while y do-while.
Abre VS Code, crea una carpeta practica_bucles y un fichero .java para cada programa.
Tabla de Contenidos
Bucles en Java práctica — Programa 1: Analizador de texto
Este programa cuenta letras, vocales, dígitos y espacios de una frase, usando las dos formas de recorrer un String que existen en Java. Es el ejercicio que resuelve la duda del principio.
import java.util.Scanner;
public class AnalizadorTexto {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("=== ANALIZADOR DE TEXTO ===");
System.out.println();
System.out.print("Escribe una frase: ");
String frase = sc.nextLine();
// FORMA 1 — con charAt() y un for con índice
// Es la más directa cuando necesitas saber también la posición
int letras = 0, digitos = 0, espacios = 0, mayusculas = 0;
for (int i = 0; i < frase.length(); i++) {
char c = frase.charAt(i); // el carácter en la posición i
if (Character.isLetter(c)) {
letras++;
if (Character.isUpperCase(c)) {
mayusculas++;
}
} else if (Character.isDigit(c)) {
digitos++;
} else if (c == ' ') {
espacios++;
}
}
// FORMA 2 — con toCharArray() y for-each
// Más limpia cuando solo te interesa el carácter, no su posición
int vocales = 0;
for (char c : frase.toLowerCase().toCharArray()) {
// toLowerCase() antes de comparar — así "A" y "a" cuentan igual
if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u') {
vocales++;
}
}
System.out.println();
System.out.println("--- Resultado ---");
System.out.printf("Longitud total: %d caracteres%n", frase.length());
System.out.printf("Letras: %d%n", letras);
System.out.printf(" De las cuales, mayúsculas: %d%n", mayusculas);
System.out.printf("Vocales: %d%n", vocales);
System.out.printf("Dígitos: %d%n", digitos);
System.out.printf("Espacios: %d%n", espacios);
// Palíndromo — comprobamos leyendo desde los dos extremos a la vez
String limpio = frase.toLowerCase().replace(" ", "");
boolean esPalindromo = true;
for (int i = 0; i < limpio.length() / 2; i++) {
// Comparamos el carácter i-ésimo desde el principio con el i-ésimo desde el final
if (limpio.charAt(i) != limpio.charAt(limpio.length() - 1 - i)) {
esPalindromo = false;
break; // en cuanto encontramos una diferencia, no hace falta seguir
}
}
System.out.printf("¿Es palíndromo? %s%n", esPalindromo ? "Sí" : "No");
sc.close();
}
}
Pruébalo con «Anita lava la tina» y confirma que el programa lo detecta como palíndromo. El bucle que lo comprueba solo recorre hasta la mitad del texto (limpio.length() / 2) porque comparar la segunda mitad sería repetir el mismo trabajo dos veces — si el primer carácter coincide con el último, y el segundo con el penúltimo, ya sabes que el resto también coincidirá si sigues ese patrón.
for (char c : frase) no compila. Un String no es directamente recorrible con for-each en Java — solo lo son los arrays y las colecciones. Para usar for-each con texto, primero tienes que convertirlo con frase.toCharArray(), que sí devuelve un array de char.
Bucles en Java práctica — Programa 2: Estadísticas de un array de notas
Aquí trabajas con bucles sobre números en lugar de texto: mínimo, máximo, media y desviación respecto a la media, todo con for-each y for con índice según lo que necesites en cada momento.
import java.util.Scanner;
public class EstadisticasNotas {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("=== ESTADÍSTICAS DE NOTAS ===");
System.out.println();
System.out.print("¿Cuántas notas vas a introducir? ");
int n = sc.nextInt();
double[] notas = new double[n];
for (int i = 0; i < n; i++) {
System.out.printf("Nota %d: ", i + 1);
notas[i] = sc.nextDouble();
}
// Suma con for-each — no necesitamos el índice, solo el valor
double suma = 0;
for (double nota : notas) {
suma += nota;
}
double media = suma / n;
// Mínimo y máximo — empezamos asumiendo que el primero es ambos
// y vamos comparando con el resto
double minimo = notas[0];
double maximo = notas[0];
for (double nota : notas) {
if (nota < minimo) minimo = nota;
if (nota > maximo) maximo = nota;
}
// Cuántas notas se alejan más de 1 punto de la media
// Aquí sí necesitamos el índice, para poder decir cuál es
int alejadas = 0;
for (int i = 0; i < n; i++) {
double distancia = Math.abs(notas[i] - media);
if (distancia > 1.0) {
alejadas++;
}
}
System.out.println();
System.out.println("--- Resultado ---");
System.out.printf("Media: %.2f%n", media);
System.out.printf("Mínimo: %.2f%n", minimo);
System.out.printf("Máximo: %.2f%n", maximo);
System.out.printf("Rango: %.2f%n", maximo - minimo);
System.out.printf("Notas a más de 1 punto de la media: %d de %d%n", alejadas, n);
sc.close();
}
}
Fíjate en el patrón para el mínimo y el máximo: no hace falta ningún truco especial, solo asumir que el primer elemento es el mínimo y el máximo a la vez, y corregir esa suposición según vas mirando el resto del array. Es el mismo patrón que usarás para buscar el elemento más caro o más barato en cualquier lista de datos.
Cuando necesites el valor de cada elemento y nada más, usa for-each. Cuando necesites saber en qué posición está algo, o comparar una posición con otra (como con el palíndromo del programa anterior), necesitas el índice, así que usa el for con contador.
Bucles en Java práctica — Programa 3: Generador de patrones con validación
El clásico de los bucles anidados, pero con una vuelta de tuerca: el usuario elige qué patrón quiere ver con un menú, así que combinas do-while, switch y bucles for anidados en un mismo programa.
import java.util.Scanner;
public class GeneradorPatrones {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("=== GENERADOR DE PATRONES ===");
int opcion;
do {
System.out.println("\n1. Triángulo");
System.out.println("2. Pirámide");
System.out.println("3. Tablero de ajedrez");
System.out.println("4. Salir");
System.out.print("Opción: ");
opcion = sc.nextInt();
if (opcion == 4) {
System.out.println("Hasta luego");
break; // salimos del do-while sin pedir el tamaño
}
System.out.print("Tamaño (3-10): ");
int n = sc.nextInt();
// Validamos antes de dibujar nada — si el tamaño no vale, avisamos y volvemos al menú
if (n < 3 || n > 10) {
System.out.println("✗ El tamaño debe estar entre 3 y 10");
continue; // salta directamente a la siguiente vuelta del do-while
}
System.out.println();
switch (opcion) {
case 1:
for (int i = 1; i <= n; i++) {
for (int j = 0; j < i; j++) {
System.out.print("* ");
}
System.out.println();
}
break;
case 2:
for (int i = 1; i <= n; i++) {
// Espacios para centrar — decrecen mientras los asteriscos crecen
for (int s = 0; s < n - i; s++) {
System.out.print(" ");
}
for (int j = 0; j < i; j++) {
System.out.print("* ");
}
System.out.println();
}
break;
case 3:
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
// (i + j) par en una casilla, impar en la otra — el truco del ajedrez
if ((i + j) % 2 == 0) {
System.out.print("■ ");
} else {
System.out.print("□ ");
}
}
System.out.println();
}
break;
default:
System.out.println("✗ Opción no válida");
}
} while (true);
sc.close();
}
}
El (i + j) % 2 == 0 del tablero de ajedrez es el patrón que más cuesta ver a primera vista, así que merece una explicación aparte. Cuando la suma de la fila y la columna es par, pintamos una casilla; cuando es impar, la otra. Como fila y columna van cambiando juntas en los dos bucles anidados, ese resultado par-impar se va alternando solo, casilla a casilla, y así aparece el patrón de ajedrez sin tener que llevar la cuenta de nada más.
continue salta directamente a la siguiente vuelta del bucle sin ejecutar el resto del código de esa vuelta. En este programa, si el tamaño no es válido, continue te devuelve al principio del do-while — es decir, al menú — sin intentar dibujar nada con un tamaño incorrecto.
Visualízalo con Python Tutor
Selecciona Java en el desplegable y pega en pythontutor.com:
public class Demo {
public static void main(String[] args) {
String texto = "ana";
// Comprobación de palíndromo, paso a paso
boolean esPalindromo = true;
for (int i = 0; i < texto.length() / 2; i++) {
char desdeElPrincipio = texto.charAt(i);
char desdeElFinal = texto.charAt(texto.length() - 1 - i);
if (desdeElPrincipio != desdeElFinal) {
esPalindromo = false;
break;
}
}
System.out.println("¿Palíndromo? " + esPalindromo);
// Mínimo y máximo de un array
int[] numeros = {7, 2, 9, 4};
int minimo = numeros[0];
int maximo = numeros[0];
for (int n : numeros) {
if (n < minimo) minimo = n;
if (n > maximo) maximo = n;
}
System.out.println("Mínimo: " + minimo + ", Máximo: " + maximo);
}
}
Ejecuta paso a paso y fíjate en dos cosas. En la comprobación del palíndromo, observa cómo texto.length() / 2 limita el bucle a una sola vuelta con «ana» (longitud 3, así que solo compara la posición 0 con la 2, y la posición del medio no necesita comparación consigo misma). Y en el mínimo y máximo, mira cómo minimo y maximo empiezan los dos con el mismo valor, 7, y se van separando según el for-each va revisando 2, 9 y 4 uno detrás de otro.
Resumen y siguiente paso
En esta práctica recorriste texto de las dos formas posibles en Java, calculaste estadísticas sobre un array combinando for y for-each según lo que necesitabas en cada momento, y controlaste un menú completo con do-while, switch, break y continue trabajando juntos. La próxima vez que el compilador te diga que no puedes hacer for-each sobre un String, ya sabes exactamente qué falta.
En el siguiente artículo tienes ejercicios para resolver por tu cuenta.
Siguiente paso: ejerciciosBucles en Java — ejercicios con vocales, notas y el bucle que se me colgó a mí