Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Sintaxis de Java: Control de Flujo

Universidad Nacional de Rio Negro - Sede Andina

La sintaxis de Java para el control de flujo hereda la claridad de C, pero introduce salvaguardas críticas para la robustez del software. En esta materia, nos enfocamos en el uso preciso de estas estructuras para construir algoritmos eficientes y seguros.

El control de flujo se refiere a las instrucciones que determinan el orden en que se ejecutan las sentencias de un programa. Sin estructuras de control, un programa ejecutaría sus instrucciones de forma secuencial, de arriba hacia abajo, sin posibilidad de tomar decisiones o repetir acciones. Las estructuras de control permiten:

Lógica Booleana y Cortocircuito

Una de las diferencias fundamentales con C es que en Java el tipo boolean no es un entero. Por lo tanto, estructuras como if (1) son errores de compilación.

En C, cualquier valor distinto de cero se interpreta como verdadero y cero como falso. Esto permite escribir código como if (x) donde x es un entero, lo cual puede ser fuente de errores sutiles. Java elimina esta ambigüedad: las condiciones deben ser expresiones booleanas.

// En C esto es válido (pero peligroso):
// if (x = 5) { ... }  // Asigna 5 a x, evalúa como verdadero

// En Java esto NO compila (error de tipos):
int x = 5;
// if (x) { }        // Error: incompatible types: int cannot be converted to boolean
if (x != 0) { }      // Correcto: expresión booleana explícita

Diferencia entre C y Java en condiciones

Operadores Relacionales

Los operadores relacionales comparan dos valores y devuelven un resultado boolean (true o false). Son idénticos a los de C:

OperadorSignificadoEjemploResultado si x = 5
==Igual ax == 5true
!=Distinto dex != 5false
<Menor quex < 5false
>Mayor quex > 5false
<=Menor o igual quex <= 5true
>=Mayor o igual quex >= 5true

Operadores Lógicos

Los operadores lógicos combinan expresiones booleanas para formar condiciones más complejas:

OperadorSignificadoEjemploDescripción
&&AND lógico (con cortocircuito)a && btrue solo si ambos son true
||OR lógico (con cortocircuito)a || btrue si al menos uno es true
!NOT lógico (negación)!aInvierte el valor booleano

Estos operadores son idénticos a los de C, pero solo funcionan con operandos booleanos (no con enteros).

boolean esMayor = true;
boolean tieneDNI = false;

// AND: ambas condiciones deben ser verdaderas
boolean puedeVotar = esMayor && tieneDNI;  // false

// OR: al menos una condición debe ser verdadera
boolean puedeEntrar = esMayor || tieneDNI;  // true

// NOT: invierte el valor
boolean esmenor = !esMayor;  // false

Uso de operadores lógicos

Tabla de Verdad de los Operadores Lógicos

aba && ba || b!a
truetruetruetruefalse
truefalsefalsetruefalse
falsetruefalsetruetrue
falsefalsefalsefalsetrue

Evaluación en Cortocircuito (Short-circuit Evaluation)

Los operadores && (AND) y || (OR) realizan una evaluación perezosa o en cortocircuito. Esto significa que Java deja de evaluar la expresión tan pronto como puede determinar el resultado final:

Esta característica no es solo una optimización de rendimiento; es una herramienta fundamental para escribir código seguro.

Diagrama de evaluación en cortocircuito: cuando la primera condición determina el resultado, la segunda no se evalúa.

Figure 1:Diagrama de evaluación en cortocircuito: cuando la primera condición determina el resultado, la segunda no se evalúa.

Operadores Lógicos Sin Cortocircuito

Java también proporciona los operadores & y | (un solo símbolo) que evalúan ambos operandos siempre, incluso si el resultado ya está determinado. Estos se usan raramente y principalmente cuando los operandos tienen efectos secundarios que deben ejecutarse.

int x = 0;
boolean resultado1 = (false && (++x > 0));  // x sigue siendo 0
boolean resultado2 = (false & (++x > 0));   // x ahora es 1 (se evaluó ++x)

