Este artículo resume los Operadores en Java y su orden de ejecución como referencia básica para cualquier programador dado que la escritura de expresiones matemáticas es usual y es conveniente tener una referencia a la mano.

1. Precedencia de operadores en Java

En todo lenguaje de programación existe una tabla de precedencia de operadores que indica el orden en el cual se evalúan los mismos, el programador de Java de reconocer y aprender a manejar la tabla de forma que pueda leer y escribir expresiones.

Como nota acerca de la mantenibilidad del software, debe tratarse de escribir expresiones no muy complejas o crípticas puesto que las mismas aunque pueden funcionar dificultan el entendimiento.

1.1. Tabla de Precedencia de Operadores

SímboloOperadorEjemplo
()Paréntesis(i + 2) * y
++, --Operadores unarios posti++, i--
++, --Operadores unarios pre++i, --i
+, -, !Operadores unarios (positivo, negativo, negación)-3, !true
*, /, %Operadores binarios (multiplicación, división, módulo)5 % 2
+, -Operadores binarios (suma y resta)6 - 8
<<, >>, >>>Operadores de desplazamiento (a la izquierda, a la derecha con signo, a la derecha sin signo)2 << 1
<, <=, >, >=, instanceofOperadores relacionales (menor, menor igual, mayor, mayor igual, instanceofobj instanceof String
==, !=Operadores de igualdad (igual, diferente)i == 5
&, ^, |Operadores lógicos (y lógico, or exclusivo lógico, o lógico a nivel de bit)true | false
&&, ||Operadores lógicos booleanos (y en cortocircuito, o en cortocircuitotrue || false
? :Operadores ternarioi > 5 ? "mayor" : "menor"
=, +=, -=, *=, /=, %=, &=, ^=, !=, <<=, >>=, >>>=Operadores de asignacióni += 2;
Tabla 1. Precedencia de Operadores

El operador más prioritario es el paréntesis, es decir, es la primera operación que se realiza, de otra parte las asignaciones son la última operación que se realiza.

Observe que las asignaciones son la única operación que se agrupa de derecha a izquierda, el resto de operadores se evalúa de izquierda a derecha.

1.2. Consideraciones de evaluación de operadores

Bien, ahora consideremos algunos puntos interesantes a tener en mente respecto de los operadores y operandos son:

  • Tenga en cuenta los literales en Java siguen reglas, de manera que debe tener presente en aplicar los operadores en valores correctos, por ejemplo la expresión !0 es un error puesto que el número cero en Java no tiene ninguna relación con el valor booleano falso, como ocurre en otros lenguajes de programación.
  • Los operadores de pre-incremento o pre-decremento se ejecutan al final de la expresión sin embargo no siguen el orden de evaluación tradicional.
  • Los operadores de asignación compuestos como *= solo funcionan si la variable del lado izquierdo ha sido inicializada previamente. El compilador automáticamente realiza un casting de las expresiones que tienen usan operadores de asignación compuestos.
  • Los operadores de comparación son usados con literales y variables nativas en cuyo caso aplican los conceptos de promoción de tipos, también se pueden comparar valores booleanos y finalmente se pueden comparar valores null o String.
Calculadora Operadores
Figura 1. Calculadora HP48

Estas reglas son tan importantes que debes tenerlas en cuenta incluso cuando escribes expresiones matemáticas en Excel o en una calculadora.

2. Promoción y casting de tipos

2.1. Promoción de tipos

La promoción de tipos ocurre para los tipos nativos cuando los mismos o sus literales están presentes en expresiones, las siguientes cuatro son las reglas que debe considerar respecto a la promoción de tipos.

  1. Si dos operandos tienen diferentes tipos, Java realiza una promoción automática del tipo más pequeño al más grande.
  2. Si uno de los operandos es un entero y el otro es de punto flotante, Java promueve el entero a punto flotante.
  3. Los operandos más pequeños que un int son promovidos primero a int antes de ser evaluados en la expresión incluso si ninguno de los dos operandos es int. Esta regla excluye los operadores unarios.
  4. Después de las promociones todos los operandos tienen el mismo tipo de dato y a causa de esto el resultado tendrá el mismo tipo de dato que los operandos.

Las valores pueden ser sujetos a conversiones de tipo forzadas, estas conversiones pueden eventualmente conllevar perdida de datos, sin embargo es una forma de decirle al compilador que sabemos que estamos haciendo.

2.2. Casting o conversión de tipos

Los casting se realizan con el uso de paréntesis y entre ellos el tipo de dato al cual se quiere hacer la conversión, en el siguiente ejemplo se muestra un casting de una expresión que de otra manera arrojaría error, note además como se esta aplicando la tercera regla de promoción en este ejemplo.

public static void main(String... args) {
    short a = 3;
    short b = 4;
    short c = (short) (a * b);
}

En las ocasiones en las que existan perdidas de datos puede ser o bien por que se trunca la parte decimal de un número en punto flotante o por que se desborda un número, el desborde es conocido como overflow o underflow y ocurre cuando un valor supera el máximo que puede ser representado por su tipo, por ejemplo los byte pueden almacenar desde -128 hasta 127, si una variable de este tipo se le asigna el número 127 y a continuación se le suma 3, no podrá almacenar el número 130 ya que este último valor no cabe en un byte, en su lugar hay un desbordamiento y el valor resultante de esta operación termina siendo -126.

3. Operadores relacionales, lógicos y en cortocircuito en Java

Las operaciones relacionales permiten comparar cantidades como son: mayor, mayor que, menor, menor que, igual y diferente. Estos operadores funcionan a nivel de tipos nativos por lo cual es importante no utilizarlos por ejemplo para comparar referencias objetuales puesto que la operación si bien puede arrojar resultados correctos puede conllevar a resultados inesperados.

3.1. Operadores lógicos y tablas de verdad

Los operadores lógicos corresponden a las siguientes tablas de verdad .Como punto curioso es conveniente observar que mientras que los operadores aritméticos son cerrados, es decir, considere la suma 3+5 el operador suma (llamado binario porque opera sobre dos argumentos) toma dos números y arroja como respuesta otro número, por ello se llama cerrado, pero una operación como 5<3 si opera sobre números y su resultado es un valor booleano.

Las operaciones relacionales habitualmente se usan en conjunto con operadores lógicos y las diferentes combinaciones de valores y resultados de las operaciones lógicas se muestran a continuación.

pqp & q
truetruetrue
truefalsefalse
falsetruefalse
falsefalsefalse
Tabla 2. Operación Y
pqp | q
truetruetrue
truefalsetrue
falsetruetrue
falsefalsefalse
Tabla 3. Operación O
pqp ^ q
truetruefalse
truefalsetrue
falsetruetrue
falsefalsefalse
Tabla 4. Operación XOR

Un concepto no tan conocido pero importante es la diferencia técnica que existe entre el operadores “&” y “&&” igualmente con la “O” lógica.

Cuando se usan dos operadores seguidos se llama operación en cortocircuito, para el caso de la “&&” se evalúa el primer argumento si el mismo es falso no se evalúa el segundo puesto que la operación ya tendrá como resultado falso, para corrobóralo verifique nuevamente la tabla de verdad del operación &, ahora con la operación O funciona de forma similar excepto que se omite la evaluación del segundo argumento si el primero es verdadero, ahora bien existe la versión sin el cortocircuito porque en ocasiones queremos forzar la ejecución de la evaluación de ambas partes especialmente si estas contienen operadores que modifican los valores de las variables como los de pre-incremento o post-incremento.

3.2. Ejemplos de pre-incremento y post-incremento

Para efectos de comprender mejor los operadores de post-incremento y pre-decremento analice la siguiente sentencia e infiera cual será el resultado de la operación, luego mire el uso de la operación y lógica y su modificación de la variable.

int i = 10;
i = i++ + ++i;
System.out.println(i);
if(5 < 3 && i++ > 5) {}
System.out.println(i);
if(5 < 3 & i++ > 5) {}
System.out.println(i);

Finalmente es conveniente anotar que estas operaciones son muy utilizadas especialmente cuando se hace uso de verificación de null antes de proceder con la verificación de una condición como se muestra en el siguiente ejemplo, el cual evita que se produzca el famoso error NullPointerException puesto que antes de avaluar esa operación se verifica si la referencia es nula.

if(str != null && str.length < 10)...

4. Artículos de Interés