Control de flujo en Java — práctica con validador, menú y adivina el número
Hay un momento muy concreto en el laboratorio de FP2 que casi todo el mundo vive igual. Llevas media hora con un programa que pide varios datos por teclado, todo compila, todo parece en orden… y de repente el programa se salta una pregunta. No da error. Simplemente sigue como si tú ya hubieras respondido algo. Y ahí empieza la búsqueda del fallo, revisando línea por línea algo que a simple vista está bien escrito.
Es la trampa del buffer de Scanner, y la vas a provocar tú mismo en el primer programa de esta práctica, a propósito, para que la reconozcas al instante la próxima vez que aparezca.
Abre VS Code, crea una carpeta practica_control_flujo y un fichero .java para cada programa.
Tabla de Contenidos
Control de flujo en Java práctica — Programa 1: Validador de datos de usuario
Este programa pide edad, email y contraseña, y valida cada uno con if/else. Es el sitio perfecto para ver la trampa del buffer en acción, porque mezcla nextInt() con nextLine() justo como pasa en un formulario real.
import java.util.Scanner;
public class ValidadorUsuario {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("=== REGISTRO DE USUARIO ===");
System.out.println();
// Edad — nextInt() deja el salto de línea "\n" sin consumir
System.out.print("Edad: ");
int edad = sc.nextInt();
sc.nextLine(); // limpiador — sin esto, el email se leería vacío
boolean edadValida = edad >= 16 && edad <= 99;
if (edadValida) {
System.out.println("✓ Edad válida");
} else {
System.out.println("✗ La edad debe estar entre 16 y 99 años");
}
// Email — validación básica sin librerías externas
System.out.print("Email: ");
String email = sc.nextLine();
// contains() busca un fragmento de texto dentro del String
boolean emailValido = email.contains("@") && email.contains(".");
if (emailValido) {
System.out.println("✓ Email con formato válido");
} else {
System.out.println("✗ El email debe contener @ y un punto");
}
// Contraseña — comprobamos varias condiciones a la vez
System.out.print("Contraseña: ");
String contrasena = sc.nextLine();
boolean longitudOk = contrasena.length() >= 8;
boolean tieneNumero = false;
for (char c : contrasena.toCharArray()) {
if (Character.isDigit(c)) {
tieneNumero = true;
break; // en cuanto encontramos un número, no hace falta seguir mirando
}
}
if (longitudOk && tieneNumero) {
System.out.println("✓ Contraseña válida");
} else if (!longitudOk && !tieneNumero) {
System.out.println("✗ Contraseña demasiado corta y sin números");
} else if (!longitudOk) {
System.out.println("✗ La contraseña necesita al menos 8 caracteres");
} else {
System.out.println("✗ La contraseña necesita al menos un número");
}
// Resumen final con operador ternario
System.out.println();
boolean todoValido = edadValida && emailValido && longitudOk && tieneNumero;
System.out.println(todoValido ? "=== REGISTRO COMPLETADO ===" : "=== REVISA LOS CAMPOS MARCADOS ===");
sc.close();
}
}
Ejecuta el programa e introduce una edad, por ejemplo 20, y pulsa Enter. Observa qué pasa con el email:
Edad: 20 ✓ Edad válida Email: ✗ El email debe contener @ y un punto
¿Ves lo que ha pasado? El programa no esperó a que escribieras el email. nextInt() leyó el 20 pero dejó el salto de línea en el buffer, y nextLine() lo consumió sin esperar a nada más, entrando en la validación con un email vacío. Comenta la línea sc.nextLine(); que viene justo después del nextInt() y comprueba tú mismo que el fallo reaparece.
Cada vez que uses nextInt(), nextDouble() o nextLong() y después necesites leer texto con nextLine(), añade un sc.nextLine() vacío entre medias. Si no lo haces, ese nextLine() se va a comer el salto de línea sobrante en vez de esperar a que escribas algo.
Control de flujo en Java práctica — Programa 2: Menú interactivo con switch
Un menú es el ejemplo más natural para practicar switch, porque cada opción numerada encaja perfectamente con un case. Aquí vas a construir uno con varias operaciones sobre una lista de la compra guardada en memoria mientras el programa se ejecuta.
import java.util.Scanner;
public class MenuListaCompra {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
// Array de tamaño fijo para simplificar — 10 huecos como máximo
String[] lista = new String[10];
int contador = 0; // cuántos productos hay realmente guardados
int opcion;
do {
System.out.println("\n=== LISTA DE LA COMPRA ===");
System.out.println("1. Añadir producto");
System.out.println("2. Ver lista completa");
System.out.println("3. Buscar producto");
System.out.println("4. Vaciar lista");
System.out.println("5. Salir");
System.out.print("Elige una opción: ");
opcion = sc.nextInt();
sc.nextLine(); // limpiador — lo necesitamos antes del próximo nextLine()
switch (opcion) {
case 1:
if (contador < lista.length) {
System.out.print("Producto a añadir: ");
lista[contador] = sc.nextLine();
contador++;
System.out.println("✓ Producto añadido");
} else {
System.out.println("✗ La lista está llena");
}
break;
case 2:
if (contador == 0) {
System.out.println("La lista está vacía");
} else {
System.out.println("--- Productos ---");
for (int i = 0; i < contador; i++) {
System.out.println((i + 1) + ". " + lista[i]);
}
}
break;
case 3:
System.out.print("¿Qué producto buscas? ");
String busqueda = sc.nextLine();
boolean encontrado = false;
for (int i = 0; i < contador; i++) {
// equalsIgnoreCase compara sin distinguir mayúsculas
if (lista[i].equalsIgnoreCase(busqueda)) {
encontrado = true;
break;
}
}
System.out.println(encontrado ? "✓ Sí está en la lista" : "✗ No está en la lista");
break;
case 4:
contador = 0; // no hace falta borrar cada posición, basta con "olvidar" cuántas hay
System.out.println("✓ Lista vaciada");
break;
case 5:
System.out.println("Hasta luego");
break;
default:
System.out.println("✗ Opción no válida, elige entre 1 y 5");
}
} while (opcion != 5);
sc.close();
}
}
Fíjate en el caso 4: para vaciar la lista no hace falta borrar cada posición del array una por una. Basta con poner contador = 0, porque el resto del programa solo mira las posiciones desde 0 hasta contador, así que lo que quede más allá simplemente se ignora.
Prueba a quitar el break del case 1 y observa qué pasa al añadir un producto. Vas a ver el fall-through en directo: el programa sigue ejecutando el case 2 justo después, aunque tú solo pediste añadir. Vuelve a poner el break; cuando lo hayas comprobado.
Control de flujo en Java práctica — Programa 3: Adivina el número con pistas
Este último programa combina todo: while para repetir hasta acertar, if/else para dar pistas, y un contador de intentos con una clasificación final según lo rápido que hayas acertado.
import java.util.Scanner;
import java.util.Random;
public class AdivinaNumero {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
Random random = new Random();
System.out.println("=== ADIVINA EL NÚMERO ===");
System.out.println("He pensado un número entre 1 y 100");
System.out.println();
// nextInt(100) genera un número entre 0 y 99 — sumamos 1 para el rango 1-100
int secreto = random.nextInt(100) + 1;
int intentos = 0;
int intento = -1; // valor imposible para forzar la primera vuelta del while
while (intento != secreto) {
System.out.print("Tu intento: ");
intento = sc.nextInt();
intentos++;
if (intento == secreto) {
System.out.println("¡Lo has adivinado!");
} else if (intento < secreto) {
// Damos más o menos margen según la distancia real
int diferencia = secreto - intento;
System.out.println(diferencia > 15 ? "Mucho más alto" : "Un poco más alto");
} else {
int diferencia = intento - secreto;
System.out.println(diferencia > 15 ? "Mucho más bajo" : "Un poco más bajo");
}
}
// Clasificación según los intentos usados
System.out.println();
String clasificacion;
switch (intentos <= 10 ? Math.min(intentos, 10) / 3 : 4) {
case 0:
case 1:
clasificacion = "Sexto sentido";
break;
case 2:
clasificacion = "Muy bien";
break;
case 3:
clasificacion = "Correcto";
break;
default:
clasificacion = "Al menos lo has conseguido";
}
System.out.printf("Acertaste en %d intentos — %s%n", intentos, clasificacion);
sc.close();
}
}
Random.nextInt(n) siempre da un número entre 0 (incluido) y n (excluido). Es el mismo patrón que ya viste con range() en Python: si necesitas que el rango empiece en 1, suma 1 al resultado, como hemos hecho aquí con random.nextInt(100) + 1.
Visualízalo con Python Tutor
Selecciona Java en el desplegable y pega en pythontutor.com:
import java.util.Scanner;
public class Demo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int edad = 20;
boolean edadValida = edad >= 16 && edad <= 99;
int opcion = 2;
switch (opcion) {
case 1:
System.out.println("Añadir");
break;
case 2:
System.out.println("Ver lista");
break;
default:
System.out.println("Otra opción");
}
int intento = 0;
int secreto = 42;
while (intento != secreto) {
intento = secreto; // simulamos que aciertas a la primera
}
System.out.println("Adivinado");
}
}
Ejecuta paso a paso y fíjate en dos momentos. Cuando llegas al switch, Python Tutor salta directamente al case 2 sin pasar por el case 1 — no evalúa las opciones en orden como un if/else, compara el valor una sola vez y va directo a su sitio. Y en el while, observa cómo la condición intento != secreto se revisa antes de cada vuelta: en cuanto intento pasa a valer lo mismo que secreto, el bucle no vuelve a ejecutarse.
Resumen y siguiente paso
En esta práctica combinaste Scanner, if/else y switch en tres programas que se parecen a cosas que vas a programar de verdad: validar datos, gestionar un menú y controlar un bucle con una condición que cambia. La trampa del buffer ya no debería pillarte por sorpresa — en cuanto veas que un programa «se salta» una pregunta, ya sabes dónde mirar.
En el siguiente artículo encontrarás ejercicios propuestos para resolver por tu cuenta.
Siguiente paso: ejerciciosControl de flujo en Java — ejercicios con validaciones, menús y bucles
Un comentario