Control de flujo de Java: sentencias if y if-else

Las declaraciones condicionales y los bucles son una herramienta muy importante en la programación. No hay muchas cosas que podamos hacer con un código que solo puede ejecutarse línea por línea...

Introducción

Las declaraciones condicionales y los bucles son una herramienta muy importante en la programación. No hay muchas cosas que podamos hacer con un código que solo puede ejecutarse línea por línea.

Eso es lo que significa "control de flujo": guiar la ejecución de nuestro programa, en lugar de dejar que se ejecute línea por línea, independientemente de cualquier factor interno o externo. Cada lenguaje de programación admite alguna forma de control de flujo, si no explícitamente a través de ifs y fors o declaraciones similares, implícitamente nos brinda las herramientas para crear tales construcciones, es decir, los lenguajes de programación de bajo nivel generalmente logran ese efecto con una gran cantidad de comandos go-to.

Los bucles eran un concepto utilizado mucho antes de que existiera la programación informática, pero la primera persona en utilizar un bucle de software fue Ada Lovelace, comúnmente conocida por su apellido de soltera - Byron, mientras calculaba [Números de Bernoulli](https://en .wikipedia.org/wiki/Bernoulli_number), allá por el siglo XIX.

Los comandos go-to se deben evitar en la mayoría de las situaciones, siempre que estemos usando un lenguaje de programación que nos brinde las herramientas para evitarlo, como lo hacen Java y todos los lenguajes remotamente similares (hay una pequeña excepción a esta regla al romper bucles anidados).

En Java, hay varias formas de controlar el flujo del código:

La declaración if

La instrucción if es probablemente la forma más común de control de flujo, independientemente del idioma. Es muy simple e intuitivo:

1
2
3
4
if(true) {
    //execute this code block if the argument/expression is true
    //some more code
}

Dado que en muchos casos, solo se necesita ejecutar una sola línea, puede omitir el uso de corchetes y un bloque de código y simplemente sangrar la siguiente línea, aunque esto solo funciona para una sola línea:

1
2
3
4
if(true) 
    System.out.println("Inside the if block");
    System.out.println("I have nothing to do with the if block!");
System.out.println("Neither do I!");

Por lo general, no ingresamos valores booleanos como en estos ejemplos, sino que usamos una expresión:

1
2
3
4
if(username != null)
    System.out.println(username);
if(argument >= 10) 
    System.out.println("The input is higher or equal than 10");

Si la expresión es falsa, el código perteneciente a la declaración si simplemente se omite:

1
2
3
if(1 > 5)
    System.out.println("Hello");
System.out.println(" World!");

Y la salida es:

1
 World!

La declaración if-else

Rara vez deseamos simplemente saltar un fragmento de código si la expresión se evalúa como falsa. Por lo general, queremos hacer algo otro en ese caso:

1
2
3
4
5
6
if(expression) {    
    //code that executes only if the expression is true
}
else {// optional
    //code that executes only if the expression is false
}

Por supuesto, puede usar la declaración else junto con la declaración abreviada if:

1
2
3
4
if(expression) 
    //code that executes only if the expression is true
else
    //code that executes only if the expression is false    

Sin embargo, esto no es recomendable si no está tratando con declaraciones simples, especialmente con ifs anidados, ya que es difícil averiguar "a qué if pertenece un else en particular". El uso de corchetes eliminará la ambigüedad del problema si encuentra que este enfoque es ilegible.

La instrucción else es opcional, por lo que no hay necesidad de escribir un bloque else {} vacío si no queremos que suceda nada si la expresión es falsa.

La sentencia else está intrínsecamente ligada a la sentencia if y no puede existir sin ella. Debe aparecer justo después de la instrucción if; de lo contrario, aparecerá un error del compilador "else without if".

En la mayoría de los casos, queremos comparar algo por igualdad, ya sea que una variable tenga el mismo valor que otra o si es más pequeña o más grande que otra:

1
2
3
4
5
6
String s = "smol";

if (s.length() > 8)
    System.out.println("s has too many characters!");
else 
    System.out.println("Ok, so basically, s is very " + s);

El operador > aquí tiene el significado habitual "mayor que", y Java admite el grupo habitual de operadores relacionales. Estos incluyen <, >, <=, =>, == verificaciones de igualdad y != verificaciones de desigualdad.

Nota: Asegúrese de usar == en declaraciones if en lugar de =, o puede asignar un valor en lugar de compararlo.

1
2
3
4
5
2 < 5   //true
2 < 2   //false
2 <= 2  //true
2 == 3  //false
2 != 3  //true

Nota: La mayoría de las veces, no comparamos variables String usando == sino con el método .equals(). == comprueba la igualdad de referencia de objetos. Para los tipos primitivos (int, char, etc.) es lo mismo que comprobar si tienen el mismo valor, pero con cadenas normalmente no lo es.

1
2
if(string1.equals(string2))
    //code to be executed if the strings are equal by value

Declaraciones anidadas if

Podemos tener más de una instrucción if conectada, ya sea anidando (colocando una declaración if dentro de otra) o agregando un else if al final de nuestro anterior if:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
int ourNumber = 10;

if(ourNumber > 8){ 
    if(ourNumber % 2 == 0){
       System.out.println("The number is larger than 8 and even");
    }
}
else if (ourNumber == 1) {
    System.out.println("1 is less than 8, so the previous if block isn't executed");
}
else {
    System.out.println("ourNumber is less than 8 and different than 1");
}

Los bloques else siempre "pertenecen" al if del mismo nivel, por lo que el else if (nuestroNúmero == 1) en nuestro código pertenece al if(nuestroNúmero > 8) y no al anidado if que comprueba si el número es par.

Puedes tener tantos bloques else if como quieras, pero solo un bloque else, que viene en último lugar. Cada bloque if, else if y else que se evalúe como true se ejecutará:

Múltiples expresiones en una sola instrucción if

Otra cosa muy útil es la capacidad de verificar múltiples condiciones en un solo si:

1
2
3
4
5
int ourNumber = 10;

if(ourNumber > 5 && (ourNumber % 2 == 0)){
    System.out.println("The number is larger than 8 and even");
}

El operador && es uno de los operadores lógicos que admite Java. boolExpr se usa como abreviatura de expresión booleana. Recordatorio: una expresión booleana es una expresión que se puede evaluar como verdadera o falsa, es decir, también puede ser una expresión que contiene un operador lógico, como podemos ver aquí:

  • !boolExpr - ! es negación, evalúa una expresión verdadera como falsa y viceversa.
  • boolExpr1 & boolExpr2: el operador Y se evalúa como verdadero si ambas expresiones son verdaderas.
  • boolExpr1 | boolExpr2: el operador OR se evalúa como verdadero si al menos una de las expresiones es verdadero.
  • boolExpr1 && boolExpr2: el operador cortocircuito Y se evalúa como verdadero solo si boolExpr1 y boolExpr2 son verdaderos. Se llama un operador de cortocircuito porque si la primera expresión es falsa, ni siquiera evaluará la segunda expresión ya que la condición básica de que ambas deben ser verdaderas nunca puede ocurrir. Con expresiones simples, esto no afecta el código de manera significativa, pero en el código de producción, ambas expresiones pueden ser operaciones costosas y este enfoque puede optimizar significativamente el código.
  • boolExpr1 || boolExpr2: el operador cortocircuito OR se evalúa como verdadero si al menos uno de boolExpr1 y boolExpr2 es verdadero. Una versión de cortocircuito del operador |.
  • boolExpr1 ^ boolExpr2: el operador XOR se evalúa como verdadero solo si boolExpr1 y boolExpr2 se evalúan de manera diferente, es decir, si solo uno de ellos es verdadero y el otro uno es falso.
1
2
3
4
5
true && false //false
(2 < 5) && (2 != 3) //true
false || true //true
true && ((false || false) ^ true) //true
(true && false) || false // false

Es muy recomendable usar paréntesis siempre que tenga sentido usarlos. El último ejemplo funciona igual sin paréntesis, pero confiar en precedencia del operador es extremadamente arriesgado y conduce a un código ilegible.

Construcciones ternarias {#construcciones ternarias}

El único operador ternario (un operador que toma tres operandos) en Java es el operador ?:. Funciona como una sentencia if-else muy compacta.

1
2
3
4
5
6
7
int max = 0;
if (a > b)
    max = a;
else max = b;

//can be written as
int max = (a > b) ? a : b; 

Así es como se ve generalmente una construcción ternaria:

1
(expression) ? returnValueIfTrue : returnValueIfFalse

Las construcciones ternarias también pueden funcionar sin paréntesis, aunque generalmente es más legible usar paréntesis:

1
int max = a > b ? a : b;

También puede usar construcciones ternarias para modificar variables:

1
2
3
4
System.out.println("10% discount for orders above $50!");
double orderPrice = 55;
double finalPrice = orderPrice > 50 ? orderPrice*09 : orderPrice;
System.out.println("Your final price is $" + finalPrice);

Y la salida es:

1
Your final price is $49.5

Usando la construcción, también podemos llamar a los métodos:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public void someMethod() {
    String userRole = "Admin";
    String result = userRole.equals("Admin") ? greetAdmin() : greetUser();
    System.out.println(result);
}

static String greetAdmin() {
    return "Hello Admin!";
}
static String greetUser() {
    return "Hello User!";
}

Lógicamente, esto resultaría en:

1
Hello Admin!

Construcciones ternarias anidadas

1
2
3
4
5
System.out.println("10% discount for all orders above $50 and additional $5 off if your order exceedes 2 items!");
double orderPrice = 140;
int quantity = 5;
double finalPrice = (orderPrice > 50) ? (quantity > 2) ? (orderPrice*0.9)-5 : orderPrice*0.9 : orderPrice;
System.out.println("Your final price is: $" + finalPrice);

Dado que ambas condiciones son verdaderas, la salida es:

1
2
10% discount for all orders above $50 and additional $5 off if your order exceedes 2 items!
Your final price is: $121.0

Sin embargo, este enfoque es terriblemente ilegible. Si es posible, evite anidar construcciones ternarias, aunque si es necesario, divídalo en bloques más simples. Por ejemplo, este ejemplo se puede hacer un poco más legible:

1
2
3
4
5
6
7
8
System.out.println("10% discount for all orders above $50 and additional $5 off if your order exceedes 2 items!");
double orderPrice = 140;
int quantity = 5;
double finalPrice = (orderPrice > 50) ?
                        (quantity > 2) ?
                                (orderPrice*0.9)-5 : orderPrice*0.9
                    : orderPrice;
System.out.println("Your final price is: $" + finalPrice);

Conclusión

El control de flujo en el código es esencial para absolutamente todas las aplicaciones. Declaraciones como if y if-else son bloques de construcción fundamentales y todo aspirante a desarrollador debe tener el control completo y ser consciente de cómo funcionan. cómo funcionan.

Licensed under CC BY-NC-SA 4.0