Buscar..


Introducción

Los operadores en el lenguaje de programación Java son símbolos especiales que realizan operaciones específicas en uno, dos o tres operandos y luego devuelven un resultado.

Observaciones

Un operador es un símbolo (o símbolos) que le dice a un programa Java que realice una operación en uno, dos o tres operandos . Un operador y sus operandos forman una expresión (consulte el tema Expresiones). Los operandos de un operador son en sí mismos expresiones.

Este tema describe los 40 o más operadores distintos definidos por Java. El tema de las expresiones separadas explica:

  • cómo los operadores, los operandos y otras cosas se combinan en expresiones,
  • cómo se evalúan las expresiones, y
  • cómo funcionan los tipos de expresión, las conversiones y la evaluación de expresiones.

El operador de concatenación de cuerdas (+)

El símbolo + puede significar tres operadores distintos en Java:

  • Si no hay ningún operando antes del + , entonces es el operador Unario Plus.
  • Si hay dos operandos, y ambos son numéricos. entonces es el operador binario de adición.
  • Si hay dos operandos, y al menos uno de ellos es un String , entonces es el operador binario de concatenación.

En el caso simple, el operador de concatenación une dos cadenas para dar una tercera cadena. Por ejemplo:

String s1 = "a String";
String s2 = "This is " + s1;    // s2 contains "This is a String"

Cuando uno de los dos operandos no es una cadena, se convierte en una String siguiente manera:

  • Un operando cuyo tipo es un tipo primitivo se convierte como si llamando toString() en el valor en caja.

  • Un operando cuyo tipo es un tipo de referencia se convierte llamando al método toString() del operando. Si el operando es null , o si el método toString() devuelve un null , en su lugar se usa el literal de cadena "null" .

Por ejemplo:

int one = 1;
String s3 = "One is "  + one;         // s3 contains "One is 1"
String s4 = null + " is null";        // s4 contains "null is null"
String s5 = "{1} is " + new int[]{1}; // s5 contains something like
                                      // "{} is [I@xxxxxxxx"

La explicación para el ejemplo de s5 es que el método toString() en tipos de matriz se hereda de java.lang.Object , y el comportamiento es producir una cadena que consiste en el nombre del tipo y el código de identidad del objeto.

El operador de concatenación se especifica para crear un nuevo objeto de String , excepto en el caso de que la expresión sea una expresión constante. En el último caso, la expresión se evalúa en el tipo de compilación, y su valor de tiempo de ejecución es equivalente a una cadena literal. Esto significa que no hay una sobrecarga de tiempo de ejecución al dividir un literal de cadena larga como este:

String typing = "The quick brown fox " +
                "jumped over the " +
                "lazy dog";           // constant expression

Optimización y eficiencia.

Como se señaló anteriormente, con la excepción de las expresiones constantes, cada expresión de concatenación de cadena crea un nuevo objeto de String . Considere este código:

public String stars(int count) {
    String res = "";
    for (int i = 0; i < count; i++) {
        res = res + "*";
    }
    return res;
}

En el método anterior, cada iteración del bucle creará una nueva String que es un carácter más largo que la iteración anterior. Cada concatenación copia todos los caracteres en las cadenas de operandos para formar la nueva String . Así, las stars(N) :

  • crea N nuevos objetos String , y tira todos menos el último,
  • copiar N * (N + 1) / 2 caracteres, y
  • generar O(N^2) bytes de basura.

Esto es muy caro para N grande. De hecho, cualquier código que concatene cadenas en un bucle puede tener este problema. Una mejor manera de escribir esto sería como sigue:

public String stars(int count) {
    // Create a string builder with capacity 'count' 
    StringBuilder sb = new StringBuilder(count);
    for (int i = 0; i < count; i++) {
        sb.append("*");
    }
    return sb.toString();
}

Idealmente, debería ajustar la capacidad de la StringBuilder , pero si esto no es práctico, la clase va a crecer de forma automática la matriz respaldo que el constructor utiliza para contener caracteres. (Nota: la implementación expande la matriz de respaldo de manera exponencial. Esta estrategia mantiene esa cantidad de caracteres que se copian en O(N) lugar de O(N^2) .

Algunas personas aplican este patrón a todas las concatenaciones de cuerdas. Sin embargo, esto no es necesario porque JLS permite que un compilador de Java optimice las concatenaciones de cadenas dentro de una sola expresión. Por ejemplo:

String s1 = ...;
String s2 = ...;    
String test = "Hello " + s1 + ". Welcome to " + s2 + "\n";

será típicamente optimizado por el compilador bytecode a algo como esto;

StringBuilder tmp = new StringBuilder();
tmp.append("Hello ")
tmp.append(s1 == null ? "null" + s1);
tmp.append("Welcome to ");
tmp.append(s2 == null ? "null" + s2);
tmp.append("\n");
String test = tmp.toString();

(El compilador JIT puede optimizar eso aún más si puede deducir que s1 o s2 no puede ser null ). Pero tenga en cuenta que esta optimización solo está permitida dentro de una sola expresión.

En resumen, si le preocupa la eficacia de las concatenaciones de cadenas:

  • Optimice a mano si está haciendo concatenación repetida en un bucle (o similar).
  • No optimice manualmente una sola expresión de concatenación.

Los operadores aritméticos (+, -, *, /,%)

El lenguaje Java proporciona 7 operadores que realizan aritmética en valores enteros y de punto flotante.

  • Hay dos operadores +
    • El operador de suma binaria agrega un número a otro. (También hay un operador binario + que realiza la concatenación de cadenas. Esto se describe en un ejemplo separado).
    • El operador Unary Plus no hace nada más que activar la promoción numérica (ver más abajo)
  • Hay dos - operadores:
    • El operador de sustracción binaria resta un número de otro.
    • El operador menos unario es equivalente a restar su operando de cero.
  • El operador de multiplicación binaria (*) multiplica un número por otro.
  • El operador de división binaria (/) divide un número por otro.
  • El operador del resto binario 1 (%) calcula el resto cuando un número se divide por otro.

1. A menudo, esto se conoce incorrectamente como operador de "módulo". "Resto" es el término utilizado por el JLS. "Módulo" y "resto" no son lo mismo.

Operandos y tipos de resultados, y promoción numérica.

Los operadores requieren operandos numéricos y producen resultados numéricos. Los tipos de operandos pueden ser cualquier tipo numérico primitivo (es decir, byte , short , char , int , long , float o double ) o cualquier tipo de contenedor numérico definido en java.lang ; ie ( Byte , Character , Short , Integer , Long , Float o Double .

El tipo de resultado se determina en base a los tipos de operandos u operandos, de la siguiente manera:

  • Si cualquiera de los operandos es double o Double , entonces el tipo de resultado es double .
  • De lo contrario, si alguno de los operandos es float o Float , el tipo de resultado es float .
  • De lo contrario, si alguno de los operandos es long o Long , entonces el tipo de resultado es long .
  • De lo contrario, el tipo de resultado es int . Esto cubre byte , short y char operandos, así como `int.

El tipo de resultado de la operación determina cómo se realiza la operación aritmética y cómo se manejan los operandos

  • Si el tipo de resultado es double , los operandos se promueven a double , y la operación se realiza utilizando aritmética de punto flotante IEE 754 de 64 bits (binario de doble precisión).
  • Si el tipo de resultado es float , los operandos se promueven a float , y la operación se realiza utilizando aritmética de punto flotante IEE 754 de 32 bits (binario de precisión simple).
  • Si el tipo de resultado es long , los operandos se promueven a long , y la operación se realiza utilizando aritmética de enteros binarios de dos bits con signo de 64 bits.
  • Si el tipo de resultado es int , los operandos se promueven a int , y la operación se realiza utilizando aritmética de enteros binarios de dos bits con signo de 32 bits.

La promoción se realiza en dos etapas:

  • Si el tipo de operando es un tipo de envoltura, el valor del operando se desajusta a un valor del tipo primitivo correspondiente.
  • Si es necesario, el tipo primitivo se promueve al tipo requerido:
    • La promoción de enteros a int o long tiene pérdidas.
    • La promoción de float al double tiene pérdidas.
    • La promoción de un número entero a un valor de punto flotante puede llevar a la pérdida de precisión. La conversión se realiza utilizando la semántica "redondeo a más cercano" IEE 768.

El significado de división

El operador / divide el operando izquierdo n (el dividendo ) y el operando derecho d (el divisor ) y produce el resultado q (el cociente ).

La división entera de Java se redondea hacia cero. La Sección 15.17.2 de JLS especifica el comportamiento de la división entera de Java de la siguiente manera:

El cociente producido para los operandos n y d es un valor entero q cuya magnitud es lo más grande posible al tiempo que satisface |d ⋅ q| ≤ |n| . Además, q es positivo cuando |n| ≥ |d| n y d tienen el mismo signo, pero q es negativo cuando |n| ≥ |d| n y d tienen signos opuestos.

Hay un par de casos especiales:

  • Si la n es MIN_VALUE y el divisor es -1, entonces se produce un desbordamiento de enteros y el resultado es MIN_VALUE . No se lanza ninguna excepción en este caso.
  • Si d es 0, entonces se lanza `ArithmeticException.

Java división de punto flotante tiene más casos de borde a considerar. Sin embargo, la idea básica es que el resultado q es el valor más cercano a la satisfacción de d . q = n .

La división de punto flotante nunca dará lugar a una excepción. En cambio, las operaciones que se dividen por cero dan como resultado valores de INF y NaN; vea abajo.

El significado del resto

A diferencia de C y C ++, el operador de resto en Java funciona con operaciones de punto flotante y enteros.

Para casos de enteros, el resultado de a % b se define como el número r tal que (a / b) * b + r es igual a a , donde / , * y + son los operadores enteros de Java apropiados. Esto se aplica en todos los casos, excepto cuando b es cero. En ese caso, el resto da como resultado una ArithmeticException .

De la definición anterior se desprende que a % b puede ser negativo solo si a es negativo, y solo positivo si a es positivo. Además, la magnitud de a % b es siempre menor que la magnitud de b .

La operación de resto de punto flotante es una generalización del caso entero. El resultado de a % b es el resto r se define por la relación matemática r = a - (b ⋅ q) donde:

  • q es un número entero,
  • es negativo solo si a / b es negativo y positivo solo si a / b es positivo, y
  • su magnitud es tan grande como sea posible sin exceder la magnitud del verdadero cociente matemático de a y b .

El resto de punto flotante puede producir valores de INF y NaN en casos de borde, como cuando b es cero; vea abajo. No lanzará una excepción.

Nota IMPORTANTE:

El resultado de una operación de resto de punto flotante calculada por % no es la misma que la producida por la operación de resto definida por IEEE 754. El resto de IEEE 754 se puede calcular utilizando el método de biblioteca Math.IEEEremainder .

Desbordamiento de enteros

Los valores enteros de Java de 32 y 64 bits están firmados y utilizan una representación binaria de dos complementos. Por ejemplo, el rango de números representables como (32 bit) int -2 31 a +2 31 - 1.

Cuando sumas, restas o múltiples enteros de dos bits N (N == 32 o 64), el resultado de la operación puede ser demasiado grande para representarlo como un entero de N bits. En este caso, la operación conduce a un desbordamiento de enteros , y el resultado se puede calcular de la siguiente manera:

  • La operación matemática se realiza para dar una representación intermedia de complemento de dos de todo el número. Esta representación será mayor que N bits.
  • Los 32 o 64 bits inferiores de la representación intermedia se utilizan como resultado.

Cabe señalar que el desbordamiento de enteros no da lugar a excepciones en ningún caso.

Valores de punto flotante INF y NAN

Java utiliza representaciones de punto flotante IEE 754 para float y double . Estas representaciones tienen algunos valores especiales para representar valores que están fuera del dominio de los números reales:

  • Los valores "infinitos" o INF denotan números que son demasiado grandes. El valor +INF denota números que son demasiado grandes y positivos. El valor -INF denota números que son demasiado grandes y negativos.
  • El "indefinido" / "no un número" o NaN denota valores resultantes de operaciones sin sentido.

Los valores INF son producidos por operaciones flotantes que causan desbordamiento, o por división por cero.

Los valores de NaN se producen dividiendo cero por cero, o calculando cero resto cero.

Sorprendentemente, es posible realizar aritmética utilizando operandos INF y NaN sin desencadenar excepciones. Por ejemplo:

  • Sumando + INF y un valor finito da + INF.
  • Sumando + INF y + INF da + INF.
  • Añadiendo + INF y -INF da NaN.
  • La división por INF da +0.0 o -0.0.
  • Todas las operaciones con uno o más operandos de NaN dan NaN.

Para obtener más detalles, consulte las subsecciones relevantes de JLS 15 . Tenga en cuenta que esto es en gran parte "académico". Para cálculos típicos, un INF o NaN significa que algo ha salido mal; por ejemplo, tiene datos de entrada incompletos o incorrectos, o el cálculo se ha programado incorrectamente.

Los operadores de igualdad (==,! =)

Los operadores == y != Son operadores binarios que se evalúan como true o false dependiendo de si los operandos son iguales. El operador == da true si los operandos son iguales y false contrario. El operador != Da false si los operandos son iguales y true contrario.

Estos operadores pueden usarse operandos con tipos primitivos y de referencia, pero el comportamiento es significativamente diferente. Según el JLS, en realidad hay tres conjuntos distintos de estos operadores:

  • Los operadores booleanos == y != .
  • Los operadores numéricos == y != .
  • Los operadores Reference == y != .

Sin embargo, en todos los casos, el tipo de resultado de los operadores == y != Es boolean .

Los operadores numéricos == y !=

Cuando uno (o ambos) de los operandos de un operador == o != Es un tipo numérico primitivo ( byte , short , char , int, long , float o double ), el operador es una comparación numérica. El segundo operando debe ser un tipo numérico primitivo o un tipo numérico en caja.

El comportamiento de otros operadores numéricos es el siguiente:

  1. Si uno de los operandos es un tipo de caja, es sin caja.
  2. Si cualquiera de los operandos ahora un byte , short o char , se promueve a un int .
  3. Si los tipos de los operandos no son los mismos, entonces el operando con el tipo "más pequeño" se promueve al tipo "más grande".
  4. La comparación se realiza de la siguiente manera:
    • Si los operandos promovidos son int o long , los valores se prueban para ver si son idénticos.
    • Si los operandos promovidos son float o double entonces:
      • las dos versiones de cero ( +0.0 y -0.0 ) se tratan como iguales
      • un valor NaN se trata como no igual a nada, y
      • otros valores son iguales si sus representaciones IEEE 754 son idénticas.

Nota: debe tener cuidado al usar == y != Para comparar valores de punto flotante.

Los operadores booleanos == y !=

Si ambos operandos son boolean , o uno es boolean y el otro es Boolean , estos operadores son los operadores booleano == y != . El comportamiento es el siguiente:

  1. Si uno de los operandos es un Boolean , es unboxed.
  2. Los operandos sin caja se prueban y el resultado booleano se calcula de acuerdo con la siguiente tabla de verdad
UNA segundo A == B A! = B
falso falso cierto falso
falso cierto falso cierto
cierto falso falso cierto
cierto cierto cierto falso

Hay dos "trampas" que hacen que sea aconsejable usar == y != moderación con los valores de verdad:

Los operadores Reference == y !=

Si ambos operandos son referencias a objetos, los operadores == y != Comprueban si los dos operandos se refieren al mismo objeto . Esto a menudo no es lo que quieres. Para probar si dos objetos son iguales por valor , se debe usar el método .equals() su lugar.

String s1 = "We are equal";
String s2 = new String("We are equal");

s1.equals(s2); // true

// WARNING - don't use == or != with String values
s1 == s2;      // false

Advertencia: el uso de == y != Para comparar valores de String es incorrecto en la mayoría de los casos; vea http://www.riptutorial.com/java/example/16290/pitfall--using----to-compare-strings . Un problema similar se aplica a los tipos de envoltorios primitivos; vea http://www.riptutorial.com/java/example/8996/pitfall--using----to-compare-primitive-wrappers-objects-such-as-integer .

Acerca de los casos de borde de NaN

JLS 15.21.1 establece lo siguiente:

Si cualquiera de los operandos es NaN , entonces el resultado de == es false pero el resultado de != Es true . De hecho, la prueba x != x es true si y solo si el valor de x es NaN .

Este comportamiento es (para la mayoría de los programadores) inesperado. Si prueba si un valor de NaN es igual a sí mismo, la respuesta es "¡No, no lo es!". En otras palabras, == no es reflexivo para los valores de NaN .

Sin embargo, esto no es una "rareza" de Java, este comportamiento se especifica en los estándares de punto flotante IEEE 754 y encontrará que está implementado por la mayoría de los lenguajes de programación modernos. (Para obtener más información, consulte http://stackoverflow.com/a/1573715/139985 ... ¡note que esto está escrito por alguien que estaba "en la sala cuando se tomaron las decisiones"!)

Los operadores de incremento / decremento (++ / -)

Las variables pueden incrementarse o disminuirse en 1 usando los operadores ++ y -- , respectivamente.

Cuando los operadores ++ y -- siguen las variables, se denominan post-incremento y post-decremento respectivamente.

int a = 10;
a++; // a now equals 11
a--; // a now equals 10 again

Cuando los operadores ++ y -- preceden a las variables, las operaciones se llaman pre-incremento y pre-decremento respectivamente.

int x = 10;
--x; // x now equals 9
++x; // x now equals 10

Si el operador precede a la variable, el valor de la expresión es el valor de la variable después de ser incrementado o disminuido. Si el operador sigue la variable, el valor de la expresión es el valor de la variable antes de ser incrementada o disminuida.

int x=10;

System.out.println("x=" + x + " x=" + x++ + " x=" + x); // outputs x=10 x=10 x=11
System.out.println("x=" + x + " x=" + ++x + " x=" + x); // outputs x=11 x=12 x=12
System.out.println("x=" + x + " x=" + x-- + " x=" + x); // outputs x=12 x=12 x=11
System.out.println("x=" + x + " x=" + --x + " x=" + x); // outputs x=11 x=10 x=10

Tenga cuidado de no sobrescribir los incrementos o decrementos posteriores. Esto sucede si utiliza un operador de post-in / decremento al final de una expresión que se reasigna a la variable in / decremented. La in / decremento no tendrá efecto. Aunque la variable en el lado izquierdo se incrementa correctamente, su valor se sobrescribirá inmediatamente con el resultado evaluado previamente en el lado derecho de la expresión:

int x = 0; 
x = x++ + 1 + x++;      // x = 0 + 1 + 1 
                        // do not do this - the last increment has no effect (bug!) 
System.out.println(x);  // prints 2 (not 3!) 

Correcto:

int x = 0;
x = x++ + 1 + x;        // evaluates to x = 0 + 1 + 1
x++;                    // adds 1
System.out.println(x);  // prints 3 

El Operador Condicional (? :)

Sintaxis

{condición para evaluar} ? {instrucción-ejecutada-en-verdadero} : {declaración-ejecutada-en-falso}

Como se muestra en la sintaxis, el Operador condicional (también conocido como Operador Ternario 1 ) usa el ? (signo de interrogación) y : (dos puntos) caracteres para habilitar una expresión condicional de dos resultados posibles. Se puede usar para reemplazar bloques if-else largos para devolver uno de los dos valores según la condición.

result = testCondition ? value1 : value2

Es equivalente a

if (testCondition) { 
    result = value1; 
} else { 
    result = value2; 
}

Se puede leer como "Si testCondition es verdadero, establezca el resultado en value1; de lo contrario, establezca el resultado en valor2 ”.

Por ejemplo:

// get absolute value using conditional operator 
a = -10;
int absValue = a < 0 ? -a : a;
System.out.println("abs = " + absValue); // prints "abs = 10"

Es equivalente a

// get absolute value using if/else loop
a = -10;
int absValue;
if (a < 0) {
    absValue = -a;
} else {
    absValue = a;
}
System.out.println("abs = " + absValue); // prints "abs = 10"

Uso común

Puede usar el operador condicional para asignaciones condicionales (como la comprobación de nulos).

String x = y != null ? y.toString() : ""; //where y is an object

Este ejemplo es equivalente a:

String x = "";

if (y != null) {
    x = y.toString();
}

Dado que el Operador Condicional tiene la segunda prioridad más baja, por encima de los Operadores de Asignación , rara vez es necesario usar paréntesis alrededor de la condición , pero se requiere paréntesis alrededor de la construcción completa del Operador Condicional cuando se combina con otros operadores:

// no parenthesis needed for expressions in the 3 parts
10 <= a && a < 19 ? b * 5 : b * 7

// parenthesis required
7 * (a > 0 ? 2 : 5)

El anidamiento de operadores condicionales también se puede hacer en la tercera parte, donde funciona más como un encadenamiento o como una instrucción switch.

a ? "a is true" :
b ? "a is false, b is true" :
c ? "a and b are false, c is true" :
    "a, b, and c are false"

//Operator precedence can be illustrated with parenthesis:

a ? x : (b ? y : (c ? z : w))

Nota:

1 - Tanto la especificación del lenguaje Java como el tutorial de Java llaman al operador ( ? : :) El operador condicional . El Tutorial dice que es "también conocido como el Operador Ternario" ya que es (actualmente) el único operador ternario definido por Java. La terminología de "Operador condicional" es consistente con C y C ++ y otros idiomas con un operador equivalente.

Los operadores bitwise y lógicos (~, &, |, ^)

El lenguaje Java proporciona 4 operadores que realizan operaciones en modo bit o lógicas en operandos enteros o booleanos.

  • El operador de complemento ( ~ ) es un operador unario que realiza una inversión lógica o bit a bit de los bits de un operando; ver JLS 15.15.5. .
  • El operador AND ( & ) es un operador binario que realiza un bit y lógico "y" de dos operandos; ver JLS 15.22.2. .
  • El operador OR ( | ) es un operador binario que realiza un bit o lógico "inclusivo o" de dos operandos; ver JLS 15.22.2. .
  • El operador XOR ( ^ ) es un operador binario que realiza una "exclusiva o" bitwise o lógica de dos operandos; ver JLS 15.22.2. .

Las operaciones lógicas realizadas por estos operadores cuando los operandos son booleanos se pueden resumir de la siguiente manera:

UNA segundo ~ A A y B Un | segundo A ^ B
0 0 1 0 0 0
0 1 1 0 1 1
1 0 0 0 1 1
1 1 0 1 1 0

Tenga en cuenta que para los operandos enteros, la tabla anterior describe lo que sucede para los bits individuales. Los operadores realmente operan en todos los 32 o 64 bits del operando u operandos en paralelo.

Tipos de operandos y tipos de resultados.

Las conversiones aritméticas habituales se aplican cuando los operandos son enteros. Casos de uso comunes para los operadores bitwise


El operador ~ se usa para invertir un valor booleano, o cambiar todos los bits en un operando entero.

El operador & se usa para "enmascarar" algunos de los bits en un operando de enteros. Por ejemplo:

int word = 0b00101010;
int mask = 0b00000011;   // Mask for masking out all but the bottom 
                         // two bits of a word
int lowBits = word & mask;            // -> 0b00000010
int highBits = word & ~mask;          // -> 0b00101000

El | operador se utiliza para combinar los valores de verdad de dos operandos. Por ejemplo:

int word2 = 0b01011111; 
// Combine the bottom 2 bits of word1 with the top 30 bits of word2
int combined = (word & mask) | (word2 & ~mask);   // -> 0b01011110

El operador ^ se usa para alternar o "voltear" los bits:

int word3 = 0b00101010;
int word4 = word3 ^ mask;             // -> 0b00101001

Para obtener más ejemplos del uso de los operadores bitwise, vea Manipulación de bits.

La instancia del operador

Este operador verifica si el objeto es de una clase particular / tipo de interfaz. El operador instanceof se escribe como:

( Object reference variable ) instanceof  (class/interface type)

Ejemplo:

public class Test {

   public static void main(String args[]){
      String name = "Buyya";
      // following will return true since name is type of String
      boolean result = name instanceof String;  
      System.out.println( result );
   }
}

Esto produciría el siguiente resultado:

true

Este operador aún devolverá verdadero si el objeto que se compara es la asignación compatible con el tipo de la derecha.

Ejemplo:

class Vehicle {}

public class Car extends Vehicle {
   public static void main(String args[]){
      Vehicle a = new Car();
      boolean result =  a instanceof Car;
      System.out.println( result );
   }
}

Esto produciría el siguiente resultado:

true

Los operadores de asignación (=, + =, - =, * =, / =,% =, << =, >> =, >>> =, & =, | = y ^ =)

El operando de la izquierda para estos operadores debe ser una variable no final o un elemento de una matriz. El operando de la derecha debe ser compatible con la asignación del operando de la izquierda. Esto significa que o los tipos deben ser iguales, o el tipo de operando derecho debe ser convertible al tipo de operandos izquierdo mediante una combinación de boxeo, desempaquetado o ampliación. (Para detalles completos refiérase a JLS 5.2 ).

El significado preciso de los operadores de "operación y asignación" se especifica en JLS 15.26.2 como:

Una expresión de asignación compuesta de la forma E1 op= E2 es equivalente a E1 = (T) ((E1) op (E2)) , donde T es el tipo de E1 , excepto que E1 se evalúa solo una vez.

Tenga en cuenta que hay una conversión de tipos implícita antes de la asignación final.

1. =

El operador de asignación simple: asigna el valor del operando de la derecha al operando de la izquierda.

Ejemplo: c = a + b agregará el valor de a + b al valor de c y lo asignará a c

2. +=

El operador "agregar y asignar": agrega el valor del operando de la mano derecha al valor del operando de la mano izquierda y asigna el resultado al operando de la mano izquierda. Si el operando de la izquierda tiene el tipo String , entonces este es un operador de "concatenar y asignar".

Ejemplo: c += a es aproximadamente lo mismo que c = c + a

3. -=

El operador "restar y asignar": resta el valor del operando derecho del valor del operando de la izquierda y asigna el resultado al operando de la izquierda.

Ejemplo: c -= a es aproximadamente lo mismo que c = c - a

4. *=

El operador "multiplicar y asignar": multiplica el valor del operando de la mano derecha por el valor del operando de la mano izquierda y asigna el resultado al operando de la mano izquierda. .

Ejemplo: c *= a es aproximadamente lo mismo que c = c * a

5. /=

El operador "dividir y asignar": divide el valor del operando de la mano derecha por el valor del operando de la mano izquierda y asigna el resultado al operando de la mano izquierda.

Ejemplo: c /*= a es aproximadamente lo mismo que c = c / a

6. %=

El operador "módulo y asignación": calcula el módulo del valor del operando de la derecha por el valor del operando de la izquierda y asigna el resultado al operando de la izquierda.

Ejemplo: c %*= a es aproximadamente lo mismo que c = c % a

7. <<=

El operador "desplazar a la izquierda y asignar".

Ejemplo: c <<= 2 es aproximadamente lo mismo que c = c << 2

8. >>=

El "operador aritmético de desplazamiento y asignación".

Ejemplo: c >>= 2 es aproximadamente lo mismo que c = c >> 2

9. >>>=

El "operador lógico de desplazamiento y asignación".

Ejemplo: c >>>= 2 es aproximadamente lo mismo que c = c >>> 2

10. &=

El operador "bitwise y y asignar".

Ejemplo: c &= 2 es aproximadamente lo mismo que c = c & 2

11. |=

El operador "bitwise o y asignar".

Ejemplo: c |= 2 es aproximadamente lo mismo que c = c | 2

12. ^=

El operador "bitwise exclusivo o y asignar".

Ejemplo: c ^= 2 es aproximadamente lo mismo que c = c ^ 2

Los operadores condicionales y condicionales u (&& y ||)

Java proporciona un operador condicional y un operador condicional, que toman uno o dos operandos de tipo boolean y producen un resultado boolean . Estos son:

  • && - el operador condicional-AND,

  • || - Los operadores condicionales-OR. La evaluación de <left-expr> && <right-expr> es equivalente al siguiente pseudocódigo:

    {
       boolean L = evaluate(<left-expr>);
       if (L) {
           return evaluate(<right-expr>);
       } else {
           // short-circuit the evaluation of the 2nd operand expression
           return false;
       }
    }
    

La evaluación de <left-expr> || <right-expr> es equivalente al siguiente pseudocódigo:

    {
       boolean L = evaluate(<left-expr>);
       if (!L) {
           return evaluate(<right-expr>);
       } else {
           // short-circuit the evaluation of the 2nd operand expression
           return true;
       }
    }

Como lo ilustra el pseudocódigo anterior, el comportamiento de los operadores de cortocircuitos es equivalente a usar las sentencias if / else .

Ejemplo: usar && como guardia en una expresión

El siguiente ejemplo muestra el patrón de uso más común para el operador && . Compare estas dos versiones de un método para probar si un Integer suministrado es cero.

public boolean isZero(Integer value) {
    return value == 0;
}

public boolean isZero(Integer value) {
    return value != null && value == 0;
}

La primera versión funciona en la mayoría de los casos, pero si el argumento de value es null , se lanzará una NullPointerException .

En la segunda versión hemos añadido una prueba de "guarda". El value != null && value == 0 expresión se evalúa realizando primero el value != null Prueba value != null . Si la prueba null tiene éxito (es decir, se evalúa como true ), se evalúa el value == 0 expresión. Si la prueba null falla, entonces la evaluación del value == 0 se omite (en cortocircuito) y no obtenemos una NullPointerException .

Ejemplo: usar && para evitar un cálculo costoso

El siguiente ejemplo muestra cómo se puede usar && para evitar un cálculo relativamente costoso:

public boolean verify(int value, boolean needPrime) {
    return !needPrime | isPrime(value);
}

public boolean verify(int value, boolean needPrime) {
    return !needPrime || isPrime(value);
}

En la primera versión, ambos operandos de la | siempre se evaluará, por lo que el método (costoso) isPrime se llamará innecesariamente. La segunda versión evita la llamada innecesaria usando || en lugar de | .

Los operadores de turno (<<, >> y >>>)

El lenguaje Java proporciona tres operadores para realizar cambios a nivel de bits en valores enteros de 32 y 64 bits. Todos estos son operadores binarios con el primer operando que es el valor que se va a cambiar, y el segundo operando que dice qué tan lejos desplazarse.

  • El operador de desplazamiento << o a la izquierda desplaza el valor dado por el primer operando a la izquierda por el número de posiciones de bit dado por el segundo operando. Las posiciones vacías en el extremo derecho están llenas de ceros.

  • El operador ">>" o de cambio aritmético desplaza el valor dado por el primer operando hacia la derecha por el número de posiciones de bit dado por el segundo operando. Las posiciones vacías en el extremo izquierdo se llenan copiando el bit más a la izquierda. Este proceso se conoce como extensión de signo .

  • El ">>>" o el operador lógico de desplazamiento a la derecha desplaza el valor dado por el primer operando hacia la derecha por el número de posiciones de bit dado por el segundo operando. Las posiciones vacías en el extremo izquierdo están llenas de ceros.

Notas:

  1. Estos operadores requieren un valor int o long como el primer operando, y producen un valor con el mismo tipo que el primer operando. (Necesitará usar un tipo explícito de conversión al asignar el resultado de un cambio a una variable de byte , short o char ).

  2. Si utiliza un operador de cambio con un primer operando que es un byte , char o short , se promueve a un int y la operación produce un int .)

  3. El segundo operando se reduce en módulo el número de bits de la operación para dar la cantidad del desplazamiento. Para más información sobre el concepto matemático mod , ver ejemplos de módulo .

  4. Los bits que se desvían del extremo izquierdo o derecho por la operación se descartan. (Java no proporciona un operador de "rotación" primitivo).

  5. El operador de cambio aritmético es equivalente dividiendo un número (el complemento de dos) por una potencia de 2.

  6. El operador de desplazamiento a la izquierda es equivalente al multiplicar un número (el complemento de dos) por una potencia de 2.

La siguiente tabla le ayudará a ver los efectos de los tres operadores de turno. (Los números se han expresado en notación binaria para ayudar a la visualización).

Operando1 Operando2 << >> >>>
0b0000000000001011 0 0b0000000000001011 0b0000000000001011 0b0000000000001011
0b0000000000001011 1 0b0000000000010110 0b0000000000000101 0b0000000000000101
0b0000000000001011 2 0b0000000000101100 0b0000000000000010 0b0000000000000010
0b0000000000001011 28 0b1011000000000000 0b0000000000000000 0b0000000000000000
0b0000000000001011 31 0b1000000000000000 0b0000000000000000 0b0000000000000000
0b0000000000001011 32 0b0000000000001011 0b0000000000001011 0b0000000000001011
... ... ... ... ...
0b1000000000001011 0 0b1000000000001011 0b1000000000001011 0b1000000000001011
0b1000000000001011 1 0b0000000000010110 0b1100000000000101 0b0100000000000101
0b1000000000001011 2 0b0000000000101100 0b1110000000000010 0b00100000000000100
0b1000000000001011 31 0b1000000000000000 0b1111111111111111 0b0000000000000001

Hay ejemplos del usuario de los operadores de cambio en la manipulación de bits.

El operador Lambda (->)

Desde Java 8 en adelante, el operador Lambda ( -> ) es el operador utilizado para introducir una expresión Lambda. Hay dos sintaxis comunes, como se ilustra en estos ejemplos:

Java SE 8
  a -> a + 1              // a lambda that adds one to its argument
  a -> { return a + 1; }  // an equivalent lambda using a block.

Una expresión lambda define una función anónima o, más correctamente, una instancia de una clase anónima que implementa una interfaz funcional .

(Este ejemplo se incluye aquí para estar completo. Consulte el tema de Expresiones de Lambda para el tratamiento completo).

Los operadores relacionales (<, <=,>,> =)

Los operadores < , <= , > y >= son operadores binarios para comparar tipos numéricos. El significado de los operadores es como usted esperaría. Por ejemplo, si a y b se declaran como cualquiera de los tipos de byte , short , char , int , long , float , double o los cuadros correspondientes:

- `a < b` tests if the value of `a` is less than the value of `b`. 
- `a <= b` tests if the value of `a` is less than or equal to the value of `b`. 
- `a > b` tests if the value of `a` is greater than the value of `b`. 
- `a >= b` tests if the value of `a` is greater than or equal to the value of `b`. 

El tipo de resultado para estos operadores es boolean en todos los casos.

Los operadores relacionales se pueden utilizar para comparar números con diferentes tipos. Por ejemplo:

int i = 1;
long l = 2;
if (i < l) {
    System.out.println("i is smaller");
}

Los operadores relacionales pueden usarse cuando uno o ambos números son instancias de tipos numéricos en caja. Por ejemplo:

Integer i = 1;   // 1 is autoboxed to an Integer
Integer j = 2;   // 2 is autoboxed to an Integer
if (i < j) {
    System.out.println("i is smaller");
}

El comportamiento preciso se resume de la siguiente manera:

  1. Si uno de los operandos es un tipo de caja, es sin caja.
  2. Si cualquiera de los operandos ahora un byte , short o char , se promueve a un int .
  3. Si los tipos de los operandos no son los mismos, entonces el operando con el tipo "más pequeño" se promueve al tipo "más grande".
  4. La comparación se realiza en los valores resultantes int , long , float o double .

Debe tener cuidado con las comparaciones relacionales que involucran números de punto flotante:

  • Las expresiones que computan números de punto flotante a menudo incurren en errores de redondeo debido al hecho de que las representaciones de punto flotante de la computadora tienen una precisión limitada.
  • Al comparar un tipo de entero y un tipo de punto flotante, la conversión del entero a punto flotante también puede llevar a errores de redondeo.

Finalmente, Java sí admite el uso de operadores relacionales con cualquier tipo distinto a los enumerados anteriormente. Por ejemplo, no puede usar estos operadores para comparar cadenas, matrices de números, etc.



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow