control de flujo en Java Scanner if else switch buffer problema

Entrada y control de flujo en Java — Scanner, if/else y switch desde cero

El control de flujo en Java cubre dos cosas que en FP2 van siempre juntas: cómo leer datos del usuario con Scanner y cómo tomar decisiones con if/else y switch. Si vienes de Python ya conoces la lógica, las condiciones funcionan igual. Si además has visto el switch de C en IC2, el de Java te va a resultar casi idéntico. Lo que es nuevo es el Scanner y el problema del buffer, esa trampa silenciosa que destroza programas enteros si no sabes que existe.

Importar clases en Java — la primera vez que ves import

Antes de usar Scanner hay que importarlo. En Python importabas módulos con import. En Java importas clases con import también, pero la sintaxis es diferente y va siempre al principio del archivo, antes de la clase:

# Python
import math
from math import sqrt
// Java — import va antes de la clase
import java.util.Scanner;

public class MiPrograma {
    public static void main(String[] args) {
        // aquí ya puedes usar Scanner
    }
}

java.util.Scanner es la ruta completa de la clase, java.util es el paquete (equivalente a un módulo de Python) y Scanner es la clase dentro de ese paquete.

VS Code con la extensión Java añade el import automáticamente cuando empiezas a escribir Scanner, pero tienes que saber que existe para entender qué hace.

También puedes importar todo el paquete con *:

import java.util.*;    // importa todas las clases de java.util

En FP2 verás las dos formas. La importación específica (import java.util.Scanner) es mejor práctica porque deja claro qué clases estás usando.

Qué es Scanner y cómo crearlo

Scanner es la clase de Java para leer entrada del usuario, el equivalente de input() en Python. Para usarlo hay que crear un objeto Scanner conectado a la entrada estándar (System.in: el teclado):

# Python — una sola función para todo
nombre = input("Introduce tu nombre: ")
edad = int(input("Introduce tu edad: "))
// Java — crear un Scanner y usarlo para leer
import java.util.Scanner;

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

        System.out.print("Introduce tu nombre: ");
        String nombre = sc.nextLine();          // lee texto

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

        System.out.println("Hola " + nombre + ", tienes " + edad + " años");

        sc.close();    // cierra el Scanner al terminar
    }
}

new Scanner(System.in) crea un objeto Scanner conectado al teclado. System.in es la entrada estándar, igual que System.out era la salida estándar. La palabra new crea un objeto nuevo, la verás constantemente en Java.

Por qué hay nextInt(), nextDouble(), nextLine()… — y cuándo usar cada uno

En Python input() siempre devuelve un String y tú convertías con int() o float(). En Java Scanner tiene métodos específicos para cada tipo, y esto es importante porque cada método lee exactamente ese tipo del teclado:

sc.nextInt()        // lee un entero (int)
sc.nextLong()       // lee un entero largo (long)
sc.nextDouble()     // lee un decimal (double)
sc.nextFloat()      // lee un decimal simple (float)
sc.nextBoolean()    // lee true o false (boolean)
sc.next()           // lee una palabra (String hasta el espacio)
sc.nextLine()       // lee una línea completa (String hasta el Enter)

La diferencia entre next() y nextLine():

// Si el usuario escribe "Sergio Medina" y pulsa Enter:

String palabra = sc.next();      // → "Sergio"  (para en el espacio)
String linea = sc.nextLine();    // → "Sergio Medina"  (lee todo hasta Enter)

Para leer un nombre completo con espacios siempre usa nextLine(). Para leer una sola palabra sin espacios puedes usar next().

El problema del buffer — la trampa más común de Scanner

Aquí está el problema que más confunde a los estudiantes de FP2 y que hace que los programas parezcan saltarse preguntas.

Cuando el usuario escribe un número y pulsa Enter, nextInt() lee el número pero deja el carácter de fin de línea \n (el Enter) en el buffer. Si después llamas a nextLine(), ese método lee el \n que quedó, y devuelve una cadena vacía en vez de esperar a que el usuario escriba algo.

