,

Estructuras de control en Java

·

Aprender estructuras de control en Java es uno de esos pasos que marcan un antes y un después cuando empiezas a programar. Al principio, un programa puede parecer una simple lista de instrucciones que se ejecutan de arriba abajo. Pero en cuanto quieres que el programa tome decisiones, repita tareas, valide datos, controle errores o se pueda depurar con método, necesitas dominar las estructuras de control en Java.

En mi caso, tanto en proyectos reales como explicando programación en el aula, suelo insistir en una idea: programar no consiste en memorizar if, for o try catch, sino en entender qué camino sigue el programa y por qué. Una estructura de control bien elegida hace que el código se lea casi como una explicación del problema.

Las estructuras de control en Java permiten decidir qué instrucciones se ejecutan, cuántas veces se repiten, cuándo se interrumpe un flujo y cómo debe reaccionar el programa ante situaciones inesperadas. En el documento base de este artículo, el tema se organiza precisamente alrededor del flujo de ejecución, las estructuras de selección, las estructuras de repetición, las sentencias de salto, el control de excepciones, la depuración y la documentación de programas.

A lo largo de esta guía vamos a ver las estructuras de control en Java desde un punto de vista práctico, con ejemplos sencillos, errores frecuentes y recomendaciones para elegir la estructura adecuada en cada situación.

Qué son las estructuras de control en Java

Las estructuras de control en Java son instrucciones que permiten modificar el flujo normal de ejecución de un programa. Sin ellas, Java ejecutaría las líneas de código una tras otra, siempre en el mismo orden y sin reaccionar ante condiciones, repeticiones o errores.

Por ejemplo, un programa lineal podría ser algo así:

System.out.println("Inicio");
System.out.println("Proceso");
System.out.println("Fin");

Este código siempre hace lo mismo. No pregunta nada, no decide nada, no repite nada y no controla errores. Es útil para entender el orden básico de ejecución, pero se queda corto en cuanto queremos crear programas con comportamiento real.

En cambio, con estructuras de control en Java podemos hacer cosas como:

if (edad >= 18) {
System.out.println("Puedes acceder");
} else {
System.out.println("No puedes acceder todavía");
}

Aquí el programa ya no ejecuta siempre el mismo camino. Depende del valor de edad. Esa es la esencia del control de flujo: el programa observa una condición y actúa en consecuencia.

El flujo de ejecución: de arriba abajo… hasta que el programa decide algo

El flujo de ejecución es el orden en el que se ejecutan las instrucciones. En Java, ese flujo suele avanzar de arriba abajo, pero las estructuras de control en Java permiten cambiarlo.

Podemos agruparlas así:

Necesidad del programaEstructura habitual
Elegir entre varios caminosif, else, switch
Repetir instruccioneswhile, do while, for
Interrumpir o modificar el flujobreak, continue, return
Evitar que un error cierre el programatry, catch, finally
Localizar por qué falla el programadepuración, puntos de ruptura, inspección de variables

Esta clasificación aparece también en el documento de partida: selección para elegir caminos, repetición para ejecutar bloques varias veces, sentencias de salto para modificar el flujo, excepciones para controlar errores y depuración para localizar fallos.

En clase suelo verlo con un ejemplo muy simple: un menú. Si el usuario pulsa 1, el programa hace una cosa; si pulsa 2, hace otra; si pulsa 0, termina. Ese pequeño menú ya combina varias estructuras de control en Java: un bucle para repetir, un switch para elegir opción y quizá un try catch para evitar que el programa se rompa si el usuario escribe texto donde se esperaba un número.

Por qué las condiciones booleanas son la base de casi todo

Antes de entender bien las estructuras de control en Java, conviene dominar las expresiones booleanas. Una expresión booleana solo puede tener dos resultados: true o false.

Algunos ejemplos:

edad >= 18
nota >= 5
opcion != 0
usuario.equals("admin")
saldo > 0 && activo

Todas esas expresiones responden a una pregunta:

  • ¿La edad es mayor o igual que 18?
  • ¿La nota es mayor o igual que 5?
  • ¿La opción es distinta de 0?
  • ¿El usuario se llama "admin"?
  • ¿El saldo es positivo y la cuenta está activa?

Java necesita que las condiciones dentro de un if, un while o un do while produzcan un valor booleano. No basta con poner una variable numérica y esperar que Java la interprete como verdadera o falsa. Esta es una diferencia importante respecto a otros lenguajes.

Por eso, cuando explico estructuras de control en Java, siempre empiezo por aquí. Si no entiendes bien las condiciones, los if y los bucles se convierten en una especie de magia rara. Y programar no debería sentirse como magia: debería sentirse como una cadena de decisiones que puedes seguir paso a paso.

Operadores relacionales y lógicos que conviene dominar desde el principio

Las condiciones se construyen con operadores relacionales y operadores lógicos.

Los operadores relacionales comparan valores:

opcion == 1
opcion != 0
edad > 18
temperatura < 0
nota >= 5
intentos <= 3

Los operadores lógicos combinan condiciones:

edad >= 18 && tieneEntrada
esAdmin || esProfesor
!activo