Diferencia entre & y &&

Estructuras Condicionales

Las estructuras condicionales permiten que un programa tome decisiones durante su ejecución. En lugar de seguir un camino lineal, el programa puede elegir entre diferentes bloques de código según el valor de una condición.

En términos de flujo de programa, las estructuras condicionales crean bifurcaciones: puntos donde el camino de ejecución se divide en dos o más alternativas.

La Sentencia if

La sentencia if es la estructura condicional más básica. Ejecuta un bloque de código solo si una condición es verdadera.

if (condicion) {
    // código que se ejecuta si condicion es true
}
// La ejecución continúa aquí, independientemente de la condición

Estructura básica del if

Anatomía del if:

La condición debe ser una expresión que evalúe a boolean. A diferencia de C, no se puede usar un entero directamente.

int temperatura = 35;

if (temperatura > 30) {
    System.out.println("Hace calor");
}
// Si temperatura es 25, no se imprime nada y el programa continúa

Ejemplo de if simple

La Sentencia if-else

Permite ejecutar un bloque alternativo cuando la condición es falsa. Esto crea una bifurcación completa: el programa siempre ejecutará exactamente uno de los dos bloques.

if (condicion) {
    // código si condicion es true (rama verdadera)
} else {
    // código si condicion es false (rama falsa)
}

Estructura if-else

int edad = 17;

if (edad >= 18) {
    System.out.println("Es mayor de edad");
} else {
    System.out.println("Es menor de edad");
}
// Siempre se imprime exactamente uno de los dos mensajes

Ejemplo de if-else

La Sentencia if-else if-else

Cuando se necesitan evaluar múltiples condiciones mutuamente excluyentes, se encadenan sentencias else if. Esta estructura crea una cadena de decisiones donde solo se ejecuta el primer bloque cuya condición sea verdadera.

if (condicion1) {
    // código si condicion1 es true
} else if (condicion2) {
    // código si condicion1 es false y condicion2 es true
} else if (condicion3) {
    // código si condicion1 y condicion2 son false y condicion3 es true
} else {
    // código si ninguna condición anterior es true (opcional pero recomendado)
}

Estructura if-else if-else

Características importantes:

int nota = 75;
String clasificacion;

if (nota >= 90) {
    clasificacion = "Sobresaliente";
} else if (nota >= 80) {
    clasificacion = "Muy bueno";
} else if (nota >= 70) {
    clasificacion = "Bueno";
} else if (nota >= 60) {
    clasificacion = "Regular";
} else {
    clasificacion = "Insuficiente";
}
// Si nota es 75, solo se ejecuta clasificacion = "Bueno"
// Las condiciones >= 60 nunca se evalúan porque ya se encontró una verdadera

Ejemplo de clasificación de notas

Condicionales Anidados

Es posible colocar estructuras if dentro de otras estructuras if. Esto se llama anidamiento y permite expresar condiciones más complejas.

int edad = 25;
boolean tieneLicencia = true;

if (edad >= 18) {
    System.out.println("Es mayor de edad");
    if (tieneLicencia) {
        System.out.println("Puede conducir");
    } else {
        System.out.println("Necesita obtener licencia");
    }
} else {
    System.out.println("Es menor de edad, no puede conducir");
}

Ejemplo de if anidado

El Operador Ternario ? :

El operador ternario (también llamado operador condicional) es una forma compacta de expresar una selección entre dos valores. Es el único operador de Java que toma tres operandos.

resultado = condicion ? valorSiTrue : valorSiFalse;

Sintaxis del operador ternario

Funcionamiento:

  1. Se evalúa la condicion

  2. Si es true, el resultado es valorSiTrue

  3. Si es false, el resultado es valorSiFalse

int edad = 20;
String estado = (edad >= 18) ? "Mayor" : "Menor";

// Equivale a:
String estado2;
if (edad >= 18) {
    estado2 = "Mayor";
} else {
    estado2 = "Menor";
}

Ejemplo del operador ternario

El operador ternario es una expresión (devuelve un valor), no una sentencia. Por eso puede usarse en cualquier lugar donde se espere un valor:

// En una asignación
int maximo = (a > b) ? a : b;

// En una llamada a método
System.out.println("El valor es " + ((x > 0) ? "positivo" : "no positivo"));

// En un return
return (lista.isEmpty()) ? valorPorDefecto : lista.get(0);

Usos del operador ternario como expresión

La Sentencia switch

El switch permite seleccionar entre múltiples alternativas basándose en el valor de una expresión. Es útil cuando se compara una variable contra varios valores constantes, especialmente cuando hay muchas alternativas.

Diferencia conceptual con if-else if:

El switch es más legible cuando se tienen muchas comparaciones de igualdad contra el mismo valor.

Switch Clásico (Sentencia)

La versión clásica del switch requiere break para evitar el “fall-through” (caída en cascada hacia el siguiente caso).

switch (expresion) {
    case valor1:
        // código para valor1
        break;
    case valor2:
        // código para valor2
        break;
    case valor3:
    case valor4:
        // código para valor3 O valor4 (casos agrupados)
        break;
    default:
        // código si ningún caso coincide
        break;
}

Estructura del switch clásico

Anatomía del switch:

int diaSemana = 3;
String nombreDia;

switch (diaSemana) {
    case 1:
        nombreDia = "Lunes";
        break;
    case 2:
        nombreDia = "Martes";
        break;
    case 3:
        nombreDia = "Miércoles";
        break;
    case 4:
        nombreDia = "Jueves";
        break;
    case 5:
        nombreDia = "Viernes";
        break;
    case 6:
    case 7:
        nombreDia = "Fin de semana";  // Casos 6 y 7 comparten el mismo código
        break;
    default:
        nombreDia = "Día inválido";
        break;
}

Ejemplo de switch con días de la semana

Tipos de datos permitidos en el switch clásico:

String comando = "salir";

switch (comando) {
    case "iniciar":
        System.out.println("Iniciando...");
        break;
    case "pausar":
        System.out.println("Pausando...");
        break;
    case "salir":
        System.out.println("Saliendo...");
        break;
    default:
        System.out.println("Comando no reconocido");
        break;
}

Switch con String

Switch Moderno (Expresión, Java 14+)

El switch moderno utiliza la flecha -> para eliminar el riesgo de caída accidental y puede devolver un valor directamente. Esta versión es más segura y concisa.

Diferencias con el switch clásico:

int diaSemana = 3;
String nombreDia = switch (diaSemana) {
    case 1 -> "Lunes";
    case 2 -> "Martes";
    case 3 -> "Miércoles";
    case 4 -> "Jueves";
    case 5 -> "Viernes";
    case 6, 7 -> "Fin de semana";  // Múltiples valores en un caso
    default -> "Día inválido";
};  // Nota el punto y coma: es una expresión que termina en asignación

Switch expresión con sintaxis de flecha

Cuando se necesita ejecutar varias sentencias en un caso, se usa un bloque con yield para retornar el valor:

String descripcion = switch (estado) {
    case ACTIVO -> "Sistema funcionando";
    case PENDIENTE -> {
        System.out.println("Procesando pendiente...");
        yield "Esperando confirmación";  // yield retorna el valor del bloque
    }
    case ERROR -> {
        registrarError();
        notificarAdministrador();
        yield "Sistema en error";
    }
    default -> "Estado desconocido";
};

Switch con bloques múltiples líneas y yield

Estructuras de Repetición: Lazos

En Java, utilizamos el término lazos para referirnos a los bucles o ciclos. Los lazos permiten ejecutar un bloque de código múltiples veces sin tener que escribirlo repetidamente.

Los lazos son fundamentales para:

Cada tipo de lazo tiene una semántica específica según el punto de evaluación de la condición:

Comparación del flujo de ejecución entre for, while y do-while. Observá cuándo se evalúa la condición en cada caso.

Figure 2:Comparación del flujo de ejecución entre for, while y do-while. Observá cuándo se evalúa la condición en cada caso.

El Lazo for

