Diferencias en los operadores booleanos: & vs && y | vs ||

Respuestas:

134

Estos son los operadores AND bit a bit y OR bit a bit.

int a = 6; // 110
int b = 4; // 100

// Bitwise AND    

int c = a & b;
//   110
// & 100
// -----
//   100

// Bitwise OR

int d = a | b;
//   110
// | 100
// -----
//   110

System.out.println(c); // 4
System.out.println(d); // 6

Gracias a Carlos por señalar la sección correspondiente en las especificaciones del lenguaje Java ( 15.22.1 , 15.22.2 ) con respecto a los diferentes comportamientos del operador en función de sus entradas.

De hecho, cuando ambas entradas son booleanas, los operadores se consideran Operadores lógicos booleanos y se comportan de manera similar a Condicional-Y (&& ) y Condicional-O ( ||) excepto por el hecho de que no hacen cortocircuito, por lo que mientras lo siguiente es seguro :

if((a != null) && (a.something == 3)){
}

Esto no es:

if((a != null) & (a.something == 3)){
}

"Cortocircuito" significa que el operador no necesariamente examina todas las condiciones. En los ejemplos anteriores, &&examinará la segunda condición solo cuandoa no lo sea null(de lo contrario, la declaración completa devolverá falso, y sería discutible examinar las siguientes condiciones de todos modos), por lo que la declaración de a.somethingno generará una excepción o se considerará "segura . "

El &operador siempre examina cada condición en la cláusula, por lo que en los ejemplos anteriores, a.somethingse puede evaluar cuando ade hecho es un nullvalor, lo que genera una excepción.

Justin Niessner
fuente
1
Quería aclarar ... ¿y devolverá 1 solo si AMBOS son 1? Entonces, ¿101 y 001 serían 001? ¿Correcto?
gideon
@giddy @Jonathon - Actualicé mis valores para mostrar mejor esa situación.
Justin Niessner
incompleto: también son operadores LÓGICOS (para booleanos).
user85421
1
@ Carlos- No. Todavía son operadores bit a bit. Simplemente se comportan igual que los operadores lógicos sin cortocircuito. Hay una diferencia.
Justin Niessner
4
y ¿qué son los operadores lógicos sin cortocircuito? Los operadores & y | (solicitados por OP) son "Operadores de bits enteros" (JLS 15.22.1) y "Operadores lógicos booleanos" (JLS 15.22.2). ¿O la Especificación del lenguaje Java está equivocada al respecto?
user85421
108

Creo que estás hablando del significado lógico de ambos operadores, aquí tienes un resumen de tabla:

boolean a, b;

Operation     Meaning                       Note
---------     -------                       ----
   a && b     logical AND                    short-circuiting
   a || b     logical OR                     short-circuiting
   a &  b     boolean logical AND            not short-circuiting
   a |  b     boolean logical OR             not short-circuiting
   a ^  b     boolean logical exclusive OR
  !a          logical NOT

short-circuiting        (x != 0) && (1/x > 1)   SAFE
not short-circuiting    (x != 0) &  (1/x > 1)   NOT SAFE

La evaluación de cortocircuito , la evaluación mínima o la evaluación de McCarthy (después de John McCarthy) es la semántica de algunos operadores booleanos en algunos lenguajes de programación en los que el segundo argumento se ejecuta o evalúa solo si el primer argumento no es suficiente para determinar el valor del expresión: cuando el primer argumento de la función AND se evalúa como falso, el valor general debe ser falso; y cuando el primer argumento de la función OR se evalúa como verdadero, el valor general debe ser verdadero.

No seguro significa que el operador siempre examina todas las condiciones de la cláusula, por lo que en los ejemplos anteriores, 1 / x puede evaluarse cuando la x es, de hecho, un valor 0, lo que genera una excepción.

Torres
fuente
1
@Torres: amplíe su respuesta explicando "cortocircuito" y "seguro". ¿También es "exclusivo o" y "no lógico" también "no está en cortocircuito"? ¿Y por qué se llama "no lógico" en lugar de "no lógico booleano"? ¿Y por qué el "NO lógico" no está agrupado con el "Y lógico" y el "O lógico"? Buena respuesta pero necesita mejora.
tfmontague
@tfmontague, he explicado lo que significa el cortocircuito (editando esta respuesta) .. Esperando que mi edición sea "revisada por pares".
Taslim Oseni
¿Qué tiene de "inseguro" no hacer cortocircuitos? ¿No debería ser más seguro que usar cortocircuitos? Por cierto: realmente no explicas el término "cortocircuito". significa que en "no cortocircuito" primero se evalúan todas las partes, luego se aplica la operación booleana, mientras que en cortocircuito se detiene la evaluación, cuando la primera expresión satisface la condición, como (a || b) no evalúe b, si a es verdadero y la operación o devolverá verdadero, sin importar lo que sea b.
SCI
26

Sé que hay muchas respuestas aquí, pero todas parecen un poco confusas. Entonces, después de investigar un poco de la guía de estudio del oráculo de Java, se me ocurrieron tres escenarios diferentes de cuándo usar && o &. Los tres escenarios son AND lógico , AND bit a bit y AND booleano .

Y lógico: Y lógico (también conocido como Y condicional) utiliza el operador && . Es el significado de cortocircuito: si el operando izquierdo es falso, entonces el operando derecho no será evaluado.
Ejemplo:

int x = 0;
if (false && (1 == ++x) {
    System.out.println("Inside of if");
}
System.out.println(x); // "0"

En el ejemplo anterior, el valor impreso en la consola de x será 0, porque el primer operando en la instrucción if es falso, por lo que java no tiene necesidad de calcular (1 == ++ x) por lo tanto, x no se calculará.

AND bit a bit: AND bit a bit utiliza el operador & . Se utiliza para realizar una operación bit a bit sobre el valor. Es mucho más fácil ver lo que está sucediendo al observar la operación en números binarios, por ejemplo:

int a = 5;     //                    5 in binary is 0101
int b = 12;    //                   12 in binary is 1100
int c = a & b; // bitwise & preformed on a and b is 0100 which is 4

Como puede ver en el ejemplo, cuando las representaciones binarias de los números 5 y 12 están alineadas, entonces un Y preformado bit a bit solo producirá un número binario donde el mismo dígito en ambos números tiene un 1. Por lo tanto, 0101 y 1100 == 0100. Que en decimal es 5 y 12 == 4.

AND booleano: ahora el operador AND booleano se comporta de manera similar y diferente tanto al AND bit a bit como al AND lógico. Me gusta pensar en ello como una preforma de bit a bit AND entre dos valores booleanos (o bits), por lo tanto, usa & operador . Los valores booleanos también pueden ser el resultado de una expresión lógica.

Devuelve un valor verdadero o falso, muy parecido al Y lógico, pero a diferencia del Y lógico, no está cortocircuitado. La razón es que, para realizar ese AND bit a bit, debe conocer el valor de los operandos izquierdo y derecho. Aquí hay un ex:

int x = 0;
if (false & (1 == ++x) {
    System.out.println("Inside of if");
}
System.out.println(x); //"1"

Ahora, cuando se ejecute la instrucción if, se ejecutará la expresión (1 == ++ x), aunque el operando izquierdo sea falso. Por lo tanto, el valor impreso para x será 1 porque se incrementó.

Esto también se aplica a OR lógico (||), OR bit a bit (|) y OR booleano (|) Espero que esto aclare algo de confusión.

LynchburgExplorer
fuente
to preform that bitwise AND, it must know the value of both left and right operandsEsto no me suena bien. Para realizar una BITWISE ANDno es necesario conocer el operando derecho para poder averiguar el resultado si el operando izquierdo es FALSE. Lo que explicas es correcto, pero el razonamiento que dices no me lo parece, al menos a mí ..
Koray Tugay
7

Los operadores && y || están en cortocircuito, lo que significa que no evaluarán su expresión de la derecha si el valor de la expresión de la izquierda es suficiente para determinar el resultado.

Tassos Bassoukos
fuente
7
-1 por decirle al OP lo que ya sabía y no responder la pregunta que realmente hizo.
Alnitak
5

& y | proporcionan el mismo resultado que && y || operadores. La diferencia es que siempre evalúan ambos lados de la expresión donde as && y || deje de evaluar si la primera condición es suficiente para determinar el resultado.

Brian Scott
fuente
1
Incorrecto .... Porque &&evalúa ambos resultados mientras que ||devuelve solo si la primera condición es verdadera.
Buhake Sindi
1
¿Eh? && solo evalúa el lado derecho de la expresión si el lado izquierdo ya se evalúa como verdadero. De lo contrario, deja de evaluar ya que el primer falso significa implícitamente que el resultado no puede ser verdadero. Ver jguru.com/faq/view.jsp?EID=16530
Brian Scott
1
( 2 & 4 )evalúa a false, mientras que ( 2 && 4 )evalúa a true. ¿Cómo es exactamente el mismo resultado?
Piskvor salió del edificio el
1
@Piskvor - ¡no en Java! 2 & 4da como resultado un número entero, no un booleano (cero en este caso). 2 && 4no compilará, && solo aceptará booleanos. Java no permite mezclar booleanos e ints: cero no es false, falseno es cero ...
user85421
1
@BuhakeSindi Mal. Porque &&solo evalúa el segundo operando si el primer operando es true.
Marqués de Lorne
2

En Java, los operadores únicos &, |, ^,! dependen de los operandos. Si ambos operandos son enteros, se realiza una operación bit a bit. Si ambos son booleanos, se realiza una operación "lógica".

Si ambos operandos no coinciden, se genera un error de tiempo de compilación.

Los operadores dobles &&, || se comportan de manera similar a sus contrapartes individuales, pero ambos operandos deben ser expresiones condicionales, por ejemplo:

if ((a <0) && (b <0)) {...} o de manera similar, if ((a <0) || (b <0)) {...}

fuente: programación java lang 4th ed

Aaron p.
fuente
1

Tal vez sea útil saber que los operadores AND bit a bit y OR bit a bit siempre se evalúan antes que el AND condicional y el OR condicional usados ​​en la misma expresión.

if ( (1>2) && (2>1) | true) // false!
alexmeia
fuente
1
¿Te refieres a la prioridad del operador más que al orden de evaluación? Preferiría no ver la diferencia de prioridad utilizada en el código real. Utilice paréntesis en lugar de operadores bit a bit para este propósito.
John Dvorak
1

&&; || son operadores lógicos .... cortocircuito

&; | son operadores lógicos booleanos .... Sin cortocircuito

Pasando a las diferencias en la ejecución de expresiones. Los operadores bit a bit evalúan ambos lados independientemente del resultado del lado izquierdo. Pero en el caso de evaluar expresiones con operadores lógicos, la evaluación de la expresión de la mano derecha depende de la condición de la mano izquierda.

Por ejemplo:

int i = 25;
int j = 25;
if(i++ < 0 && j++ > 0)
    System.out.println("OK");
System.out.printf("i = %d ; j = %d",i,j);

Esto imprimirá i = 26; j = 25, como la primera condición es falsa, la condición de la mano derecha se omite ya que el resultado es falso de todos modos, independientemente de la condición del lado derecho (cortocircuito)

int i = 25;
int j = 25;
if(i++ < 0 & j++ > 0)
    System.out.println("OK");
System.out.printf("i = %d ; j = %d",i,j);

Pero, esto imprimirá i = 26; j = 26,

Nickhil
fuente
0

Si una expresión que involucra el booleano & se evalúa operador , se evalúan ambos operandos. Luego, el operador & se aplica al operando.

Cuando una expresión que incluye && se evalúa operador , se evalúa el primer operando. Si el primer operando se evalúa como falso, se omite la evaluación del segundo operando.

Si el primer operando devuelve un valor verdadero, se evalúa el segundo operando. Si el segundo operando devuelve un valor verdadero, entonces el operador && se aplica al primer y segundo operandos.

Similar para | y ||.

RishiKesh Pathak
fuente
0

Si bien la diferencia básica es que &se usa principalmente para operaciones bit a bit long, into bytedonde se puede usar para una especie de máscara, los resultados pueden diferir incluso si lo usa en lugar de lógico &&.

La diferencia es más notable en algunos escenarios:

  1. Evaluar algunas de las expresiones lleva mucho tiempo
  2. La evaluación de una de las expresiones se puede hacer solo si la anterior era verdadera
  3. Las expresiones tienen algún efecto secundario (intencionado o no)

El primer punto es bastante sencillo, no causa errores, pero lleva más tiempo. Si tiene varias comprobaciones diferentes en una declaración condicional, coloque las que sean más baratas o con más probabilidades de fallar a la izquierda.

Para el segundo punto, vea este ejemplo:

if ((a != null) & (a.isEmpty()))

Esto falla null, ya que la evaluación de la segunda expresión produce un NullPointerException. Operador lógico&& es perezoso, si el operando izquierdo es falso, el resultado es falso sin importar cuál sea el operando derecho.

Ejemplo para el tercer punto: digamos que tenemos una aplicación que usa DB sin activadores ni cascadas. Antes de eliminar un objeto Edificio, debemos cambiar el edificio de un objeto Departamento a otro. Digamos también que el estado de la operación se devuelve como booleano (verdadero = éxito). Luego:

if (departmentDao.update(department, newBuilding) & buildingDao.remove(building))

Esto evalúa ambas expresiones y, por lo tanto, realiza la eliminación del edificio incluso si la actualización del departamento falló por algún motivo. Con&& , funciona según lo previsto y se detiene después del primer fallo.

En cuanto a a || b, es equivalente a !(!a && !b), se detiene si aes cierto, no se necesita más explicación.

Vlasec
fuente