El operador && significa “y”: deben cumplirse las dos condiciones. El operador || significa “o”: basta con que se cumpla una de ellas. El operador ! niega una condición.

Un error clásico al empezar con estructuras de control en Java es confundir = con ==.

int opcion = 1;      // asigna un valor
opcion == 1 // compara un valor

El operador = sirve para asignar. El operador == sirve para comparar. Esta diferencia parece pequeña, pero puede provocar errores muy molestos.

Estructuras de selección: cómo tomar decisiones en Java

Las estructuras de selección son las estructuras de control en Java que permiten elegir entre distintos caminos. Se usan para validar datos, clasificar valores, mostrar mensajes diferentes o ejecutar una acción solo cuando se cumple una condición.

En la práctica, las más importantes son:

  • if
  • if else
  • else if
  • switch
  • operador ternario

Cuando vienes de proyectos reales, aprendes rápido que elegir bien la estructura no es solo una cuestión de sintaxis. También afecta a la claridad del código. No es lo mismo resolver un menú con diez if desordenados que usar un switch claro y fácil de leer.

if: ejecutar código solo si se cumple una condición

La estructura if ejecuta un bloque de código únicamente si la condición es verdadera.

int edad = 20;

if (edad >= 18) {
System.out.println("Puedes acceder.");
}

Este ejemplo es sencillo: si edad es mayor o igual que 18, se muestra el mensaje. Si no, el programa continúa después del bloque.

El if es una de las estructuras de control en Java más básicas y más usadas. Sirve cuando quieres que algo ocurra solo bajo una condición concreta.

Ejemplos típicos:

if (nota < 5) {
System.out.println("Debes recuperar.");
}
if (saldo <= 0) {
System.out.println("Saldo insuficiente.");
}
if (opcion == 0) {
System.out.println("Saliendo...");
}

Mi recomendación es que el if sea fácil de leer. Una condición como esta se entiende bien:

if (nota >= 5 && nota <= 10) {
System.out.println("Nota válida.");
}

Pero si empiezas a meter demasiadas condiciones en la misma línea, quizá convenga separar la lógica o usar variables intermedias.

if else: elegir entre dos caminos

La estructura if else permite ejecutar un bloque si la condición es verdadera y otro bloque si es falsa.

int edad = 16;

if (edad >= 18) {
System.out.println("Puedes acceder.");
} else {
System.out.println("No puedes acceder todavía.");
}

Este patrón es perfecto cuando hay dos caminos excluyentes. Por ejemplo:

double nota = 6.5;

if (nota >= 5) {
System.out.println("Aprobado");
} else {
System.out.println("Suspenso");
}

Aquí no hay duda: una nota no puede estar aprobada y suspensa al mismo tiempo. Por eso if else encaja tan bien.

Dentro de las estructuras de control en Java, if else es una de las más útiles para introducir lógica real en programas sencillos. Clasificar edades, validar notas, comprobar accesos o decidir si una operación puede realizarse son casos muy habituales.

else if: clasificar valores en varios casos

Cuando hay más de dos posibilidades, podemos encadenar if, else if y else.

double nota = 7.5;

if (nota < 5) {
System.out.println("Insuficiente");
} else if (nota < 6) {
System.out.println("Suficiente");
} else if (nota < 7) {
System.out.println("Bien");
} else if (nota < 9) {
System.out.println("Notable");
} else {
System.out.println("Sobresaliente");
}

Esta estructura es muy útil para clasificar valores por rangos. El orden importa mucho, porque Java evalúa las condiciones de arriba abajo y entra en el primer bloque cuya condición se cumpla.

Este detalle es importante: si las condiciones están mal ordenadas, el programa puede funcionar, pero dar resultados incorrectos. Y esos son los errores más peligrosos para quien empieza, porque el programa no siempre se rompe. A veces simplemente calcula mal.

Por eso insisto mucho en probar casos límite. En el ejemplo de notas, habría que probar valores como 4.9, 5, 6, 7, 9 y 10.

switch: cuando comparas una opción con valores concretos

La estructura switch permite elegir un bloque de código según el valor de una variable o expresión. Suele usarse cuando comparamos una misma variable con varios valores concretos.

int opcion = 2;

switch (opcion) {
case 1:
System.out.println("Crear usuario");
break;
case 2:
System.out.println("Modificar usuario");
break;
case 3:
System.out.println("Eliminar usuario");
break;
default:
System.out.println("Opción no válida");
}

El switch encaja especialmente bien con menús, códigos, opciones numéricas o valores cerrados. El documento lo presenta como una estructura adecuada cuando se compara una misma variable con valores concretos, como opciones de menú, códigos o días de la semana.

Dentro de las estructuras de control en Java, switch ayuda mucho a ordenar el código cuando hay muchas opciones. En lugar de escribir varios if else if, podemos mostrar claramente qué ocurre en cada caso.

Un error frecuente es olvidar el break en un switch clásico. Si no lo pones, Java puede seguir ejecutando los siguientes case. Este comportamiento se llama fall-through y suele dar bastantes quebraderos de cabeza al principio.

switch (opcion) {
case 1:
System.out.println("Opción 1");
case 2:
System.out.println("Opción 2");
}

Si opcion vale 1, este código puede imprimir también "Opción 2" porque falta break.