El lazo for es ideal cuando se conoce de antemano la cantidad de iteraciones. Consta de tres partes separadas por punto y coma: inicialización, condición y actualización.

for (inicializacion; condicion; actualizacion) {
    // código que se repite mientras condicion sea true
}

Estructura del lazo for

Las tres partes del for:

  1. Inicialización: Se ejecuta una sola vez, antes de la primera iteración. Generalmente declara e inicializa la variable de control.

  2. Condición: Se evalúa antes de cada iteración. Si es true, se ejecuta el cuerpo; si es false, el lazo termina.

  3. Actualización: Se ejecuta después de cada iteración, antes de volver a evaluar la condición. Generalmente modifica la variable de control.

La ejecución sigue este orden:

  1. Se ejecuta la inicialización (una sola vez)

  2. Se evalúa la condición

  3. Si es true, se ejecuta el cuerpo del lazo

  4. Se ejecuta la actualización

  5. Se vuelve al paso 2

for (int i = 1; i <= 5; i = i + 1) {
    System.out.println(i);
}
// Imprime: 1, 2, 3, 4, 5

// Traza de ejecución:
// i=1: condición 1<=5 es true, imprime 1, actualiza i=2
// i=2: condición 2<=5 es true, imprime 2, actualiza i=3
// i=3: condición 3<=5 es true, imprime 3, actualiza i=4
// i=4: condición 4<=5 es true, imprime 4, actualiza i=5
// i=5: condición 5<=5 es true, imprime 5, actualiza i=6
// i=6: condición 6<=5 es false, termina el lazo

Ejemplo de for que imprime números del 1 al 5

for (int i = 10; i >= 0; i = i - 1) {
    System.out.println(i);
}
// Imprime: 10, 9, 8, ..., 1, 0

Ejemplo de for con conteo descendente

// Imprimir números pares del 0 al 20
for (int i = 0; i <= 20; i = i + 2) {
    System.out.println(i);
}
// Imprime: 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20

Ejemplo de for con incremento diferente

Partes Opcionales del for

Todas las partes del for son opcionales (aunque se deben mantener los punto y coma):

// Variable ya inicializada afuera
int i = 0;
for (; i < 10; i = i + 1) {
    System.out.println(i);
}

// Actualización dentro del cuerpo
for (int j = 0; j < 10; ) {
    System.out.println(j);
    j = j + 1;
}

// Lazo infinito (usar con cuidado)
// for (;;) {
//     // Se ejecuta indefinidamente
// }

Variantes del for

El Lazo while

El lazo while evalúa la condición antes de ejecutar el cuerpo. Si la condición es falsa desde el inicio, el cuerpo nunca se ejecuta (cero iteraciones).

while (condicion) {
    // código que se repite mientras condicion sea true
}

Estructura del lazo while

Características del while:

int suma = 0;
int numero = 1;

while (suma < 100) {
    suma = suma + numero;
    numero = numero + 1;
}

System.out.println("Suma final: " + suma);
System.out.println("Último número sumado: " + (numero - 1));

// Traza: suma=0, agrega 1 (suma=1), agrega 2 (suma=3), agrega 3 (suma=6)...
// Continúa hasta que suma >= 100

Ejemplo de while para sumar números hasta llegar a un límite

int x = 10;

while (x < 5) {  // Condición es false desde el inicio
    System.out.println(x);  // Nunca se ejecuta
    x = x + 1;
}

System.out.println("Lazo terminado");  // Se imprime directamente

Ejemplo de while que no ejecuta ninguna iteración

Patrón recomendado: búsqueda con bandera booleana en lugar de break. La bandera encontrado controla la terminación anticipada del lazo.

Figure 3:Patrón recomendado: búsqueda con bandera booleana en lugar de break. La bandera encontrado controla la terminación anticipada del lazo.

boolean encontrado = false;  // Bandera: indica si encontramos el valor
int indice = 0;