Scanner sc = new Scanner(System.in);

System.out.print("Edad: ");
int edad = sc.nextInt();         // el usuario escribe "22" y pulsa Enter
                                 // nextInt() lee "22" pero deja "\n" en el buffer

System.out.print("Nombre: ");
String nombre = sc.nextLine();   // ← lee el "\n" que quedó → nombre = ""
                                 // el programa NO espera que el usuario escriba

System.out.println("Hola " + nombre);    // → "Hola " — nombre está vacío

El programa parece que se salta la pregunta del nombre. En realidad sí preguntó, pero respondió automáticamente con el Enter que quedó en el buffer.

La solución, añadir un sc.nextLine() vacío después de cualquier nextInt(), nextDouble() o similar para consumir el \n sobrante:

Scanner sc = new Scanner(System.in);

System.out.print("Edad: ");
int edad = sc.nextInt();
sc.nextLine();              // ← consume el "\n" sobrante — línea limpiadora

System.out.print("Nombre: ");
String nombre = sc.nextLine();    // ahora sí espera al usuario

System.out.println("Hola " + nombre + ", tienes " + edad + " años");

La regla práctica: siempre que uses nextInt(), nextDouble() u otro método de tipo, y después necesites leer un String con nextLine(), añade un sc.nextLine() vacío entre los dos.

int numero = sc.nextInt();
sc.nextLine();              // limpiador — siempre aquí si viene nextLine() después
String texto = sc.nextLine();

Otra solución alternativa que evita el problema completamente, leer todo como String y convertir:

System.out.print("Edad: ");
int edad = Integer.parseInt(sc.nextLine());    // lee la línea y convierte

System.out.print("Nombre: ");
String nombre = sc.nextLine();                 // no hay problema de buffer

Esta segunda forma es más segura y muchos programadores de Java la prefieren. En FP2 verás las dos.

El if/else en Java — igual que en Python pero con llaves

La lógica de if/else es idéntica a Python. Lo que cambia es la sintaxis, paréntesis alrededor de la condición y llaves en vez de indentación:

# Python
nota = 7.5
if nota >= 9:
    print("Matrícula")
elif nota >= 7:
    print("Notable")
elif nota >= 5:
    print("Aprobado")
else:
    print("Suspenso")

java

// Java
double nota = 7.5;
if (nota >= 9) {
    System.out.println("Matrícula");
} else if (nota >= 7) {
    System.out.println("Notable");
} else if (nota >= 5) {
    System.out.println("Aprobado");
} else {
    System.out.println("Suspenso");
}

Las diferencias respecto a Python:

  • La condición va entre paréntesis (nota >= 9), obligatorio
  • elif en Python = else if en Java, dos palabras separadas
  • Las llaves { } delimitan cada bloque
  • No hay dos puntos : al final de la condición

Los operadores de comparación son exactamente iguales que en Python:

==    // igual (para primitivos — para objetos usa .equals())
!=    // distinto
>     // mayor que
<     // menor que
>=    // mayor o igual
<=    // menor o igual

Los operadores lógicos cambian de nombre respecto a Python.