Operador ternario: útil, pero solo si mejora la legibilidad

El operador ternario permite escribir una selección simple en una sola expresión.

int edad = 19;
String mensaje = edad >= 18 ? "Mayor de edad" : "Menor de edad";
System.out.println(mensaje);

Su forma general es:

condicion ? valorSiVerdadero : valorSiFalso

Es cómodo para asignaciones sencillas. Por ejemplo:

String resultado = nota >= 5 ? "Aprobado" : "Suspenso";

Pero no conviene abusar. Si la condición es larga o hay varias decisiones, un if else suele ser más claro. Las estructuras de control en Java deben ayudar a entender el código, no convertirlo en un acertijo.

Error típico: comparar textos con == en lugar de equals()

En Java, comparar textos con == es uno de los errores más habituales al empezar.

String usuario = "admin";

if (usuario == "admin") {
System.out.println("Usuario administrador");
}

Puede parecer que funciona en algunos casos, pero no es la forma correcta de comparar contenido de cadenas.

La forma correcta es usar equals():

if (usuario.equals("admin")) {
System.out.println("Usuario administrador");
}

O equalsIgnoreCase() si queremos ignorar mayúsculas y minúsculas:

if (usuario.equalsIgnoreCase("ADMIN")) {
System.out.println("Coincide aunque cambien las mayúsculas");
}

La razón es que == compara referencias cuando trabajamos con objetos, mientras que equals() compara el contenido. El documento destaca este punto como un detalle importante para evitar errores lógicos difíciles de detectar.

Estructuras de repetición: cómo repetir instrucciones sin copiar código

Las estructuras de repetición son las estructuras de control en Java que permiten ejecutar varias veces un bloque de instrucciones. También se llaman bucles.

Son imprescindibles para:

  • recorrer listas de datos;
  • repetir menús;
  • validar entradas;
  • calcular sumas o medias;
  • procesar varios valores;
  • ejecutar una acción hasta que se cumpla una condición de parada.

Una idea clave: todo bucle necesita una condición de continuidad o de parada. Si esa condición nunca cambia, puedes crear un bucle infinito.

while: repetir mientras se cumpla una condición

El bucle while evalúa la condición antes de ejecutar el bloque.

int contador = 1;

while (contador <= 5) {
System.out.println("Vuelta " + contador);
contador++;
}

Primero comprueba si contador <= 5. Si la condición es verdadera, entra en el bucle. Al final de cada vuelta, contador++ aumenta el valor de la variable. Cuando contador pasa de 5, el bucle termina.

El while es útil cuando no sabes de antemano cuántas veces se va a repetir algo.

Por ejemplo, leer notas hasta que el usuario introduzca -1:

Scanner sc = new Scanner(System.in);

double nota;
System.out.print("Introduce una nota (-1 para salir): ");
nota = sc.nextDouble();

while (nota != -1) {
System.out.println("Nota registrada: " + nota);

System.out.print("Introduce otra nota (-1 para salir): ");
nota = sc.nextDouble();
}

sc.close();

Este patrón se entiende muy bien en clase porque refleja una situación real: “seguir pidiendo datos hasta que el usuario decida terminar”.

do while: ideal para menús que deben mostrarse al menos una vez

El bucle do while ejecuta el bloque al menos una vez y comprueba la condición al final.

int opcion;
Scanner sc = new Scanner(System.in);

do {
System.out.println("1. Saludar");
System.out.println("0. Salir");
System.out.print("Elige una opción: ");
opcion = sc.nextInt();

if (opcion == 1) {
System.out.println("Hola");
}
} while (opcion != 0);

sc.close();

Este tipo de bucle encaja especialmente bien con menús. Primero muestras las opciones y después decides si repites o sales.

Dentro de las estructuras de control en Java, do while tiene una ventaja clara: garantiza que el bloque se ejecuta al menos una vez. Eso lo hace muy natural para programas de consola.

En proyectos sencillos, un menú con do while y switch suele ser una de las mejores prácticas para empezar a combinar estructuras de control en Java.

for: cuando sabes cuántas vueltas necesitas

El bucle for se usa normalmente cuando sabes cuántas veces quieres repetir una acción.

for (int i = 1; i <= 5; i++) {
System.out.println("Vuelta " + i);
}

En una sola línea agrupa tres partes:

for (inicialización; condición; actualización)

Ejemplo:

for (int i = 1; i <= 10; i++) {
System.out.println("Número: " + i);
}

El for es ideal para tablas de multiplicar:

Scanner sc = new Scanner(System.in);

System.out.print("Introduce un número: ");
int numero = sc.nextInt();

for (int i = 1; i <= 10; i++) {
System.out.println(numero + " x " + i + " = " + (numero * i));
}

sc.close();

En mi experiencia, el for suele ser el bucle que más rápido se entiende cuando hay un contador visible. El problema llega cuando se usa para todo. Si no sabes cuántas vueltas habrá, quizá un while sea más adecuado.

Contadores, acumuladores y centinelas

Muchos programas con estructuras de control en Java se apoyan en tres patrones básicos: contadores, acumuladores y centinelas.

