Bucles: for, while, do-while
Introducción
Los bucles son estructuras fundamentales en la programación que nos permiten ejecutar un bloque de código repetidamente mientras se cumpla una determinada condición. Gracias a ellos, podemos automatizar tareas repetitivas, procesar colecciones de datos y crear algoritmos eficientes sin tener que escribir el mismo código una y otra vez.
En Java, disponemos de tres tipos principales de bucles: for
, while
y do-while
, cada uno con características particulares que los hacen más adecuados para diferentes situaciones. En este artículo aprenderás cómo funcionan estos bucles, cuándo utilizar cada uno de ellos y las mejores prácticas para implementarlos correctamente en tus programas.
El bucle for
El bucle for
es probablemente el más utilizado en Java cuando conocemos de antemano el número de iteraciones que necesitamos realizar o cuando trabajamos con colecciones.
Sintaxis básica
for (inicialización; condición; incremento) {
// Código a ejecutar en cada iteración
}
Los componentes del bucle for
son:
- Inicialización: Se ejecuta una sola vez al inicio del bucle.
- Condición: Se evalúa antes de cada iteración; si es
true
, el bucle continúa. - Incremento: Se ejecuta después de cada iteración.
Ejemplo simple
public class EjemploFor {
public static void main(String[] args) {
// Imprimir los números del 1 al 5
for (int i = 1; i <= 5; i++) {
System.out.println("Número: " + i);
}
}
}
Cuando ejecutes este programa, verás:
Número: 1
Número: 2
Número: 3
Número: 4
Número: 5
Bucle for en orden descendente
También podemos contar hacia atrás utilizando un bucle for
:
public class ForDescendente {
public static void main(String[] args) {
// Cuenta regresiva desde 10 hasta 1
for (int i = 10; i >= 1; i--) {
System.out.println("Cuenta atrás: " + i);
}
System.out.println("¡Despegue!");
}
}
Bucle for con incremento personalizado
Podemos modificar el incremento para saltar números:
public class ForIncrementoPersonalizado {
public static void main(String[] args) {
// Imprimir los números pares del 2 al 10
for (int i = 2; i <= 10; i += 2) {
System.out.println("Número par: " + i);
}
}
}
Bucle for anidado
Los bucles for
pueden anidarse para trabajar con estructuras bidimensionales como matrices:
public class ForAnidado {
public static void main(String[] args) {
// Crear un patrón de asteriscos (una matriz de 5x5)
for (int fila = 1; fila <= 5; fila++) {
for (int columna = 1; columna <= 5; columna++) {
System.out.print("* ");
}
System.out.println(); // Salto de línea al final de cada fila
}
}
}
Este código imprimirá un cuadrado de asteriscos de 5x5:
* * * * *
* * * * *
* * * * *
* * * * *
* * * * *
El bucle while
El bucle while
ejecuta un bloque de código mientras una condición específica sea verdadera. A diferencia del bucle for
, no tiene una variable de control integrada, por lo que es ideal cuando no sabemos exactamente cuántas iteraciones necesitaremos.
Sintaxis básica
while (condición) {
// Código a ejecutar mientras la condición sea verdadera
}
Ejemplo simple
public class EjemploWhile {
public static void main(String[] args) {
int contador = 1;
while (contador <= 5) {
System.out.println("Iteración número: " + contador);
contador++; // Incrementamos el contador para evitar un bucle infinito
}
}
}
Ejemplo práctico: adivinar un número
import java.util.Scanner;
import java.util.Random;
public class JuegoAdivinanza {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
Random random = new Random();
int numeroSecreto = random.nextInt(100) + 1; // Número entre 1 y 100
int intentos = 0;
int adivinanza = 0;
System.out.println("He pensado un número entre 1 y 100. ¡Adivínalo!");
while (adivinanza != numeroSecreto) {
System.out.print("Introduce tu número: ");
adivinanza = scanner.nextInt();
intentos++;
if (adivinanza < numeroSecreto) {
System.out.println("El número secreto es mayor.");
} else if (adivinanza > numeroSecreto) {
System.out.println("El número secreto es menor.");
} else {
System.out.println("¡Correcto! Has adivinado el número en " + intentos + " intentos.");
}
}
scanner.close();
}
}
En este juego de adivinanza, no sabemos cuántos intentos necesitará el usuario para adivinar el número, por lo que un bucle while
es más apropiado que un for
.
El bucle do-while
El bucle do-while
es similar al while
, pero con una diferencia crucial: la condición se evalúa al final de cada iteración, lo que garantiza que el bloque de código se ejecute al menos una vez, incluso si la condición inicialmente es falsa.
Sintaxis básica
do {
// Código a ejecutar al menos una vez y luego mientras la condición sea verdadera
} while (condición);
Ejemplo simple
public class EjemploDoWhile {
public static void main(String[] args) {
int contador = 1;
do {
System.out.println("Iteración número: " + contador);
contador++;
} while (contador <= 5);
}
}
Ejemplo práctico: menú de opciones
import java.util.Scanner;
public class MenuOpciones {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int opcion;
do {
System.out.println("\n--- MENÚ PRINCIPAL ---");
System.out.println("1. Ver usuarios");
System.out.println("2. Añadir usuario");
System.out.println("3. Eliminar usuario");
System.out.println("0. Salir");
System.out.print("Selecciona una opción: ");
opcion = scanner.nextInt();
switch (opcion) {
case 1:
System.out.println("Mostrando lista de usuarios...");
break;
case 2:
System.out.println("Añadiendo nuevo usuario...");
break;
case 3:
System.out.println("Eliminando usuario...");
break;
case 0:
System.out.println("Saliendo del programa...");
break;
default:
System.out.println("Opción no válida. Inténtalo de nuevo.");
}
} while (opcion != 0);
scanner.close();
System.out.println("¡Programa finalizado!");
}
}
Este ejemplo muestra un menú que se presenta al menos una vez, y sigue mostrándose después de cada operación hasta que el usuario elija la opción de salir. El bucle do-while
es perfecto para este tipo de situaciones.
El bucle for-each
Desde Java 5, se introdujo el bucle for
mejorado, también conocido como bucle "for-each". Esta estructura está diseñada específicamente para recorrer colecciones y arrays de manera más sencilla y legible.
Sintaxis básica
for (TipoDato elemento : coleccion) {
// Código a ejecutar para cada elemento
}
Ejemplo con array
public class ForEachEjemplo {
public static void main(String[] args) {
String[] frutas = {"Manzana", "Plátano", "Naranja", "Fresa", "Kiwi"};
// Recorremos el array con for-each
for (String fruta : frutas) {
System.out.println("Me gusta la " + fruta.toLowerCase());
}
}
}
Este código es más claro y conciso que el equivalente con un bucle for
tradicional:
for (int i = 0; i < frutas.length; i++) {
System.out.println("Me gusta la " + frutas[i].toLowerCase());
}
La principal limitación del bucle for-each
es que no tenemos acceso directo al índice del elemento, y no podemos modificar la colección mientras la recorremos.
Control de flujo en bucles
Java proporciona varias instrucciones para controlar el flujo de ejecución dentro de los bucles:
break
La instrucción break
termina inmediatamente el bucle más interno que la contiene y continúa la ejecución desde la siguiente línea después del bucle.
public class EjemploBreak {
public static void main(String[] args) {
for (int i = 1; i <= 10; i++) {
if (i == 6) {
System.out.println("¡Encontrado el número 6! Saliendo del bucle...");
break; // Sale del bucle cuando i es 6
}
System.out.println("Número actual: " + i);
}
System.out.println("Bucle finalizado");
}
}
continue
La instrucción continue
salta a la siguiente iteración del bucle más interno, omitiendo el resto del código en la iteración actual.
public class EjemploContinue {
public static void main(String[] args) {
// Imprimir solo los números impares del 1 al 10
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) {
continue; // Salta los números pares
}
System.out.println("Número impar: " + i);
}
}
}
Etiquetas (labels)
Las etiquetas permiten controlar bucles anidados especificando a qué bucle nos referimos con las instrucciones break
y continue
.
public class EjemploEtiquetas {
public static void main(String[] args) {
// Buscar una coordenada específica en una matriz 5x5
int filaObjetivo = 3;
int columnaObjetivo = 2;
boolean encontrado = false;
bucleExterno: // Etiqueta para el bucle externo
for (int fila = 1; fila <= 5; fila++) {
for (int columna = 1; columna <= 5; columna++) {
System.out.println("Comprobando posición: [" + fila + "," + columna + "]");
if (fila == filaObjetivo && columna == columnaObjetivo) {
System.out.println("¡Objetivo encontrado en [" + fila + "," + columna + "]!");
encontrado = true;
break bucleExterno; // Sale de ambos bucles
}
}
}
if (encontrado) {
System.out.println("Búsqueda exitosa.");
} else {
System.out.println("Objetivo no encontrado.");
}
}
}
En este ejemplo, la etiqueta bucleExterno
nos permite salir de ambos bucles a la vez cuando encontramos nuestro objetivo, en lugar de salir solo del bucle interno.
Bucles infinitos y cómo evitarlos
Un bucle infinito es aquel que nunca termina porque su condición de salida nunca se cumple. Aunque a veces son útiles (por ejemplo, en sistemas que deben ejecutarse continuamente), generalmente son errores de programación.
Ejemplo de bucle infinito
// No ejecutes este código sin una estrategia para detenerlo
while (true) {
System.out.println("¡Este mensaje se imprimirá infinitamente!");
}
Para evitar bucles infinitos:
- Asegúrate de que la condición del bucle eventualmente cambie a falsa
- Verifica que las variables de control se actualicen correctamente
- Considera añadir una condición de salida de seguridad o un contador límite
// Ejemplo seguro: bucle con límite de iteraciones
int contador = 0;
int limite = 1000000;
while (true) {
System.out.println("Iteración: " + contador);
contador++;
if (contador >= limite) {
System.out.println("Alcanzado límite de seguridad. Saliendo del bucle.");
break;
}
}
Ejemplo integrado: Procesamiento de notas
Veamos un ejemplo completo que integra varios tipos de bucles para procesar un conjunto de notas de estudiantes:
import java.util.Scanner;
public class ProcesadorNotas {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("¿Cuántos estudiantes hay en la clase? ");
int numeroEstudiantes = scanner.nextInt();
// Array para almacenar las notas
double[] notas = new double[numeroEstudiantes];
// Bucle for para solicitar las notas
for (int i = 0; i < numeroEstudiantes; i++) {
System.out.print("Introduce la nota del estudiante " + (i + 1) + ": ");
double nota;
// Bucle do-while para validar que la nota esté entre 0 y 10
do {
nota = scanner.nextDouble();
if (nota < 0 || nota > 10) {
System.out.print("La nota debe estar entre 0 y 10. Inténtalo de nuevo: ");
}
} while (nota < 0 || nota > 10);
notas[i] = nota;
}
// Calcular estadísticas usando un bucle while
int i = 0;
double suma = 0;
double notaMaxima = notas[0];
double notaMinima = notas[0];
while (i < notas.length) {
suma += notas[i];
if (notas[i] > notaMaxima) {
notaMaxima = notas[i];
}
if (notas[i] < notaMinima) {
notaMinima = notas[i];
}
i++;
}
double media = suma / numeroEstudiantes;
// Mostrar las notas usando for-each
System.out.println("\nNotas registradas:");
int estudianteNum = 1;
for (double nota : notas) {
System.out.println("Estudiante " + estudianteNum + ": " + nota);
estudianteNum++;
}
// Mostrar estadísticas
System.out.println("\nEstadísticas:");
System.out.println("Media de la clase: " + media);
System.out.println("Nota más alta: " + notaMaxima);
System.out.println("Nota más baja: " + notaMinima);
scanner.close();
}
}
Este ejemplo muestra:
- Uso de
for
para recorrer un array con acceso al índice - Uso de
do-while
para validación de entrada - Uso de
while
para cálculos acumulativos - Uso de
for-each
para mostrar resultados
Comparación de los diferentes tipos de bucles
Bucle | Cuando usarlo | Ventajas | Desventajas |
---|---|---|---|
for |
Cuando sabes el número exacto de iteraciones | Compacto, con inicialización y actualización integradas | Menos flexible para condiciones complejas |
while |
Cuando no sabes cuántas iteraciones necesitarás | Simple y claro cuando la condición es lo más importante | Requiere inicialización externa y actualización manual |
do-while |
Cuando necesitas ejecutar el código al menos una vez | Garantiza al menos una ejecución | Puede ser confuso para principiantes |
for-each |
Para recorrer colecciones completas | Muy legible y conciso | No se puede acceder al índice ni modificar la colección |
Resumen
Los bucles son estructuras fundamentales que nos permiten ejecutar código repetidamente mientras se cumpla una condición determinada. En Java, disponemos principalmente de tres tipos de bucles: for
, while
y do-while
, además del bucle for-each
para recorrer colecciones.
El bucle for
es ideal cuando conocemos el número de iteraciones de antemano, el bucle while
cuando la condición de continuación es lo más importante, y el bucle do-while
cuando necesitamos que el código se ejecute al menos una vez. Además, disponemos de instrucciones como break
y continue
para controlar el flujo dentro de los bucles.
Elegir el tipo de bucle adecuado para cada situación y aplicar buenas prácticas nos ayudará a escribir código más eficiente, legible y mantenible. En el próximo artículo, exploraremos las sentencias de salto en Java, que complementan a los bucles y nos permiten controlar de manera más precisa el flujo de ejecución en nuestros programas.