# Python
if a > 0 and b > 0:
if a > 0 or b > 0:
if not activo:
// Java
if (a > 0 && b > 0) {    // and → &&
if (a > 0 || b > 0) {    // or  → ||
if (!activo) {            // not → !

If sin llaves — cuando es correcto y cuando es trampa en el control de flujo en Java

Si el bloque tiene una sola instrucción puedes omitir las llaves, igual que en C:

if (nota >= 5)
    System.out.println("Aprobado");    // correcto — una sola instrucción

if (nota >= 5)
    System.out.println("Aprobado");
    System.out.println("Enhorabuena"); // TRAMPA — esta línea NO está en el if
                                       // se ejecuta siempre

En el segundo ejemplo la indentación engaña, parece que las dos líneas están dentro del if pero sin llaves solo la primera lo está. La segunda se ejecuta siempre independientemente de la condición.

La recomendación para FP2: usa siempre llaves, aunque el bloque tenga una sola línea. Evita problemas y el código es más claro.

El operador ternario — if/else en una línea

Java tiene el operador ternario, una forma compacta de escribir un if/else que devuelve un valor:

# Python — expresión condicional
calificacion = "Aprobado" if nota >= 5 else "Suspenso"
// Java — operador ternario
// condición ? valor_si_verdadero : valor_si_falso
String calificacion = (nota >= 5) ? "Aprobado" : "Suspenso";

Se lee así: «si nota >= 5 entonces "Aprobado", si no "Suspenso"«.

int max = (a > b) ? a : b;             // el mayor de dos números
String paridad = (n % 2 == 0) ? "par" : "impar";
System.out.println((x > 0) ? "positivo" : "no positivo");

Úsalo para asignaciones simples. Cuando la lógica es más compleja usa if/else normal, el ternario anidado es ilegible:

// MAL — ternario anidado, difícil de leer
String nota = (n >= 9) ? "Matrícula" : (n >= 7) ? "Notable" : (n >= 5) ? "Aprobado" : "Suspenso";

// BIEN — if/else normal para lógica compleja
String nota;
if (n >= 9) nota = "Matrícula";
else if (n >= 7) nota = "Notable";
else if (n >= 5) nota = "Aprobado";
else nota = "Suspenso";

Switch/case en Java — comparativa con C

Si has visto el switch de C en IC2, el de Java te va a resultar casi idéntico, misma estructura, mismo break, mismo default. La diferencia principal es que Java permite usar Strings además de enteros:

// C — switch solo con enteros y chars
switch (opcion) {
    case 1:
        printf("Opción 1\n");
        break;
    case 2:
        printf("Opción 2\n");
        break;
    default:
        printf("Opción inválida\n");
}
// Java — switch con enteros, chars, Strings y enums
switch (opcion) {
    case 1:
        System.out.println("Opción 1");
        break;
    case 2:
        System.out.println("Opción 2");
        break;
    default:
        System.out.println("Opción inválida");
}

La estructura es prácticamente idéntica a C. Las diferencias:

  • Java admite String en el switch (C no)
  • System.out.println en vez de printf
  • Por lo demás — igual

Por qué break es obligatorio — el fall-through

El break al final de cada case no es decorativo, es lo que hace que el switch salga del bloque después de ejecutar ese caso. Sin break, Java continúa ejecutando el siguiente case aunque su condición no se cumpla, esto se llama fall-through y es el mismo comportamiento que en C:

int dia = 2;
switch (dia) {
    case 1:
        System.out.println("Lunes");
        // sin break — caemos al siguiente
    case 2:
        System.out.println("Martes");
        // sin break — caemos al siguiente
    case 3:
        System.out.println("Miércoles");
        break;
    case 4:
        System.out.println("Jueves");
        break;
}
// dia = 2, pero la salida es:
// Martes
// Miércoles
// (cayó desde case 2 hasta el break en case 3)
// Con break — correcto
int dia = 2;
switch (dia) {
    case 1:
        System.out.println("Lunes");
        break;
    case 2:
        System.out.println("Martes");    // solo esto se ejecuta
        break;
    case 3:
        System.out.println("Miércoles");
        break;
    default:
        System.out.println("Día inválido");
}
// → Martes

El fall-through a veces se usa intencionadamente cuando varios casos deben ejecutar el mismo código:

// Fall-through intencional — varios casos, misma acción
switch (dia) {
    case 1:
    case 2:
    case 3:
    case 4:
    case 5:
        System.out.println("Día laborable");
        break;
    case 6:
    case 7:
        System.out.println("Fin de semana");
        break;
}

Switch con String — lo que C no puede hacer

String comando = "salir";
switch (comando) {
    case "ayuda":
        System.out.println("Mostrando ayuda...");
        break;
    case "salir":
        System.out.println("Hasta luego");
        break;
    case "inicio":
        System.out.println("Volviendo al inicio...");
        break;
    default:
        System.out.println("Comando desconocido: " + comando);
}
// → Hasta luego

Internamente Java usa .equals() para comparar los Strings del switch, por eso funciona correctamente. No uses variables de tipo long, float o double en switch, solo int, char, String y enum.

Switch vs if/else — cuándo usar cada uno

Usa switch cuando:
  - Comparas una variable contra valores fijos y concretos
  - Hay 3 o más casos distintos
  - Los valores son enteros, chars o Strings

Usa if/else cuando:
  - Las condiciones son rangos (nota >= 5, nota < 7...)
  - Las condiciones mezclan varias variables
  - Solo hay 1 o 2 casos
// switch — perfecto para valores exactos
switch (mes) {
    case 1: System.out.println("Enero"); break;
    case 2: System.out.println("Febrero"); break;
    // ...
}

// if/else — necesario para rangos
if (nota >= 9) {
    System.out.println("Matrícula");
} else if (nota >= 7) {
    System.out.println("Notable");
}
// esto NO se puede hacer con switch

Un programa completo con todo junto

import java.util.Scanner;

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

        System.out.println("=== Calculadora de notas ===\n");

        System.out.print("Nombre del estudiante: ");
        String nombre = sc.nextLine();

        System.out.print("Nota del primer parcial (0-10): ");
        double parcial1 = sc.nextDouble();

        System.out.print("Nota del segundo parcial (0-10): ");
        double parcial2 = sc.nextDouble();
        sc.nextLine();    // limpiador de buffer

        double media = (parcial1 + parcial2) / 2;

        // Clasificación con if/else
        String calificacion;
        if (media >= 9) {
            calificacion = "Matrícula de Honor";
        } else if (media >= 7) {
            calificacion = "Notable";
        } else if (media >= 5) {
            calificacion = "Aprobado";
        } else {
            calificacion = "Suspenso";
        }

        // Operador ternario para estado
        String estado = (media >= 5) ? "APROBADO" : "SUSPENSO";

        // Salida formateada
        System.out.println("\n--- Resultado ---");
        System.out.printf("Estudiante:  %s%n", nombre);
        System.out.printf("Parcial 1:   %.2f%n", parcial1);
        System.out.printf("Parcial 2:   %.2f%n", parcial2);
        System.out.printf("Media:       %.2f%n", media);
        System.out.printf("Nota:        %s%n", calificacion);
        System.out.printf("Estado:      %s%n", estado);

        // Switch para mensaje según calificación
        System.out.print("\nMensaje: ");
        switch (calificacion) {
            case "Matrícula de Honor":
                System.out.println("¡Excelente trabajo!");
                break;
            case "Notable":
                System.out.println("Muy bien, sigue así.");
                break;
            case "Aprobado":
                System.out.println("Aprobado, pero puedes mejorar.");
                break;
            default:
                System.out.println("Ánimo, a por la próxima convocatoria.");
        }

        sc.close();
    }
}

Ejemplo de ejecución:

=== Calculadora de notas ===

Nombre del estudiante: Sergio
Nota del primer parcial (0-10): 7.5
Nota del segundo parcial (0-10): 8.0

--- Resultado ---
Estudiante:  Sergio
Parcial 1:   7.50
Parcial 2:   8.00
Media:       7.75
Nota:        Notable
Estado:      APROBADO

Mensaje: Muy bien, sigue así.

Resumen rápido

// IMPORTAR Scanner
import java.util.Scanner;    // siempre antes de la clase

// CREAR Scanner
Scanner sc = new Scanner(System.in);

// MÉTODOS DE LECTURA
sc.nextInt()        // lee int
sc.nextDouble()     // lee double
sc.nextLong()       // lee long
sc.next()           // lee palabra (hasta espacio)
sc.nextLine()       // lee línea completa (hasta Enter)
sc.nextBoolean()    // lee true/false

// PROBLEMA DEL BUFFER — solución
int n = sc.nextInt();
sc.nextLine();          // ← limpiador obligatorio antes de nextLine()
String s = sc.nextLine();

// CERRAR Scanner
sc.close();

// IF/ELSE
if (condicion) {
    ...
} else if (otraCondicion) {
    ...
} else {
    ...
}
// elif de Python = else if en Java

// OPERADORES LÓGICOS
// Python: and, or, not
// Java:   &&,  ||, !

// OPERADOR TERNARIO
tipo var = (condicion) ? valorSiVerdadero : valorSiFalso;
String s = (nota >= 5) ? "Aprobado" : "Suspenso";

// SWITCH — igual que en C pero admite String
switch (variable) {
    case valor1:
        // código
        break;       // obligatorio — sin él hay fall-through
    case valor2:
        // código
        break;
    default:         // equivale al else — opcional
        // código
}

// SWITCH vs IF/ELSE
// switch → valores exactos (int, char, String)
// if/else → rangos y condiciones complejas

// DIFERENCIAS CON C
// Java admite String en switch (C no)
// El fall-through funciona igual que en C
// break obligatorio igual que en C

En el próximo artículo vemos los bucles, for, for each y while en Java comparados con Python y C.


Input and control flow in Java — Scanner, if/else and switch from scratch

Control flow in Java covers two things that always go together in FP2: reading user input with Scanner and making decisions with if/else and switch. If you know Python you already know the logic. If you’ve seen C’s switch in IC2, Java’s is almost identical. What’s new is Scanner and the buffer problem, a silent trap that breaks entire programs if you don’t know it exists.

Importing classes in Java

import java.util.Scanner;    // before the class declaration

public class MyProgram {
    public static void main(String[] args) {
        // Scanner available here
    }
}

VS Code adds imports automatically, but knowing they exist matters.

What is Scanner and how to create it

# Python — one function for everything
name = input("Enter your name: ")
age = int(input("Enter your age: "))
// Java — create a Scanner object
import java.util.Scanner;

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

        System.out.print("Enter your name: ");
        String name = sc.nextLine();

        System.out.print("Enter your age: ");
        int age = sc.nextInt();

        System.out.println("Hello " + name + ", you are " + age);

        sc.close();
    }
}