PatrónPara qué sirveEjemplo
ContadorCuenta cuántas veces ocurre algocontador++
AcumuladorSuma o acumula valoressuma += nota
CentinelaValor especial que indica cuándo terminar-1 para salir

Ejemplo completo:

Scanner sc = new Scanner(System.in);

int contador = 0;
double suma = 0;
double nota;

System.out.print("Introduce una nota (-1 para terminar): ");
nota = sc.nextDouble();

while (nota != -1) {
suma += nota;
contador++;

System.out.print("Introduce otra nota (-1 para terminar): ");
nota = sc.nextDouble();
}

if (contador > 0) {
double media = suma / contador;
System.out.println("Media: " + media);
} else {
System.out.println("No se han introducido notas.");
}

sc.close();

El documento presenta estos tres patrones como bases importantes para trabajar con bucles: contador para contar, acumulador para sumar y centinela como valor especial de parada.

Este tipo de ejemplo es muy potente porque combina varias estructuras de control en Java: un while, un if else, un contador, un acumulador y una condición de salida.

Bucles anidados y bucles infinitos

Un bucle anidado es un bucle dentro de otro. Se usa para recorrer tablas, matrices o combinaciones de valores.

for (int fila = 1; fila <= 3; fila++) {
for (int columna = 1; columna <= 4; columna++) {
System.out.print("[" + fila + "," + columna + "] ");
}
System.out.println();
}

Por cada vuelta del bucle externo, el bucle interno se ejecuta completo. Este patrón aparece mucho cuando se trabajan estructuras de datos bidimensionales.

El problema contrario es el bucle infinito. Ocurre cuando la condición nunca deja de cumplirse.

int contador = 1;

while (contador <= 5) {
System.out.println(contador);
// Falta contador++
}

Aquí contador siempre vale 1, así que la condición contador <= 5 siempre será verdadera. El programa no termina.

Cuando reviso código de principiantes, una de las primeras cosas que miro en un while es si dentro del bucle hay algo que pueda hacer falsa la condición. Si no lo hay, probablemente tenemos un bucle infinito esperando a aparecer.

Sentencias de salto: break, continue y return

Las sentencias de salto también forman parte de las estructuras de control en Java. Sirven para alterar el flujo normal de ejecución.

Las más importantes son:

  • break
  • continue
  • return

Son útiles, pero conviene usarlas con cabeza. Si mezclas demasiados saltos en la misma zona del programa, el código puede volverse difícil de seguir.

Cuándo usar break

La sentencia break finaliza el switch o bucle más cercano.

for (int i = 1; i <= 10; i++) {
if (i == 5) {
break;
}
System.out.println(i);
}

System.out.println("Fin del bucle");

Este código imprime 1, 2, 3 y 4. Cuando i vale 5, se ejecuta break y el bucle termina.

En un switch, break sirve para evitar que se ejecuten los siguientes case.

switch (opcion) {
case 1:
System.out.println("Alta");
break;
case 2:
System.out.println("Baja");
break;
default:
System.out.println("Opción no válida");
}

Cuándo usar continue

La sentencia continue no termina el bucle completo. Solo salta a la siguiente vuelta.

for (int i = 1; i <= 5; i++) {
if (i == 3) {
continue;
}
System.out.println(i);
}

Este código imprime 1, 2, 4 y 5. Cuando i vale 3, se salta esa vuelta.

continue puede ser útil para ignorar valores que no interesan. Por ejemplo, saltar números negativos:

for (int numero = -2; numero <= 3; numero++) {
if (numero < 0) {
continue;
}
System.out.println(numero);
}

Cuándo usar return

La sentencia return termina la ejecución de un método. Si el método devuelve un valor, return debe devolverlo.

public static boolean esMayorDeEdad(int edad) {
return edad >= 18;
}

También puede usarse en métodos void para salir antes:

public static void mostrarMensaje(String mensaje) {
if (mensaje == null) {
return;
}

System.out.println(mensaje);
}

En programación real, return puede ayudar a simplificar métodos. En lugar de anidar muchos if, a veces es más claro salir antes cuando una condición no tiene sentido.

public static void procesarNota(double nota) {
if (nota < 0 || nota > 10) {
System.out.println("Nota no válida");
return;
}

System.out.println("Nota procesada");
}

Cómo evitar que los saltos vuelvan el código difícil de seguir

break, continue y return son herramientas útiles, pero no deberían convertir el código en un laberinto.

Una buena regla práctica:

  • usa break para salir claramente de un switch o de un bucle;
  • usa continue solo cuando saltar una vuelta haga el código más claro;
  • usa return para expresar salidas naturales de un método;
  • evita mezclar muchos saltos en bloques largos.

El documento también recomienda evitar mezclar demasiados break, continue y return si eso dificulta seguir el flujo del programa.

Control de excepciones en Java

El control de excepciones es otra parte fundamental de las estructuras de control en Java. Una excepción representa una situación anómala durante la ejecución del programa.

Puede aparecer, por ejemplo, cuando:

  • el usuario escribe texto donde se esperaba un número;
  • se intenta dividir entre cero;
  • se accede a una posición inexistente de un array;
  • se intenta usar una referencia null;
  • se convierte un texto inválido en número.

