Estructuras básicas en Java: condición booleana

Estoy preparando varios artículos sobre estructuras básicas en Java, como if/else, (do) while, for y for-each. Sin embargo, antes de empezar quiero aclarar cómo funciona la condición booleana que se evalúa en dichas estructuras. En los próximos artículos te mostraré ejemplos de dichas estructuras y veremos algunas de las trampas que te puedes encontrar en el examen de certificación OCAJ8P, para que vayas sobre aviso y no caigas en ellas.

More...

Estructuras básicas en Java: ¿en qué consisten?

Estructuras básicas en Java: este pavo real con más likes que tú

TRUE: este pajarraco tiene más likes que tú en Instagram

Como ya indica el título de este artículo, las estructuras básicas en Java son aquellos elementos sintácticos sencillos que aparecen continuamente en cualquier programa en Java. Ten muy presente que, aunque son estructuras sencillas, no debes bajar la guardia, ya que, como verás más adelante, existen una serie de casos que te pueden llevar a error. En los siguientes artículos vamos a ver las estructuras que te enumero a continuación:

  • if/else, que te permite bifurcar la ejecución del programa, según el valor de una condición,
  • el operador ternario, que es un if/else resumido, y 
  • los bucles while, do-while, for y for-each

Como todas estas estructuras evalúan una condición booleana, sobre la que basan su comportamiento, vamos a empezar primero por ver en qué consiste esta condición, y qué forma puede tomar.

¿Cómo es la condición que se evalúa?

La condición que se evalúa en estas estructuras básicas en Java puede presentarse de distintas formas, pero su valor ha de ser siempre true (verdadero) o false (falso). A continuación te pongo varios ejemplos de lo que te puedes encontrar: 

  • En primer lugar, puedes encontrarte un valor booleano, ya sea como variable, objeto o directamente: true/false.
  • En segundo lugar, es posible que te encuentres con una comparación entre dos objetos o variables.
  • Por último, puedes encontrarte con una cadena de condiciones.

A continuación vamos a ver con más detenimiento cada uno de estos casos, con ejemplos prácticos. También examinaremos las posibles trampas.

Primer caso: la condición es un valor booleano

Un valor booleano es aquel que solo admite true (verdadero) o false (falso).

En Java, aparte de las variables primitivas, también existen clases envoltorio (wrappers), que vienen a ser objetos que equivalen a esas mismas variables primitivas. Así, la clase envoltorio de una variable boolean es un objeto de tipo Boolean. Para instanciar un objeto de tipo Boolean, puedes asignarle un valor booleano, o utilizar uno de los constructores.

A diferencia de otros lenguajes de programación, en Java no puedes asignar a una variable booleana un número entero (como 0 o 1). En cambio, la clase envoltorio Boolean posee dos constructores, de manera que puedes crear un objeto de tipo Boolean de las dos maneras que siguen:

Te he dicho antes que no se puede asignar un número entero a una variable booleana, y tampoco puedes utilizarlo para instanciar un objeto de tipo Boolean. Si te fijas bien, aquí tampoco lo he hecho: el número está entre comillas, lo que quiere decir que he instanciado el objeto con una String

Cuidado con el constructor new Boolean(String)

Cuando utilices el constructor new Boolean(String), el objeto que instancias tomará el valor true si utilizas la String "true" (en mayúscula o minúscula). Cualquier otra String hará que el objeto tome el valor false.

Por último, ten en cuenta que una asignación toma el valor de la asignación. Es decir, si ya has declarado la variable booleana first, puedes utilizar como condición la asignación first = false. Esta condición tiene el valor false, el mismo que se asigna.

Como conclusión de esta primera parte, la condición que se utiliza en una estructura básica en Java puede ser:

  • Una variable booleana.
  • Un objeto de tipo Boolean.
  • Una llamada a uno de los constructores de la clase Boolean (presta atención al constructor que acepta una String).
  • La asignación de un valor booleano.

Segundo caso: la condición es una comparación entre dos objetos o variables

¿Son estos dos objetos iguales? Pero, ¿qué es la igualdad entre dos objetos?

Debes tener muy claro qué es la igualdad cuando se comparan dos objetos en Java. Sobre todo, cuando comparas dos objetos de tipo String. Como sabes, puedes comparar dos objetos de tipo String utilizando == (o con !=, para indicar que son distintos) o con el método equals(String).

La diferencia es que == te dice si ambos objetos comparados son el mismo. Mejor dicho: te dice si las dos referencias que estás comparando apuntan al mismo objeto. El método equals(String) te dice si ambas String tienen el mismo valor, no si las referencias apuntan al mismo objeto. Por ello, como utilizan criterios distintos para comparar, ambos pueden darte valores distintos, dado el caso:

===
=equals(String)

Ambas referencias apuntan al mismo objeto

true

true

Ambas referencias apuntan a objetos distintos

false

true o false

Si ambas referencias de tipo String apuntan al mismo objeto, al compararlas con == obtendrás true y, por supuesto, obtendrás el mismo resultado al compararlas con equals(String). En cambio, si las referencias apuntan a objetos distintos, al compararlas con == obtendrás false. Sin embargo, dos objetos distintos pueden poseer el mismo valor, así que al compararlos con equals(String) puedes obtener true o false, si los objetos poseen valores distintos.

¿Cómo se instancian los objetos de tipo String?

Como has visto en el ejemplo, se pueden instanciar objetos de tipo String de varias maneras, pero al compararlos resultan ser el mismo objeto. Esto se debe a que los valores asignados a objetos de tipo String se reutilizan. La única manera manera de asignar un valor nuevo a un objeto de tipo String es utilizando el constructor.

Incluso si utilizas un valor que ya existe, si lo asignas utilizando el constructor, ese objeto se considera "nuevo".

El método intern() convierte ese objeto "nuevo" en un objeto reutilizado.

Todos los clases en Java disponen del método equals(), que heredan de la clase Object y que acepta un parámetro del mismo tipo que la clase que hereda el método. Sin embargo, este método equivale a ==. Algunas clases, como String, sobreescriben este método heredado, de manera que para la clase String este método funciona con un criterio diferente.

En el caso de que evalúes cifras, puedes utilizar < (menor que), > (mayor que), <= (menor o igual), >= (mayor o igual) y != (distinto de). Todas estas comparaciones también tienen como resultado true o false.

Tercer caso: la condición es, en realidad, una cadena de condiciones (cuando las estructuras básicas en Java dejan de ser sencillas)

¿Qué pasa si, por ejemplo, quieres que se evalúen varias condiciones? Podría ser que no necesitases que todas esas condiciones fuesen verdaderas; quizá solo la primera, o la segunda. En ese caso, puedes utilizar dos tipos de operadores: los operadores ansiosos & y | o los operadores de cortocircuito && y ||.

  • & y && equivalen a "y".
  • | y || equivalen a "o".

El primer operador se utiliza para indicar que ambas condiciones han de ser verdaderas. El segundo, para indicar que una de las condiciones, como mínimo, ha de ser verdadera.

Imagínate que vas a tomarte un café con operadores ansiosos

Por ejemplo, imagínate que quieres tomarte un café en el bar de al lado. En ese caso, has de evaluar dos condiciones, y ambas han de ser verdaderas:

tengo dinero & tengo tiempo

Pero suponte que te tomas el café, pero a la hora de pagar te das cuenta de que has perdido la cartera. El camarero puede colocarte ante la siguiente tesitura:

friegas tazas sucias | llamo a la policía

En este caso, te deja la elección. Basta con que uno de los dos sea true. No obstante, como está utilizando un operador ansioso, ya está con el teléfono en la mano.

Diferencia entre & / | y && / ||

La diferencia que existe entre los operadores ansiosos (simples) y los de cortocircuito (dobles) es que los operadores ansiosos evalúan siempre todas las condiciones. Por el contrario, los operadores de cortocircuito dejan de evaluar condiciones si pueden deducir el resultado.

Imagínate que vas a tomarte un café con operadores de cortocircuito

Por ejemplo, en el ejemplo anterior evalúas tanto si tienes dinero, como si tienes tiempo. Es un operador ansioso. No obstante, si realizas la evaluación así:

tengo dinero && tengo tiempo

Si no tienes dinero ni te vas a plantear si tienes tiempo o no. Ambas condiciones tienen que ser verdaderas, así que si la primera es falsa, no es necesario evaluar la segunda.

Si el camarero se lo toma de la siguiente manera:

friegas tazas sucias || llamo a la policía

Ni se planteará llamar a la policía, porque ya has saltado sobre las tazas. Una de las condiciones ha de ser verdadera, y ha sido la primera. No es necesario evaluar la segunda.

En tu casa estabas mejor

TRUE: en tu casa estabas mejor

Consecuencias de evaluar (o no) la segunda condición

Como ya te he dicho más arriba, las condiciones pueden ser estructuras complejas, cuyo resultado final sea verdadero o falso. Estas estructuras pueden contener asignaciones u otros operadores que modifiquen el valor asignado a variables ya declaradas. Fíjate en el siguiente ejemplo:

Como ves, la segunda condición se evalúa con los operadores ansiosos (simples), aunque sea innecesario, ya que la primera condición es siempre verdadera.

Ejercicios recomendados

En este primer artículo sobre estructuras básicas en Java, te recomiendo que ejercites sobre todo cómo instanciar objetos de tipo String. ¿Te atreves a intentar adivinar si las siguiente condiciones son verdaderas o falsas? Ejecuta el código e intenta explicar el resultado:

¡Cuéntame en los comentarios si has acertado! 🙂