Pregunta 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 usé automáticamente un operador de acceso directo. |= más bien que negativeValue = negativeValue || boolean.

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

Espero negativeValue para que sea verdadero si alguno de los valores por defecto de <something> 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 compila y ejecuta.


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


75
2018-03-21 09:06


origen


Respuestas:


los |= es un operador de asignación compuesta (JLS 15.26.2) para el operador lógico booleano | (JLS 15.22.2); no confundir con el condicional o || (JLS 15.24) También hay &= y ^= correspondiente 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 evaluar 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 a 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 su pregunta original, sí, esa construcción es válida, y mientras |= no es exactamente un atajo equivalente para = y ||, calcula lo que quieres. Desde el lado derecho de la |= 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 condicional o? (&& =, || =).


183
2018-03-21 09:44



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án lo que usted desee en términos de trabajando.

Como un ejemplo de la diferencia, este código estará bien si 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 puedes hacer "".equals(text) para ese caso particular, solo intento demostrar el principio).


16
2018-03-21 09:12



Podrías tener una sola declaración. 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 mas rapido que || porque a pesar de que evita hacer una comparación, significa usar una rama implícitamente y eso puede ser mucho más costoso.


3
2018-03-21 10:14



Aunque podría ser excesivo para su problema, el Guayaba la biblioteca tiene una buena sintaxis con Predicates y realiza una evaluación de cortocircuito de y / y Predicates.

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.


1
2018-03-22 14:28



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 );

1
2018-04-25 09:38



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

0
2018-03-21 09:15



|| 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


0
2018-01-11 19:15



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 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
2018-04-16 14:13