Sin control de excepciones, un programa puede cerrarse bruscamente. Con try catch, podemos capturar el problema y mostrar un mensaje más claro al usuario.

Diferencia entre error de compilación, error de ejecución y error lógico

Antes de usar excepciones, conviene distinguir tres tipos de errores.

Tipo de errorCuándo ocurreEjemplo
Error de compilaciónAntes de ejecutarFalta un punto y coma
Error de ejecuciónMientras funciona el programaDivisión entre cero
Error lógicoEl programa ejecuta, pero calcula malMedia mal calculada

Esta distinción es muy importante. El compilador no detecta todos los problemas. Un programa puede compilar perfectamente y aun así funcionar mal. Por eso son necesarias las pruebas y la depuración, tal como se remarca en el documento.

En mi caso, suelo decirlo así: que el programa “arranque” no significa que esté bien. Solo significa que Java ha podido ejecutarlo. Ahora hay que comprobar si hace lo que debe hacer.

Cómo funciona try catch

La estructura try catch permite intentar ejecutar código que podría fallar y capturar una excepción si se produce.

try {
int resultado = 10 / 0;
System.out.println(resultado);
} catch (ArithmeticException e) {
System.out.println("No se puede dividir entre cero.");
}

El bloque try contiene el código peligroso. El bloque catch captura la excepción.

Otro ejemplo habitual:

try {
int numero = Integer.parseInt("hola");
System.out.println(numero);
} catch (NumberFormatException e) {
System.out.println("El texto no se puede convertir a número.");
}

Dentro de las estructuras de control en Java, try catch no sirve para tomar decisiones normales, sino para controlar situaciones anómalas. No deberíamos usar excepciones para todo.

Capturar errores de entrada con Scanner

Un caso muy común en programas de consola es pedir un número y que el usuario escriba texto.

import java.util.InputMismatchException;
import java.util.Scanner;

public class LecturaSegura {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);

try {
System.out.print("Introduce tu edad: ");
int edad = sc.nextInt();
System.out.println("Edad introducida: " + edad);
} catch (InputMismatchException e) {
System.out.println("Debes introducir un número entero.");
}

sc.close();
}
}

El documento utiliza este mismo tipo de situación para explicar cómo Scanner puede lanzar una InputMismatchException cuando se espera un número y se introduce otro tipo de dato.

Este ejemplo es muy útil porque enseña algo importante: un buen programa no debería mostrar al usuario un mensaje técnico incomprensible. Si alguien escribe mal un dato, conviene explicar el problema con claridad.

Para qué sirve finally

El bloque finally se ejecuta siempre, haya o no haya excepción. Suele usarse para cerrar recursos o hacer tareas de limpieza.

Scanner sc = new Scanner(System.in);

try {
System.out.print("Introduce un número: ");
int numero = sc.nextInt();
System.out.println("Número: " + numero);
} catch (InputMismatchException e) {
System.out.println("Entrada no válida.");
} finally {
sc.close();
System.out.println("Recurso cerrado.");
}

En programas sencillos puede no parecer tan importante, pero es bueno conocerlo desde el principio. Cerrar recursos es parte de escribir código responsable.

Validar antes o capturar una excepción: cuándo elegir cada opción

No todo debe resolverse con excepciones. Muchas veces es mejor validar antes.

Por ejemplo, para evitar una división entre cero:

int divisor = 0;

if (divisor != 0) {
int resultado = 10 / divisor;
System.out.println(resultado);
} else {
System.out.println("El divisor no puede ser cero.");
}

Aquí no hace falta provocar una excepción. Podemos comprobar antes si el divisor es válido.

Una buena guía:

SituaciónMejor enfoque
Comprobar si una nota está entre 0 y 10Validación con if
Comprobar si una opción de menú existeValidación con if o switch
Usuario escribe texto donde se esperaba un númerotry catch o lectura como texto y validación
Archivo que puede no existirControl de excepción

Las estructuras de control en Java no compiten entre sí. Se combinan. Un programa sólido suele usar if, bucles, switch, try catch y pruebas.

Cómo crear un programa ejecutable combinando estructuras de control

Una vez entiendes las piezas por separado, llega lo importante: combinarlas en un programa completo. Ahí es donde las estructuras de control en Java empiezan a tener sentido de verdad.

Un programa de consola suele incluir:

  • importaciones;
  • clase principal;
  • método main;
  • variables iniciales;
  • bucle principal;
  • selección de opciones;
  • control de errores;
  • cierre de recursos.

El documento propone precisamente esta estructura para programas de consola con estructuras de control, incluyendo importaciones, clase principal, método main, variables, bucle principal, selección de opciones, validaciones, try catch y cierre de recursos.

La estructura básica con main

En Java, el método main es el punto de entrada de una aplicación de consola.

public class ProgramaPrincipal {
public static void main(String[] args) {
System.out.println("Programa iniciado");
}
}

A partir de ahí podemos añadir variables, menús, bucles, decisiones y control de errores.

Menú de consola con do while, switch, if y try catch

Un menú sencillo permite combinar varias estructuras de control en Java:

import java.util.InputMismatchException;
import java.util.Scanner;

public class MenuBasico {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int opcion = -1;

do {
System.out.println("1. Saludar");
System.out.println("2. Despedir");
System.out.println("0. Salir");
System.out.print("Opción: ");

try {
opcion = sc.nextInt();

switch (opcion) {
case 1:
System.out.println("Hola");
break;
case 2:
System.out.println("Adiós");
break;
case 0:
System.out.println("Fin del programa");
break;
default:
System.out.println("Opción no válida");
}
} catch (InputMismatchException e) {
System.out.println("Debes introducir un número.");
sc.nextLine();
}

} while (opcion != 0);

sc.close();
}
}

Aquí tenemos:

  • do while para repetir el menú;
  • switch para elegir la acción;
  • try catch para controlar una entrada incorrecta;
  • break para cerrar cada case;
  • una condición de salida con opcion != 0.

Este ejemplo resume muy bien por qué las estructuras de control en Java son tan importantes. No estamos escribiendo instrucciones aisladas. Estamos diseñando comportamiento.

Caso práctico: gestión de notas paso a paso

Un caso muy completo es un programa de gestión de notas. El objetivo es introducir notas, calcular la media, contar aprobados y suspensos, controlar entradas incorrectas y repetir el menú hasta salir.

La lógica sería:

Inicio
Inicializar suma, contador, aprobados y suspensos
Repetir
Mostrar menú
Leer opción
Según opción:
1 -> Pedir nota, validar, acumular y contar
2 -> Mostrar resumen
0 -> Salir
otra -> Mostrar error
Mientras opción no sea 0
Fin

Este diseño coincide con el caso práctico del documento, que combina do while, switch, if else, try catch, contadores y acumuladores para gestionar notas.

Una versión simplificada podría ser:

import java.util.InputMismatchException;
import java.util.Scanner;

public class GestionNotas {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);

double suma = 0;
int contador = 0;
int aprobados = 0;
int suspensos = 0;
int opcion = -1;

do {
System.out.println("\n--- MENÚ DE NOTAS ---");
System.out.println("1. Introducir nota");
System.out.println("2. Mostrar resumen");
System.out.println("0. Salir");
System.out.print("Elige una opción: ");

try {
opcion = sc.nextInt();

switch (opcion) {
case 1:
System.out.print("Introduce una nota entre 0 y 10: ");
double nota = sc.nextDouble();

if (nota < 0 || nota > 10) {
System.out.println("La nota debe estar entre 0 y 10.");
} else {
suma += nota;
contador++;

if (nota >= 5) {
aprobados++;
} else {
suspensos++;
}

System.out.println("Nota registrada correctamente.");
}
break;

case 2:
if (contador == 0) {
System.out.println("Todavía no hay notas registradas.");
} else {
double media = suma / contador;
System.out.println("Notas registradas: " + contador);
System.out.println("Media: " + media);
System.out.println("Aprobados: " + aprobados);
System.out.println("Suspensos: " + suspensos);
}
break;

case 0:
System.out.println("Saliendo del programa...");
break;

default:
System.out.println("Opción no válida.");
}
} catch (InputMismatchException e) {
System.out.println("Entrada no válida. Debes introducir un número.");
sc.nextLine();
}

} while (opcion != 0);

sc.close();
}
}

Este ejemplo es muy completo para practicar estructuras de control en Java porque obliga a tomar decisiones, repetir un menú, validar rangos, acumular datos, contar resultados y controlar errores.

Depuración: cómo encontrar errores sin tocar código al azar

Depurar es localizar, analizar y corregir errores. No consiste en cambiar líneas al azar hasta que algo parezca funcionar.

Esta parte me parece especialmente importante. En desarrollo real, y también en clase, depurar bien ahorra muchísimo tiempo. Cuando un alumno se acostumbra a observar variables, comprobar condiciones y seguir el flujo paso a paso, deja de depender de la intuición y empieza a razonar como programador.

Qué tipos de errores puedes depurar

Podemos depurar varios tipos de errores:

TipoSíntoma
SintaxisEl programa no compila
EjecuciónEl programa se detiene o lanza una excepción
LógicoEl programa termina, pero el resultado es incorrecto
FlujoEntra en un if que no debería
BucleRepite demasiado, demasiado poco o nunca termina

El documento define la depuración como un proceso para localizar, analizar y corregir errores, comparando el comportamiento real del programa con el esperado. También destaca que depurar ayuda a entender cómo se ejecuta realmente el código.

Puntos de ruptura y ejecución paso a paso

Un punto de ruptura, o breakpoint, es una marca que colocamos en una línea para que el depurador detenga ahí la ejecución.

int suma = 0;

for (int i = 1; i <= 5; i++) {
suma += i; // Coloca aquí un punto de ruptura
}

System.out.println("Suma: " + suma);

Al detener el programa, podemos ver cuánto vale i, cuánto vale suma y cómo cambian en cada vuelta.

Las acciones típicas del depurador son:

AcciónPara qué sirve
Step OverEjecutar la línea actual sin entrar en métodos
Step IntoEntrar dentro del método llamado
Step ReturnSalir del método actual
ResumeContinuar hasta el siguiente punto de ruptura
TerminateFinalizar la ejecución