// El lazo continúa mientras no hayamos encontrado Y queden elementos
while (indice < cantidad && !encontrado) {
    if (elementos[indice] == valorBuscado) {
        encontrado = true;  // Encontramos el valor, el lazo terminará
        // NO incrementamos indice para conservar la posición encontrada
    } else {
        indice = indice + 1;  // Avanzar solo si no encontramos
    }
}

// Después del lazo, verificamos qué pasó
if (encontrado) {
    System.out.println("Encontrado en posición: " + indice);
} else {
    System.out.println("No encontrado");
}

Búsqueda con bandera (patrón recomendado)

Este patrón tiene varias ventajas:

El Lazo do-while

El lazo do-while evalúa la condición después de ejecutar el cuerpo. Esto garantiza que el cuerpo se ejecuta al menos una vez, independientemente del valor de la condición.

do {
    // código que se ejecuta al menos una vez
} while (condicion);  // Nota: termina con punto y coma

Estructura del lazo do-while

Características del do-while:

int opcion;
do {
    System.out.println("Menú:");
    System.out.println("1. Opción A");
    System.out.println("2. Opción B");
    System.out.println("0. Salir");
    System.out.print("Seleccione: ");
    opcion = scanner.nextInt();
} while (opcion != 0);

// El menú se muestra al menos una vez antes de verificar si el usuario quiere salir

Ejemplo de do-while para validar entrada

int numero;
do {
    System.out.print("Ingrese un número entre 1 y 10: ");
    numero = scanner.nextInt();
    
    if (numero < 1 || numero > 10) {
        System.out.println("Valor fuera de rango. Intente nuevamente.");
    }
} while (numero < 1 || numero > 10);

System.out.println("Número válido ingresado: " + numero);

Ejemplo de do-while para validar rango

Diferencia entre while y do-while

int x = 100;

// Con while: no se ejecuta ninguna vez
while (x < 10) {
    System.out.println("while: " + x);
    x = x + 1;
}

// Con do-while: se ejecuta exactamente una vez
do {
    System.out.println("do-while: " + x);  // Imprime "do-while: 100"
    x = x + 1;
} while (x < 10);

Comparación con condición inicialmente falsa

Comparación de Lazos

LazoEvaluación de CondiciónEjecución MínimaUso TípicoEstructura Equivalente en C
forAntes de cada iteración0 vecesCantidad de iteraciones conocidaIdéntica
whileAntes de cada iteración0 vecesCantidad de iteraciones desconocidaIdéntica
do-whileDespués de cada iteración1 vezSe requiere al menos una ejecuciónIdéntica

Guía para elegir el lazo correcto:

// FOR: cuando conocés la cantidad de iteraciones
// "Hacer algo N veces" o "recorrer de A a B"
for (int i = 0; i < 10; i = i + 1) {
    // Exactamente 10 iteraciones (0 a 9)
}

// WHILE: cuando no sabés cuántas iteraciones, pero podría ser cero
// "Mientras haya datos" o "hasta que se cumpla X"
while (hayMasDatos()) {
    procesarSiguiente();
}

// DO-WHILE: cuando necesitás al menos una iteración
// "Hacer al menos una vez, repetir si es necesario"
do {
    pedirDato();
} while (!datoValido());

Cuándo usar cada tipo de lazo

Equivalencia entre for y while

Todo lazo for puede reescribirse como while y viceversa. La elección entre uno u otro es principalmente una cuestión de claridad y convención:

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

Lazo for

int i = 0;                    // Inicialización (antes del lazo)
while (i < 10) {              // Condición
    System.out.println(i);
    i = i + 1;                // Actualización (al final del cuerpo)
}

Equivalente con while

Lazos Anidados

Es posible colocar un lazo dentro de otro. El lazo interno se ejecuta completamente por cada iteración del lazo externo. Esto es útil para trabajar con estructuras bidimensionales (matrices) o generar combinaciones.

for (int fila = 1; fila <= 5; fila = fila + 1) {
    for (int columna = 1; columna <= 5; columna = columna + 1) {
        int producto = fila * columna;
        System.out.print(producto + "\t");  // \t es tabulador
    }
    System.out.println();  // Nueva línea después de cada fila
}

