É uma boa prática usar o operador xor para verificações booleanas? [fechadas]


150

Pessoalmente, gosto do operador exclusivo ou , ^quando faz sentido no contexto de verificações booleanas devido à sua concisão. Eu prefiro muito escrever

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

do que

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

mas muitas vezes recebo olhares confusos de outros desenvolvedores Java experientes (não apenas dos novatos) e, às vezes, comenta sobre como ele deve ser usado apenas para operações bit a bit.

Estou curioso sobre as melhores práticas em relação ao uso do ^operador.

Respostas:


298

Você pode simplesmente usar !=.


36
"O que há de errado com! =" bool1 ^ bool2 ^ bool3 Faz mais sentido lógico para mim do quebool1 != bool2 != bool3
BlueRaja - Danny Pflughoeft

4
Meu cérebro dói. Então, pode! = Produzir resultados incorretos ou não?
vemv

27
@vemv, !=produz resultados corretos para booleans (mas não para Booleans, tenha cuidado). Nem sempre é bonito, por exemplo, (some != null) != (other != null)não é muito legível. Você precisa extrair as partes em booleanos explícitos ou extraí-las !=em um método separado.
ivant

23
Aqui está o porquê: a ^ b=> "a ou b, mas não ambos", a != b=> "a não é igual a b". (O que o @RobertGrant disse). A maioria dos humanos entenderia o primeiro mais fácil se eles sabem o xor é (o que é bastante útil para saber se você está no campo da computação ...)
Harold R. Eason

2
@ HaroldR.Eason dicas importantes aqui: a != b=> "a não é IDÊNTICO b"
Mario Reutter

27

Acho que você respondeu sua própria pergunta - se você receber olhares estranhos das pessoas, provavelmente é mais seguro usar a opção mais explícita.

Se você precisar comentar, provavelmente será melhor substituí-lo pela versão mais detalhada e não fazer com que as pessoas façam a pergunta em primeiro lugar.


6
Eu posso afirmar que você, você vai ter olhares estranhos de mim, quando você escreve seriamente (boolean1 && !boolean2) || (boolean2 && !boolean1)em um código de aplicação na vida real ...
Holger

17

Acho que tenho muitas conversas semelhantes. Por um lado, você tem um método compacto e eficiente para atingir seu objetivo. Por outro lado, você tem algo que o resto da sua equipe pode não entender, dificultando a manutenção no futuro.

Minha regra geral é perguntar se a técnica usada é algo que é razoável esperar que os programadores em geral conheçam. Nesse caso, acho razoável esperar que os programadores saibam como usar operadores booleanos, portanto, usar xor em uma instrução if está correto.

Como um exemplo de algo que não seria bom, use o xor para trocar duas variáveis ​​sem usar uma variável temporária. Esse é um truque com o qual eu não esperaria que todos estivessem familiarizados, para que não passasse na revisão de código.


14

Eu acho que tudo bem se você comentar, por exemplo // ^ == XOR.


10

Você sempre pode envolvê-lo em uma função para fornecer um nome detalhado:

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

Mas, parece-me que não seria difícil para quem não sabia o que é o operador ^ para o Google, muito rápido. Não será difícil lembrar depois da primeira vez. Como você solicitou outros usos, é comum usar o XOR para mascarar bits.

Você também pode usar o XOR para trocar os valores em duas variáveis ​​sem usar uma terceira variável temporária .

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

Aqui está uma pergunta sobre o Stackoverflow relacionada à troca de XOR .


6

Recentemente, usei um xor em um projeto JavaScript no trabalho e acabei adicionando 7 linhas de comentários para explicar o que estava acontecendo. A justificação para a utilização de xor nesse contexto que era um dos termos ( term1no exemplo a seguir) pode assumir não dois, mas três valores: undefined, trueou falseenquanto o outro ( term2) pode ser trueou false. Eu teria que adicionar uma verificação adicional para os undefinedcasos, mas com o xor, o seguinte foi suficiente, pois o xor força o primeiro termo a ser avaliado pela primeira vez como um booleano, permitindo que undefinedseja tratado como false:

if (term1 ^ term2) { ...

No final, foi um pouco exagerado, mas eu queria mantê-lo lá de qualquer maneira, como uma espécie de ovo de páscoa.


IMHO, em vez de confiar na conversão implícita, em uma situação incomum, é melhor explicitar a conversão . E, em geral, "deixar o indefinido ser tratado como falso" é uma prática questionável em qualquer idioma. Eu não usei valores de três estados em java, mas em C #, um bool? avalor pode ser explicitamente testado para uso verdadeiro a == true- existe uma técnica semelhante em java? Em C #, dados dois bool?valores, "tratar nulo como falso" levaria a (a == true) ^ (b == true). Uma fórmula equivalente é (a == true) != (b == true). Você pode fazer algo semelhante em java?
Página

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

IMHO este código pode ser simplificado:

if(boolean1 != boolean2) 
{ 
  //do it 
} 

5

Com a clareza do código em mente, minha opinião é que o uso do XOR em verificações booleanas não é um uso típico para o operador bit a bit do XOR. Pela minha experiência, o XOR bit a bit em Java é normalmente usado para implementar um flag togglecomportamento de máscara :

flags = flags ^ MASK;

Este artigo de Vipan Singla explica o caso de uso em mais detalhes.

Se você precisar usar o XOR bit a bit, como no seu exemplo, comente o motivo de usá-lo, pois é provável que exija que mesmo um público alfabetizado bit a bit pare em suas trilhas para entender por que você está usando.


-1

Pessoalmente, prefiro a expressão "boolean1 ^ boolean2" devido à sua sucessão.

Se eu estivesse na sua situação (trabalhando em equipe), obteria um compromisso encapsulando a lógica "boolean1 ^ boolean2" em uma função com um nome descritivo como "isDifferent (boolean1, boolean2)".

Por exemplo, em vez de usar "boolean1 ^ boolean2", você chamaria "isDifferent (boolean1, boolean2)" assim:

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

Sua função "isDifferent (boolean1, boolean2)" seria semelhante a:

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

Obviamente, essa solução implica o uso de uma chamada de função aparentemente ostensiva, que por si só está sujeita ao exame de Melhores Práticas, mas evita a expressão detalhada (e feia) "(boolean1 &&! Boolean2) || (boolean2 &&! Boolean1) "!


-2

Se o padrão de uso justifica, por que não? Embora sua equipe não reconheça o operador imediatamente, com o tempo que eles puderam. Os humanos aprendem novas palavras o tempo todo. Por que não na programação?

O único cuidado que posso afirmar é que "^" não possui a semântica de curto-circuito da sua segunda verificação booleana. Se você realmente precisa da semântica de curto-circuito, um método utilitário estático também funciona.

public static boolean xor(boolean a, boolean b) {
    return (a && !b) || (b && !a);
}

16
Não vejo nenhum curto-circuito possível com xor - você precisa conhecer aeb para avaliar o resultado.
Thelema

7
Além disso, os argumentos seriam avaliados no tempo de chamada, para que nenhum curto-circuito aconteça.
erikkallen

3
Além disso, o xor deve ser uma operação única no nível da máquina.
Ogre Psalm33

Você provavelmente deve procurar a diferença entre avaliação de curto-circuito e avaliação lenta. A avaliação de curto-circuito é um estilo de código que impede chamadas que, de outra forma, resultariam em erros de tempo de execução, como divisão por zero. Em C, isso pode ser 'se (denominador! = 0 && numerador / denominador)', que por si só utiliza avaliação lenta para impedir a divisão por zero. Sua resposta também é puramente especulativa.
19313 Martin

2
Para ser honesto, um programador escrevendo uma função xor, que faz exatamente o que o operador xor faz, mas de maneira indireta, traria mais perguntas em minha mente (especificamente sobre competência) do que um programador que acabou de usar ^.
Stijn de Witt

-3

! = está OK para comparar duas variáveis. Porém, não funciona com múltiplas comparações.


-3

Como operador bit a bit, o xor é muito mais rápido do que qualquer outro meio para substituí-lo. Portanto, para cálculos críticos e escalonáveis ​​de desempenho, xor é imperativo.

Minha opinião pessoal subjetiva: é absolutamente proibido, para qualquer finalidade, usar igualdade (== ou! =) Para booleanos. Usá-lo mostra falta de ética e fundamentos básicos de programação. Qualquer um que lhe dê uma olhada confusa ^ deve ser enviado de volta ao básico da álgebra booleana (fiquei tentado a escrever "nos rios da crença" aqui :)).


1
Exceto que o JIT é extremamente bom em otimizações (pequenas) de fechadura, como substituir uma expressão booleana por outra.
David Leppik

1
Além disso, ^ não é principalmente um operador booleano (lógico), é um operador bit a bit. Diz ao leitor para diminuir a velocidade, porque é provável que haja erros de sinal. Se você usar ^ for! =, Ficará realmente confuso se programar em C. Os operadores bit a bit são um sinal para os seus leitores (aqueles que depuram seu código, incluindo você) para diminuir a velocidade e procurar erros de sinal . E eles podem ser complicados. Por exemplo, você sabia que o módulo% de Java não é verdadeiro, como em C ou Python? Certa vez, tive um trecho de código que era executado em C, JavaScript e Python, mas não em Java.
David Leppik

6
Como isso foi votado? Primeiro, no Java XOR e! = São compilados [ stackoverflow.com/a/4175512/202504,95 ( exatamente no mesmo código), segundo mesmo nos testes de igualdade de montagem e xor são operações simples e únicas cada. Você tem algum número para fazer backup de sua declaração?
jmiserez

-4
str.contains("!=") ^ str.startsWith("not(")

parece melhor para mim do que

str.contains("!=") != str.startsWith("not(")
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.