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ímbolo | Operador | Ejemplo |
---|---|---|
() | Paréntesis | (i + 2) * y |
++, -- | Operadores unarios post | i++, 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 |
<, <=, >, >=, instanceof | Operadores relacionales (menor, menor igual, mayor, mayor igual, instanceof | obj 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 cortocircuito | true || false |
? : | Operadores ternario | i > 5 ? "mayor" : "menor" |
=, +=, -=, *=, /=, %=, &=, ^=, !=, <<=, >>=, >>>= | Operadores de asignación | i += 2; |
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
oString
.
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.
- Si dos operandos tienen diferentes tipos, Java realiza una promoción automática del tipo más pequeño al más grande.
- Si uno de los operandos es un entero y el otro es de punto flotante, Java promueve el entero a punto flotante.
- Los operandos más pequeños que un
int
son promovidos primero aint
antes de ser evaluados en la expresión incluso si ninguno de los dos operandos esint
. Esta regla excluye los operadores unarios. - 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.
p | q | p & q |
---|---|---|
true | true | true |
true | false | false |
false | true | false |
false | false | false |
p | q | p | q |
---|---|---|
true | true | true |
true | false | true |
false | true | true |
false | false | false |
p | q | p ^ q |
---|---|---|
true | true | false |
true | false | true |
false | true | true |
false | false | false |
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)...
Deja un comentario
Lo siento, debes estar conectado para publicar un comentario.