new Scanner(System.in) creates a Scanner object connected to the keyboard. System.in is standard input, just as System.out is standard output.

Scanner methods — one per type

sc.nextInt()        // reads int
sc.nextLong()       // reads long
sc.nextDouble()     // reads double
sc.nextBoolean()    // reads true/false
sc.next()           // reads one word (stops at space)
sc.nextLine()       // reads full line (until Enter)

next() vs nextLine(): if the user types «Sergio Medina» and presses Enter, next() returns "Sergio", nextLine() returns "Sergio Medina".

The buffer problem — Scanner’s most common trap

When the user types a number and presses Enter, nextInt() reads the number but leaves the newline character \n in the buffer. A subsequent nextLine() reads that leftover \n instead of waiting for user input — returning an empty string:

Scanner sc = new Scanner(System.in);

System.out.print("Age: ");
int age = sc.nextInt();        // reads "22", leaves "\n" in buffer

System.out.print("Name: ");
String name = sc.nextLine();   // reads the leftover "\n" → name = ""
                               // program doesn't wait for user input

System.out.println("Hello " + name);    // → "Hello "

The program seems to skip the name question. It didn’t, it answered automatically with the leftover Enter.

The fix, add an empty sc.nextLine() after any nextInt(), nextDouble() etc. to consume the leftover \n:

int age = sc.nextInt();
sc.nextLine();              // ← cleaner — consumes leftover "\n"

String name = sc.nextLine();    // now waits for user input

Rule: whenever you use nextInt(), nextDouble() etc. and then need nextLine(), always add an empty sc.nextLine() between them.

Alternative read everything as String and convert:

int age = Integer.parseInt(sc.nextLine());    // no buffer problem
String name = sc.nextLine();

if/else — same logic as Python, different syntax

# Python
if grade >= 9:
    print("Distinction")
elif grade >= 7:
    print("Merit")
elif grade >= 5:
    print("Pass")
else:
    print("Fail")
// Java
if (grade >= 9) {
    System.out.println("Distinction");
} else if (grade >= 7) {
    System.out.println("Merit");
} else if (grade >= 5) {
    System.out.println("Pass");
} else {
    System.out.println("Fail");
}

Key differences from Python:

  • Condition in parentheses (grade >= 9) — required
  • elifelse if (two words)
  • Curly braces { } delimit blocks — no colons

Logical operators:

# Python: and, or, not
// Java:  &&,  ||, !
if (a > 0 && b > 0) { ... }
if (a > 0 || b > 0) { ... }
if (!active) { ... }

Ternary operator

# Python
result = "Pass" if grade >= 5 else "Fail"
// Java — condition ? value_if_true : value_if_false
String result = (grade >= 5) ? "Pass" : "Fail";
int max = (a > b) ? a : b;

