Operador de acceso directo "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 cadena de comparaciones era larga y difícil de leer, así que la rompí para facilitar la lectura, y automáticamente fui a usar un operador de acceso directo |= en lugar de negativeValue = negativeValue || boolean.

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

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


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

Author: Raedwald, 2010-03-21

8 answers

El |= es un compuesto operador de asignación (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 "cortocircuitan"; los últimos lo hacen. Es decir:

  • & y | siempre evaluar ambos operandos
  • && and || evaluate the right operand conditionally; the right operand is evaluated only if its value could affect the result of the binary operation. Eso significa que el operando correcto NO se evalúa cuando:
    • El operando izquierdo de && evalúa a false
      • (porque no importa a qué se evalúe el operando correcto, la expresión completa es false)
    • El operando izquierdo de || evalúa a true
      • (porque no importa a qué se evalúe el operando correcto, la expresión completa es true)

Así que 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 simple operación de comparación de enteros, el hecho de que | no tenga cortocircuito es insignificante.

Hay casos, cuando se desea cortocircuitar, o incluso se requiere, pero su escenario no es uno de ellos.

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

 184
Author: polygenelubricants,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:34:08

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

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

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 se podría hacer "".equals(text) para ese caso particular - solo estoy tratando de demostrar el principio.)

 16
Author: Jon Skeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-03-21 09:12:10

Solo podrías tener una declaración. Expresado en múltiples líneas se lee casi exactamente como su código de ejemplo, solo que menos imperativo:

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

Para expresiones más simples, usar | puede ser más rápido que || porque aunque evita hacer una comparación significa usar una rama implícitamente y eso puede ser muchas veces más caro.

 3
Author: Peter Lawrey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-17 18:31:54

Aunque podría ser excesivo para su problema, la biblioteca Guava tiene una sintaxis agradable con Predicates y hace una evaluación de cortocircuito de or/and Predicate s.

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

 1
Author: Carl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-03-22 14:28:50

Si se trata de legibilidad, tengo el concepto de separación de datos probados de la lógica de prueba. Ejemplo 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 se ve más detallado y se explica por sí mismo. 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 'comparison string', y también tiene la ventaja de rendimiento de cortocircuitar (a costa de la asignación de matrices y la llamada a métodos).

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

La firma del método sería:

boolean checkIfAnyNegative(DataType ... data)

Y la llamada podría verse así:

checkIfAnyNegative( defaultStock, defaultWholesale, defaultRetail, defaultDelivery );
 1
Author: Krzysztof Jabłoński,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-26 08:11:53
List<Integer> params = Arrays.asList (defaultStock, defaultWholesale, 
                                       defaultRetail, defaultDelivery);
int minParam = Collections.min (params);
negativeValue = minParam < 0;
 0
Author: Roman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-03-21 09:21:31

/ / booleano lógico O
/ bitwise OR

/ = operador OR y asignación inclusivo a bit

La razón por la que |= no hace shortcircit es porque hace un OR lógico O no. Es decir:


C |= 2 is same as C = C | 2

Tutorial para operadores java

 0
Author: oneklc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-11 19:15:04

Es un post antiguo, pero con el fin de proporcionar una perspectiva diferente para los 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 era el punto de esto? Era para evitar escribir la variable a dos veces en la misma línea. (¿Me estoy perdiendo algo superior aquí?)

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

b1 |= b2;
 0
Author: oxyt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-17 08:53:57