Acceso directo al operador “or-assignment” (| =) en Java

Tengo un largo conjunto de comparaciones que hacer en Java, y me gustaría saber si una o más de ellas salen como verdaderas. La secuencia de comparaciones fue larga y difícil de leer, así que la dividí para que fuera legible, y automáticamente utilicé un operador de acceso directo |= lugar de negativeValue = negativeValue || boolean negativeValue = negativeValue || boolean

 boolean negativeValue = false; negativeValue |= (defaultStock < 0); negativeValue |= (defaultWholesale < 0); negativeValue |= (defaultRetail < 0); negativeValue |= (defaultDelivery < 0); 

Espero que negativeValue sea ​​verdadero si alguno de los valores predeterminados de es negativo. Es esto valido? ¿Hará lo que espero? No pude verlo mencionado en el sitio de Sun o stackoverflow, pero Eclipse no parece tener un problema y el código se comstack y ejecuta.


Del mismo modo, si quisiera realizar varias intersecciones lógicas, ¿podría usar &= lugar de && ?

El |= es un operador de asignación compuesto ( JLS 15.26.2 ) para el operador lógico booleano | ( JLS 15.22.2 ); no debe confundirse con el condicional o || ( JLS 15.24 ). También hay &= y ^= correspondientes a la versión de asignación compuesta de la lógica booleana & y ^ respectivamente.

En otras palabras, para boolean b1, b2 , estos dos son equivalentes:

  b1 |= b2; b1 = b1 | b2; 

La diferencia entre los operadores lógicos ( & y | ) en comparación con sus contrapartes condicionales ( && y || ) es que los primeros no “cortocircuito”; este último lo hace. Es decir:

  • & y | siempre evalúa ambos operandos
  • && y || evaluar el operando correcto condicionalmente ; el operando correcto se evalúa solo si su valor podría afectar el resultado de la operación binaria. Eso significa que el operando correcto NO se evalúa cuando:
    • El operando izquierdo de && evalúa como false
      • (porque no importa a qué evalúe el operando correcto, la expresión completa es false )
    • El operando izquierdo de || evalúa a true
      • (porque no importa a qué evalúe el operando correcto, la expresión completa es true )

Volviendo a tu pregunta original, sí, esa construcción es válida, y mientras |= no es exactamente un atajo equivalente para = y || , calcula lo que quieres. Dado que el lado derecho del operador |= en su uso es una operación de comparación entera simple, el hecho de que | el cortocircuito no es insignificante.

Hay casos en que se desea o incluso se requiere un cortocircuito, pero su escenario no es uno de ellos.

Es desafortunado que, a diferencia de otros lenguajes, Java no tenga &&= y ||= . Esto fue discutido en la pregunta ¿Por qué Java no tiene versiones de asignación compuesta de los operadores condicional-y y-condicional-u? (&& =, || =) .

No es un operador de “atajo” (o cortocircuito) en la forma en que || y & son (en el sentido de que no evaluarán el RHS si ya conocen el resultado basado en el LHS) pero harán lo que quieran en términos de trabajo .

Como un ejemplo de la diferencia, este código estará bien si el text es nulo:

 boolean nullOrEmpty = text == null || text.equals("") 

mientras que esto no:

 boolean nullOrEmpty = false; nullOrEmpty |= text == null; nullOrEmpty |= text.equals(""); // Throws exception if text is null 

(Obviamente, podrías hacer "".equals(text) para ese caso en particular; solo estoy tratando de demostrar el principio).

Podrías tener una sola statement. Expresado en varias líneas, se lee casi exactamente como el código de muestra, solo que es menos imperativo:

 boolean negativeValue = defaultStock < 0 | defaultWholesale < 0 | defaultRetail < 0 | defaultDelivery < 0; 

Para expresiones más simples, usando | puede ser más rápido que || porque a pesar de que evita hacer una comparación, significa usar una twig implícitamente y eso puede ser mucho más costoso.

Aunque puede ser excesivo para su problema, la biblioteca de Guava tiene una syntax agradable con Predicate y realiza una evaluación de cortocircuito de y / y Predicate .

Esencialmente, las comparaciones se convierten en objetos, se empaquetan en una colección y luego se repiten. Para o predicados, el primer hit verdadero regresa de la iteración, y viceversa para y.

Si se trata de legibilidad, tengo el concepto de datos de prueba separados de la lógica de prueba. Muestra de código:

 // declare data DataType [] dataToTest = new DataType[] { defaultStock, defaultWholesale, defaultRetail, defaultDelivery } // define logic boolean checkIfAnyNegative(DataType [] data) { boolean negativeValue = false; int i = 0; while (!negativeValue && i < data.length) { negativeValue = data[i++] < 0; } return negativeValue; } 

El código parece más prolijo y autoexplicativo. Incluso puede crear una matriz en la llamada al método, como esta:

 checkIfAnyNegative(new DataType[] { defaultStock, defaultWholesale, defaultRetail, defaultDelivery }); 

Es más legible que 'cadena de comparación', y también tiene la ventaja de rendimiento de cortocircuito (a costa de la asignación de matriz y la llamada a método).

Editar: aún más legibilidad se puede lograr simplemente mediante el uso de parámetros varargs:

La firma del método sería:

 boolean checkIfAnyNegative(DataType ... data) 

Y la llamada podría verse así:

 checkIfAnyNegative( defaultStock, defaultWholesale, defaultRetail, defaultDelivery ); 
 List params = Arrays.asList (defaultStock, defaultWholesale, defaultRetail, defaultDelivery); int minParam = Collections.min (params); negativeValue = minParam < 0; 

|| lógico booleano O
| a nivel de bit OR

| = operador de reasignación de bits O y asignación de bits

La razón por la que | = no cortocircuita es porque hace un O a nivel de bit O no un O lógico. Es decir:


 C | = 2 es lo mismo que C = C |  2

Tutorial para operadores de Java

Es una publicación anterior pero para proporcionar una perspectiva diferente para principiantes, me gustaría dar un ejemplo.

Creo que el caso de uso más común para un operador compuesto similar sería += . Estoy seguro de que todos escribimos algo como esto:

 int a = 10; // a = 10 a += 5; // a = 15 

¿Cuál fue el punto de esto? Fue para evitar escribir la variable dos veces en la misma línea. (¿Me estoy perdiendo algo superior aquí?)

Entonces, la próxima línea hace exactamente lo mismo, evitando escribir la variable b1 dos veces en la misma línea.

 b1 |= b2;