Use for simple assignments, not for complex nested logic.

switch/case — comparison with C

If you’ve used C’s switch in IC2, Java’s is nearly identical, same structure, same break, same default. The main addition: Java allows Strings:

// C — integers and chars only
switch (option) {
    case 1: printf("Option 1\n"); break;
    case 2: printf("Option 2\n"); break;
    default: printf("Invalid\n");
}
// Java — integers, chars, Strings and enums
switch (option) {
    case 1:
        System.out.println("Option 1");
        break;
    case 2:
        System.out.println("Option 2");
        break;
    default:
        System.out.println("Invalid");
}

Why break is required — fall-through

Without break, Java continues executing the next case even if its value doesn’t match, same as C:

int day = 2;
switch (day) {
    case 2:
        System.out.println("Tuesday");    // executes
        // no break — falls through
    case 3:
        System.out.println("Wednesday");  // also executes
        break;
}
// Output: Tuesday
//         Wednesday

Intentional fall-through, multiple cases, same action:

switch (day) {
    case 1: case 2: case 3: case 4: case 5:
        System.out.println("Weekday");
        break;
    case 6: case 7:
        System.out.println("Weekend");
        break;
}

switch with String — what C can’t do

String command = "quit";
switch (command) {
    case "help":
        System.out.println("Showing help...");
        break;
    case "quit":
        System.out.println("Goodbye");
        break;
    default:
        System.out.println("Unknown command: " + command);
}

Java uses .equals() internally to compare Strings in switch, so it works correctly.

switch vs if/else — when to use each

Use switch: comparing one variable against exact fixed values
            3+ distinct cases
            int, char, or String values

Use if/else: ranges (grade >= 5, grade < 7...)
             conditions mixing multiple variables
             1-2 cases

Quick summary

// IMPORT
import java.util.Scanner;

// CREATE
Scanner sc = new Scanner(System.in);

// READ METHODS
sc.nextInt()       sc.nextDouble()    sc.nextLong()
sc.next()          sc.nextLine()      sc.nextBoolean()

// BUFFER FIX
int n = sc.nextInt();
sc.nextLine();         // ← cleaner — always here before nextLine()
String s = sc.nextLine();

// CLOSE
sc.close();

// IF/ELSE
if (condition) { ... }
else if (condition) { ... }
else { ... }

// LOGICAL OPERATORS
// Python: and   or   not
// Java:   &&    ||   !

// TERNARY
type var = (condition) ? valueIfTrue : valueIfFalse;

// SWITCH — same as C but accepts String
switch (variable) {
    case value1:
        // code
        break;     // required — prevents fall-through
    case value2:
        // code
        break;
    default:
        // code
}

// DIFFERENCES FROM C
// Java accepts String in switch (C does not)
// Fall-through works the same as C
// break required the same as C

Publicaciones Similares

Un comentario

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *