¿Es una buena práctica usar el operador xor para verificaciones booleanas? [cerrado]

150

Personalmente, me gusta el operador exclusivo o , ^cuando tiene sentido en el contexto de los controles booleanos debido a su concisión. Prefiero escribir

if (boolean1 ^ boolean2)
{
  //do it
}

que

if((boolean1 && !boolean2) || (boolean2 && !boolean1))
{
  //do it
}

pero a menudo recibo miradas confusas de otros desarrolladores de Java experimentados (no solo los novatos), y a veces comenta sobre cómo solo debe usarse para operaciones bit a bit.

Tengo curiosidad sobre las mejores prácticas con respecto al uso del ^operador.

Peter
fuente

Respuestas:

298

Simplemente puede usar !=en su lugar.


fuente
36
"¿Qué tiene de malo! =" bool1 ^ bool2 ^ bool3bool1 != bool2 != bool3
Tiene
44
Me duele el cerebro. Entonces, ¿puede! = Producir resultados incorrectos o no?
vemv
27
@vemv, !=produce resultados correctos para booleans (pero no para Booleans, así que tenga cuidado). Sin embargo, no siempre es bonito, por ejemplo, (some != null) != (other != null)no es muy legible. Debe extraer las partes en booleanos explícitos o extraerlas !=en un método separado.
ivant
23
He aquí por qué: a ^ b=> "aob pero no ambos", a != b=> "a no es igual a b". (Lo que dijo @RobertGrant). La mayoría de los humanos entenderían el primero más fácilmente si supieran qué es xor (lo cual es bastante útil saber si estás en el campo de la informática ...)
Harold R. Eason
2
@ HaroldR.Eason es importante aquí: a != b=> "a no es IDÉNTICO para b"
Mario Reutter
27

Creo que has respondido tu propia pregunta: si obtienes miradas extrañas de la gente, probablemente sea más seguro optar por la opción más explícita.

Si necesita comentarlo, entonces probablemente sea mejor reemplazarlo con la versión más detallada y no hacer que la gente haga la pregunta en primer lugar.

Martín
fuente
66
Puedo afirmar que recibirás miradas extrañas cuando escribas seriamente (boolean1 && !boolean2) || (boolean2 && !boolean1)un código de aplicación de la vida real ...
Holger
17

Me parece que tengo muchas conversaciones similares. Por un lado, tiene un método compacto y eficiente para lograr su objetivo. Por otro lado, tiene algo que el resto de su equipo podría no entender, lo que dificulta su mantenimiento en el futuro.

Mi regla general es preguntar si la técnica utilizada es algo que es razonable esperar que los programadores en general sepan. En este caso, creo que es razonable esperar que los programadores sepan cómo usar operadores booleanos, por lo que usar xor en una declaración if está bien.

Como ejemplo de algo que no estaría bien, tome el truco de usar xor para intercambiar dos variables sin usar una variable temporal. Ese es un truco con el que no esperaría que todos estén familiarizados, por lo que no pasaría la revisión del código.

Dave Tarkowski
fuente
14

Creo que estaría bien si lo comentaras, por ejemplo // ^ == XOR.

Dre
fuente
10

Siempre puedes envolverlo en una función para darle un nombre detallado:

public static boolean XOR(boolean A, boolean B) {
    return A ^ B;
}

Pero, me parece que no sería difícil para cualquiera que no supiera para qué sirve el operador ^, para que Google sea realmente rápido. No será difícil de recordar después de la primera vez. Como solicitó otros usos, es común usar el XOR para el enmascaramiento de bits.

También puede usar XOR para intercambiar los valores en dos variables sin usar una tercera variable temporal .

// Swap the values in A and B
A ^= B;
B ^= A;
A ^= B;

Aquí hay una pregunta de Stackoverflow relacionada con el intercambio de XOR .

Cory Gross
fuente
6

Recientemente utilicé un xor en un proyecto de JavaScript en el trabajo y terminé agregando 7 líneas de comentarios para explicar lo que estaba sucediendo. La justificación para el uso de xor en ese contexto fue que uno de los términos ( term1en el ejemplo de abajo) podría asumir no dos, sino tres valores: undefined, trueo falsemientras que el otro ( term2) podría ser trueo false. Hubiera tenido que agregar una verificación adicional para los undefinedcasos, pero con xor, lo siguiente fue suficiente, ya que xor obliga al primer término a ser evaluado por primera vez como booleano, permitiendo que undefinedse lo trate como false:

if (term1 ^ term2) { ...

Al final, fue un poco exagerado, pero de todos modos quería mantenerlo allí, como una especie de huevo de pascua.

Ates Goral
fuente
En mi humilde opinión, en lugar de depender de la conversión implícita, en una situación que es inusual encontrar, es mejor hacer la conversión explícita . Y en general, "dejar que lo indefinido sea tratado como falso" es una práctica cuestionable en cualquier idioma. No he usado valores de tres estados en Java, pero en C #, un bool? avalor puede probarse explícitamente para el uso verdadero a == true: ¿existe una técnica similar en Java? En C #, dados dos bool?valores, "tratar nulo como falso" conduciría a (a == true) ^ (b == true). Una fórmula equivalente es (a == true) != (b == true). ¿Se puede hacer algo similar en Java?
ToolmakerSteve
5
if((boolean1 && !boolean2) || (boolean2 && !boolean1)) 
{ 
  //do it 
} 

En mi humilde opinión este código podría simplificarse:

if(boolean1 != boolean2) 
{ 
  //do it 
} 
Y--
fuente
5

Con la claridad del código en mente, mi opinión es que usar XOR en comprobaciones booleanas no es un uso típico para el operador XOR bitwise. Según mi experiencia, el XOR bit a bit en Java se usa típicamente para implementar un flag togglecomportamiento de máscara :

flags = flags ^ MASK;

Este artículo de Vipan Singla explica el caso de uso con más detalle.

Si necesita usar XOR bit a bit como en su ejemplo, comente por qué lo usa, ya que es probable que incluso un público alfabetizado bit a bit se detenga para comprender por qué lo está utilizando.

Gunnar Karlsson
fuente
-1

Personalmente prefiero la expresión "boolean1 ^ boolean2" debido a su brevedad.

Si estuviera en su situación (trabajando en equipo), llegaría a un compromiso encapsulando la lógica "boolean1 ^ boolean2" en una función con un nombre descriptivo como "isDifferent (boolean1, boolean2)".

Por ejemplo, en lugar de usar "boolean1 ^ boolean2", llamaría "isDifferent (boolean1, boolean2)" de esta manera:

if (isDifferent(boolean1, boolean2))
{
  //do it
}

Su función "isDifferent (boolean1, boolean2)" se vería así:

private boolean isDifferent(boolean1, boolean2)
{
    return boolean1 ^ boolean2;
}

Por supuesto, esta solución implica el uso de una llamada a una función aparentemente extraña, que en sí misma está sujeta al escrutinio de las Mejores Prácticas, pero evita la expresión detallada (y fea) "(boolean1 &&! Boolean2) || (boolean2 &&! Boolean1) "!

UNO
fuente
-2

Si el patrón de uso lo justifica, ¿por qué no? Si bien su equipo no reconoce al operador de inmediato, con el tiempo podrían hacerlo. Los humanos aprenden nuevas palabras todo el tiempo. ¿Por qué no en programación?

La única precaución que podría decir es que "^" no tiene la semántica de cortocircuito de su segunda verificación booleana. Si realmente necesita la semántica de cortocircuito, también funciona un método de utilidad estático.

public static boolean xor(boolean a, boolean b) {
    return (a && !b) || (b && !a);
}
Alan
fuente
16
No veo ningún cortocircuito posible con xor: debe conocer a y b para evaluar el resultado.
Thelema
77
Además, los argumentos se evaluarían en el momento de la llamada, por lo que no ocurrirá ningún cortocircuito.
erikkallen
3
Además, xor debería ser una sola operación a nivel de máquina.
Ogre Psalm33
Probablemente debería buscar la diferencia entre la evaluación de cortocircuito y la evaluación diferida. La evaluación de curcuit corta es un estilo de código que evita las llamadas que de otro modo darían lugar a errores de tiempo de ejecución, como la división por cero. En C esto puede ser ´if (denominador! = 0 && numerador / denominador) ´, que en sí mismo utiliza una evaluación diferida para evitar la división por cero. Tu respuesta también es puramente especulativa.
Martin
2
Para ser honesto, un programador que escribe una función xor, que hace exactamente lo que hace el operador xor pero de forma indirecta, me plantearía más preguntas (específicamente sobre la competencia) que un programador que acaba de usar ^.
Stijn de Witt
-3

! = está bien para comparar dos variables. Sin embargo, no funciona con múltiples comparaciones.


fuente
-3

Como operador bit a bit, xor es mucho más rápido que cualquier otro medio para reemplazarlo. Entonces, para cálculos críticos y escalables de rendimiento, xor es imprescindible.

Mi opinión personal subjetiva: está absolutamente prohibido, por cualquier motivo, utilizar la igualdad (== o! =) Para los booleanos. Su uso muestra falta de ética y fundamentos básicos de programación. Cualquiera que te dé miradas confusas ^ debería ser enviado de vuelta a los conceptos básicos del álgebra booleana (tuve la tentación de escribir "a los ríos de creencias" aquí :)).

Mella
fuente
1
Excepto que el JIT es extremadamente bueno en optimizaciones (pequeñas) de ojo de cerradura, como reemplazar una expresión booleana con otra.
David Leppik
1
Además, ^ no es principalmente un operador booleano (lógico), es un operador bit a bit. Le dice al lector que disminuya la velocidad, porque es probable que haya errores de señal. Si usa ^ for! =, Se volverá realmente desordenado si alguna vez programa en C. Los operadores de Bitwise son una señal para sus lectores (aquellos que depuran su código, incluido usted) para reducir la velocidad y buscar errores de signos . Y pueden ser complicados. Por ejemplo, ¿sabía que el% de Java no es un módulo verdadero, como en C o Python? Una vez tuve un fragmento de código que funcionaba igual en C, JavaScript y Python, pero no en Java.
David Leppik
66
¿Cómo se votó esto alguna vez? En primer lugar, en Java XOR y! = Se compilan [ stackoverflow.com/a/4175512/202504font>( al mismo código exacto), segundo incluso en las pruebas de ensamblador para igualdad y xor son operaciones simples y simples cada una. ¿Tiene algún número para respaldar su estado de cuenta?
jmiserez
-4
str.contains("!=") ^ str.startsWith("not(")

se ve mejor para mí que

str.contains("!=") != str.startsWith("not(")
Chris Rea
fuente