Cuando se aprenden estructuras de control en Java, depurar es una herramienta fantástica porque permite ver el flujo en directo. Puedes comprobar si un if entra donde esperabas, si un while repite demasiadas veces o si un contador aumenta correctamente.

Inspección de variables

Durante la depuración, el IDE muestra el valor de las variables.

Conviene revisar:

VariableQué comprobar
contadorSi aumenta correctamente
sumaSi acumula los valores esperados
opcionSi recoge la opción real del usuario
notaSi está dentro del rango permitido
mensajeSi contiene el texto correcto

En el caso del programa de notas, yo pondría puntos de ruptura después de leer la opción y después de leer la nota. Así se puede comprobar qué camino sigue el switch, si el if valida correctamente y si los contadores cambian como deben.

Método ordenado para depurar un programa

Un método sencillo para depurar sería:

  1. Reproduce el error.
  2. Anota qué entrada provoca el fallo.
  3. Lee el mensaje completo si aparece una excepción.
  4. Localiza la zona probable del problema.
  5. Coloca un punto de ruptura antes.
  6. Ejecuta paso a paso.
  7. Observa variables y condiciones.
  8. Corrige una cosa cada vez.
  9. Vuelve a probar.

Esta forma de trabajar conecta muy bien con mi manera de entender la programación: estructura, claridad y resultados reales. No se trata de tocar por tocar. Se trata de observar qué hace el programa y compararlo con lo que debería hacer.

Comentarios, documentación y pruebas

Las estructuras de control en Java no solo deben funcionar. También deben entenderse, probarse y mantenerse.

Un programa puede compilar, ejecutar y aun así ser difícil de leer. Por eso los comentarios, la documentación y las pruebas forman parte de escribir buen código.

Comentarios útiles frente a comentarios que solo meten ruido

Un comentario útil explica una decisión, no repite lo evidente.

Buen comentario:

// Calcula el importe del descuento antes de restarlo al precio inicial
double importeDescuento = precio * porcentaje / 100;

Comentario poco útil:

// Suma uno a contador
contador++;

Si el código ya se entiende, no hace falta comentarlo todo. En proyectos reales, demasiados comentarios obvios pueden hacer más ruido que ayuda.

Javadoc y documentación externa básica

Java permite varios tipos de comentarios:

// Comentario de una línea
/*
Comentario de bloque
*/
/**
* Calcula la media de dos notas.
* @param nota1 primera nota
* @param nota2 segunda nota
* @return media aritmética
*/
public static double calcularMedia(double nota1, double nota2) {
return (nota1 + nota2) / 2;
}

La documentación externa puede incluir:

  • objetivo del programa;
  • datos de entrada;
  • proceso que realiza;
  • datos de salida;
  • estructuras de control utilizadas;
  • excepciones o validaciones aplicadas;
  • pruebas realizadas;
  • problemas encontrados y soluciones.

El documento indica que una práctica sencilla debería documentar el objetivo, entradas, proceso, salidas, estructuras utilizadas, validaciones, pruebas, evidencias y problemas encontrados.

Pruebas normales, límite y erróneas

Probar es tan importante como programar.

En el programa de notas, habría que probar:

PruebaEntradaResultado esperado
Opción válida1 y nota 7Nota registrada como aprobada
Nota límite inferior0Nota registrada como suspensa
Nota límite superior10Nota registrada como aprobada
Nota fuera de rango12Mensaje de error
Resumen sin notas2 al inicioMensaje indicando que no hay notas
Entrada no numéricatextoMensaje de entrada no válida
Salir0El programa termina

El documento propone pruebas de este tipo para el caso de gestión de notas y recomienda revisar también puntos de depuración concretos, como la opción del menú, la nota introducida y los contadores.

Errores frecuentes al aprender estructuras de control en Java

Al aprender estructuras de control en Java, hay errores que se repiten muchísimo. Conocerlos ayuda a detectarlos antes.

Confundir = con ==

int opcion = 1; // asignación
opcion == 1 // comparación

Usa = para asignar y == para comparar valores primitivos.

Olvidar break en un switch

switch (opcion) {
case 1:
System.out.println("Uno");
case 2:
System.out.println("Dos");
}

Si falta break, se pueden ejecutar varios case seguidos.

Crear un bucle infinito sin querer

int contador = 1;

while (contador <= 5) {
System.out.println(contador);
}

Falta actualizar contador.

No limpiar Scanner tras una entrada incorrecta

Cuando Scanner lanza una InputMismatchException, muchas veces conviene limpiar la entrada:

sc.nextLine();

Si no lo haces, el programa puede repetir el catch continuamente.

No probar casos límite

Si un programa acepta notas entre 0 y 10, no basta con probar 7. Hay que probar 0, 10, negativos, valores mayores que 10 y entradas no numéricas.

El documento recoge estos errores frecuentes: usar =, comparar String con ==, olvidar actualizar contadores, olvidar break, no limpiar Scanner, no probar casos límite y escribir comentarios inútiles.

Ejercicios recomendados para practicar

La mejor forma de dominar estructuras de control en Java es escribir programas pequeños. No hace falta empezar con proyectos enormes. De hecho, suele ser mejor trabajar ejercicios muy concretos.

Clasificador de edad

Objetivo: pedir una edad y mostrar si la persona es menor de edad, adulta o jubilada.

Scanner sc = new Scanner(System.in);

System.out.print("Introduce tu edad: ");
int edad = sc.nextInt();

if (edad < 0) {
System.out.println("Edad no válida");
} else if (edad < 18) {
System.out.println("Menor de edad");
} else if (edad < 65) {
System.out.println("Adulto");
} else {
System.out.println("Jubilado");
}

sc.close();

Tabla de multiplicar

Objetivo: practicar el bucle for.

Scanner sc = new Scanner(System.in);

System.out.print("Introduce un número: ");
int numero = sc.nextInt();

for (int i = 1; i <= 10; i++) {
System.out.println(numero + " x " + i + " = " + (numero * i));
}

sc.close();

Menú repetitivo

Objetivo: combinar do while y switch.

Scanner sc = new Scanner(System.in);
int opcion;

do {
System.out.println("1. Saludar");
System.out.println("2. Despedir");
System.out.println("0. Salir");
System.out.print("Opción: ");
opcion = sc.nextInt();

switch (opcion) {
case 1:
System.out.println("Hola");
break;
case 2:
System.out.println("Adiós");
break;
case 0:
System.out.println("Fin");
break;
default:
System.out.println("Opción no válida");
}
} while (opcion != 0);

sc.close();

Entrada segura con try catch

Objetivo: evitar que el programa se cierre si el usuario escribe texto donde se espera un número.

try {
System.out.print("Introduce un número: ");
int numero = sc.nextInt();
System.out.println("Número introducido: " + numero);
} catch (InputMismatchException e) {
System.out.println("Error: debes introducir un número entero.");
sc.nextLine();
}

Estos ejercicios aparecen alineados con las actividades guiadas del documento: clasificador de edad, tabla de multiplicar, menú repetitivo y entrada segura.

Resumen final

Las estructuras de control en Java permiten que un programa deje de ser una simple secuencia lineal de instrucciones. Gracias a ellas, el código puede tomar decisiones, repetir procesos, interrumpir flujos, controlar errores y facilitar la depuración.

Las estructuras de selección, como if, if else, else if y switch, permiten elegir entre distintos caminos. Las estructuras de repetición, como while, do while y for, permiten ejecutar instrucciones varias veces. Las sentencias de salto, como break, continue y return, modifican el recorrido normal del programa. Y el control de excepciones con try catch ayuda a gestionar situaciones anómalas sin que el programa se cierre de forma brusca.

Pero dominar estructuras de control en Java no consiste solo en conocer la sintaxis. Lo importante es saber cuándo usar cada una. En un menú, probablemente usarás do while y switch. Para validar una nota, un if puede ser suficiente. Para repetir una acción un número concreto de veces, un for suele ser lo más claro. Para controlar una entrada incorrecta, try catch puede salvar el programa.

En mi experiencia, tanto desarrollando como enseñando, la diferencia se nota cuando el código empieza a tener intención. Un buen programa no solo funciona: se entiende, se prueba, se depura y se puede mantener. Y las estructuras de control en Java son la base para conseguirlo.

Preguntas frecuentes sobre estructuras de control en Java

¿Qué son las estructuras de control en Java?

Las estructuras de control en Java son instrucciones que permiten modificar el flujo de ejecución de un programa. Sirven para tomar decisiones, repetir bloques de código, interrumpir procesos, controlar errores y depurar programas.

¿Qué diferencia hay entre if y switch?

if se usa para evaluar condiciones generales. switch se usa cuando queremos comparar una misma variable con varios valores concretos, como opciones de menú.

¿Qué diferencia hay entre while, do while y for?

while comprueba la condición antes de ejecutar el bloque. do while ejecuta el bloque al menos una vez y comprueba la condición al final. for suele usarse cuando conocemos el número de repeticiones.

¿Para qué sirve try catch en Java?

try catch sirve para capturar excepciones durante la ejecución del programa. Permite controlar errores como entradas incorrectas, divisiones entre cero o conversiones inválidas, mostrando mensajes comprensibles en lugar de cerrar el programa bruscamente.

¿Qué es un bucle infinito?

Un bucle infinito ocurre cuando la condición de repetición nunca deja de cumplirse. Suele pasar cuando olvidamos actualizar la variable de control dentro del bucle.

¿Qué es un punto de ruptura?

Un punto de ruptura, o breakpoint, es una marca colocada en una línea de código para que el depurador detenga ahí la ejecución. Sirve para observar variables y comprobar qué camino sigue el programa.

¿Por qué es importante depurar al aprender estructuras de control en Java?

Porque permite ver cómo se ejecuta realmente el código. Al depurar, puedes comprobar si una condición se cumple, si un bucle repite correctamente o si una variable tiene el valor esperado.

julian lopez jimenez

Hola, encantado de conocerte.

Regístrate para recibir las últimas entradas, cada domingo.

¡No hago spam!

Recibe nuevas entradas cada semana

Una seleccion de articulos, recursos y novedades sobre informatica, FP y tecnologia aplicada.

julian lopez jimenez

Hola, encantado de conocerte.

Regístrate para recibir las últimas entradas, cada domingo.

¡No hago spam!

Tambien te puede interesar