// Salida:
// 1    2    3    4    5
// 2    4    6    8    10
// 3    6    9    12   15
// 4    8    12   16   20
// 5    10   15   20   25

Ejemplo de lazos anidados (tabla de multiplicar)

Análisis de la ejecución:

for (int i = 1; i <= 3; i = i + 1) {
    System.out.println("Lazo externo: i = " + i);
    for (int j = 1; j <= 2; j = j + 1) {
        System.out.println("  Lazo interno: j = " + j);
    }
}

// Salida:
// Lazo externo: i = 1
//   Lazo interno: j = 1
//   Lazo interno: j = 2
// Lazo externo: i = 2
//   Lazo interno: j = 1
//   Lazo interno: j = 2
// Lazo externo: i = 3
//   Lazo interno: j = 1
//   Lazo interno: j = 2

Traza de lazos anidados

Lazos Infinitos y Cómo Evitarlos

Un lazo infinito es un lazo cuya condición nunca se vuelve falsa, causando que el programa se ejecute indefinidamente (hasta que se lo detenga externamente o se agote algún recurso).

// Error 1: Condición siempre verdadera
while (true) {
    System.out.println("Infinito!");
}

// Error 2: Variable de control no modificada
int i = 0;
while (i < 10) {
    System.out.println(i);
    // Falta: i = i + 1;
}

// Error 3: Actualización en dirección incorrecta
for (int j = 0; j < 10; j = j - 1) {  // j decrece, nunca llega a 10
    System.out.println(j);
}

// Error 4: Condición que no puede volverse falsa
int k = 1;
while (k != 10) {  // k solo toma valores impares
    System.out.println(k);
    k = k + 2;  // k: 1, 3, 5, 7, 9, 11, 13, ... nunca es 10
}

Ejemplos de lazos infinitos (errores comunes)

Cómo evitar lazos infinitos:

  1. Verificar que la variable de control se modifique en cada iteración

  2. Verificar que la modificación acerque la condición a ser falsa

  3. Usar condiciones con < o > en lugar de != cuando sea posible

  4. Evitar punto flotante como variables de control

Sentencias de Control de Flujo: break y continue

Java proporciona las sentencias break y continue para alterar el flujo normal de los lazos. Estas sentencias permiten salir anticipadamente de un lazo o saltar a la siguiente iteración.

La Sentencia break

La sentencia break termina inmediatamente el lazo más interno que la contiene. La ejecución continúa en la primera sentencia después del lazo.

// Búsqueda con break - NO USAR en este curso
for (int i = 0; i < 100; i = i + 1) {
    if (valores[i] == buscado) {
        System.out.println("Encontrado en: " + i);
        break;  // Sale del lazo inmediatamente
    }
}

// Equivalente con bandera (USAR en este curso)
boolean encontrado = false;
int i = 0;
while (i < 100 && !encontrado) {
    if (valores[i] == buscado) {
        encontrado = true;
    } else {
        i = i + 1;
    }
}
if (encontrado) {
    System.out.println("Encontrado en: " + i);
}

Ejemplo de break (uso general, NO permitido en este curso)

La Sentencia continue

La sentencia continue salta a la siguiente iteración del lazo, omitiendo el resto del código en la iteración actual. En un for, ejecuta la actualización antes de verificar la condición.

// Imprimir solo impares con continue - NO USAR en este curso
for (int i = 0; i < 10; i = i + 1) {
    if (i % 2 == 0) {
        continue;  // Salta los números pares
    }
    System.out.println(i);  // Solo imprime impares
}

// Equivalente sin continue (USAR en este curso)
for (int i = 0; i < 10; i = i + 1) {
    if (i % 2 != 0) {  // Condición invertida
        System.out.println(i);
    }
}

Ejemplo de continue (uso general, NO permitido en este curso)

Uso Permitido de break: en switch

El único lugar donde break está permitido en este curso es dentro de sentencias switch, donde es necesario para evitar el fall-through:

switch (opcion) {
    case 1:
        hacerOpcion1();
        break;  // Permitido y necesario
    case 2:
        hacerOpcion2();
        break;  // Permitido y necesario
    default:
        hacerDefault();
        break;
}

break permitido en switch

Comparativa de Seguridad con C

Java hereda la sintaxis de control de flujo de C pero añade verificaciones que previenen errores comunes:

1. Asignación en Condiciones

En C, if (x = 5) es un error común que asigna 5 a x y evalúa a verdadero (porque 5 es distinto de cero). En Java, esto falla en compilación (a menos que x sea boolean), previniendo errores lógicos sutiles.

int x = 0;

// En C esto compila y siempre es verdadero (asigna 5 a x)
// En Java esto NO compila:
// if (x = 5) { }  // Error: incompatible types: int cannot be converted to boolean

// Forma correcta:
if (x == 5) { }  // Comparación

Protección contra asignación accidental

2. Inicialización Obligatoria

Java exige que las variables locales estén inicializadas antes de ser usadas en cualquier estructura de control. El compilador analiza todos los caminos posibles.

int resultado;

if (condicion) {
    resultado = 10;
}

// Error de compilación: variable resultado might not have been initialized
// System.out.println(resultado);

// Correcto: inicializar en todas las ramas
if (condicion) {
    resultado = 10;
} else {
    resultado = 0;
}
System.out.println(resultado);  // OK

Verificación de inicialización

3. Tipo Booleano Estricto

Las condiciones deben ser expresiones boolean. No se puede usar un entero, referencia a objeto, o cualquier otro tipo directamente como condición.

int cantidad = 5;
String texto = "hola";

// Estos NO compilan en Java (sí en C):
// if (cantidad) { }      // Error: int no es boolean
// while (texto) { }      // Error: String no es boolean

// Forma correcta:
if (cantidad != 0) { }     // Comparación explícita
while (texto != null) { }  // Comparación explícita

Condiciones estrictamente booleanas

4. Alcance de Variables en Lazos

En Java moderno, declarar la variable de control en el for la limita al ámbito del lazo, evitando conflictos de nombres y uso accidental posterior.

for (int i = 0; i < 10; i = i + 1) {
    System.out.println(i);
}
// i no existe aquí - evita errores

for (int i = 0; i < 5; i = i + 1) {
    // Esta i es diferente, sin conflicto
    System.out.println(i);
}

Alcance limitado de variables de control

Estas diferencias hacen que Java sea más seguro que C para programación a gran escala, aunque la sintaxis sea visualmente similar.

Ejercicios de Nivel Universitario

Gracias al **cortocircuito** del operador `&&`, si `x` es 0, la primera condición `(x != 0)` evalúa a `false`. En ese momento, Java detiene la evaluación de la expresión completa porque ya sabe que el resultado será `false` (en un AND, si uno es falso, todo es falso). Por lo tanto, la segunda parte `(y / x > 1)` **nunca se ejecuta** cuando `x` es 0, evitando así la división por cero. Este patrón es muy común para proteger operaciones que podrían fallar: ```java // Proteger división if (divisor != 0 && dividendo / divisor > limite) { ... } // Proteger acceso a arreglo if (indice >= 0 && indice < arr.length && arr[indice] == valor) { ... } // Proteger referencia nula if (objeto != null && objeto.metodo()) { ... }

```{exercise}
:label: ej-for-while
Reescribí el siguiente lazo `for` como un lazo `while` equivalente:

`for (int i = 10; i > 0; i = i - 2) { System.out.println(i); }`
```java int i = 10; // Inicialización: antes del while while (i > 0) { // Condición: en el while System.out.println(i); i = i - 2; // Actualización: al final del cuerpo } ``` **Análisis de la conversión:** 1. La **inicialización** (`int i = 10`) se mueve antes del `while` 2. La **condición** (`i > 0`) se coloca en el `while` 3. La **actualización** (`i = i - 2`) se coloca al final del cuerpo del lazo Ambos lazos imprimen: 10, 8, 6, 4, 2 **Nota**: Cuando la variable se declara fuera del `while`, su alcance es mayor (existe después del lazo). En el `for` original, `i` deja de existir al terminar el lazo.```java Scanner scanner = new Scanner(System.in); boolean encontrado = false; // Bandera: ¿encontramos un negativo? int posicion = 0; // Posición donde se encontró int contador = 0; // Contador de números ingresados while (contador < 10 && !encontrado) { System.out.print("Ingrese número " + (contador + 1) + ": "); int numero = scanner.nextInt(); if (numero < 0) { encontrado = true; posicion = contador; // NO incrementamos contador para conservar la posición correcta } else { contador = contador + 1; } } // Verificar resultado después del lazo if (encontrado) { System.out.println("Primer negativo en posición: " + (posicion + 1)); } else { System.out.println("No se encontraron números negativos"); } ``` **Puntos clave del patrón:** - La condición `!encontrado` permite salir del lazo anticipadamente - Solo incrementamos `contador` cuando NO encontramos (para conservar la posición) - Después del lazo, la bandera indica si la búsqueda fue exitosaLa diferencia fundamental es el **momento de evaluación de la condición**: - `while` evalúa la condición **antes** de ejecutar el cuerpo (puede ejecutarse 0 veces) - `do-while` evalúa la condición **después** (se ejecuta **al menos 1 vez**) Un caso apropiado para `do-while` es la **validación de entrada** donde necesitamos al menos un intento: ```java int numero; do { System.out.print("Ingrese un número entre 1 y 10: "); numero = scanner.nextInt(); if (numero < 1 || numero > 10) { System.out.println("Valor inválido. Intente nuevamente."); } } while (numero < 1 || numero > 10); System.out.println("Número válido: " + numero); ``` **¿Por qué `do-while` es mejor aquí?** - Siempre necesitamos pedir **al menos un número** antes de verificar si es válido - Con `while`, tendríamos que duplicar el código de entrada o usar una variable auxiliar inicializada con un valor inválido - El `do-while` expresa naturalmente la semántica de "hacer algo y repetir si es necesario"**Cuándo preferir `switch`:** - Cuando se compara **una variable** contra **múltiples valores constantes** - Cuando hay **más de 2-3 alternativas** - Cuando los valores son del tipo compatible con switch (int, char, String, enum) **Código reescrito con switch:** ```java // Switch clásico String tipo; switch (codigo) { case 1: tipo = "Estudiante"; break; case 2: tipo = "Docente"; break; case 3: tipo = "Administrativo"; break; default: tipo = "Desconocido"; break; } // Switch moderno (Java 14+) - más conciso String tipo = switch (codigo) { case 1 -> "Estudiante"; case 2 -> "Docente"; case 3 -> "Administrativo"; default -> "Desconocido"; };

El switch es más legible cuando hay muchas comparaciones de igualdad contra el mismo valor.


````{exercise}
:label: ej-lazos-anidados
Escribí un programa que imprima el siguiente patrón usando lazos anidados:

**




```java for (int fila = 1; fila <= 5; fila = fila + 1) { for (int columna = 1; columna <= fila; columna = columna + 1) { System.out.print("*"); } System.out.println(); // Nueva línea después de cada fila } ``` **Análisis:** - El lazo externo controla las **filas** (de 1 a 5) - El lazo interno controla las **columnas** (de 1 hasta el número de fila actual) - En la fila 1, el lazo interno ejecuta 1 vez (imprime 1 asterisco) - En la fila 2, el lazo interno ejecuta 2 veces (imprime 2 asteriscos) - Y así sucesivamente... **Traza:** | Fila | Columnas | Asteriscos | |:---:|:---:|:---| | 1 | 1 | * | | 2 | 1, 2 | ** | | 3 | 1, 2, 3 | *** | | 4 | 1, 2, 3, 4 | **** | | 5 | 1, 2, 3, 4, 5 | ***** |

Referencias Bibliográficas


- {ref}`regla-0x5001` - Estilo de llaves y bloques en estructuras de control.
- {ref}`regla-0xE001` - Comparación de tipos primitivos vs objetos.