Operador lógico Java em curto-circuito

100

Qual conjunto está em curto-circuito e o que exatamente significa que a expressão condicional complexa está em curto-circuito?

public static void main(String[] args) {
  int x, y, z;

  x = 10;
  y = 20;
  z = 30;

  // T T
  // T F
  // F T
  // F F

  //SET A
  boolean a = (x < z) && (x == x);
  boolean b = (x < z) && (x == z);
  boolean c = (x == z) && (x < z);
  boolean d = (x == z) && (x > z);
  //SET B    
  boolean aa = (x < z) & (x == x);
  boolean bb = (x < z) & (x == z);
  boolean cc = (x == z) & (x < z);
  boolean dd = (x == z) & (x > z);

}
Aaron
fonte
4
Veja esta pergunta: stackoverflow.com/questions/7101992/…
Eng.Fouad

Respostas:

244

O &&e|| operadores entram em "curto-circuito", ou seja, não avaliam o lado direito se não for necessário.

Os operadores &e |, quando usados ​​como operadores lógicos, sempre avaliam ambos os lados.

Existe apenas um caso de curto-circuito para cada operadora, e eles são:

  • false && ...- não é necessário saber o que é o lado direito porque o resultado só pode ser falseindependente do valor lá
  • true || ...- não é necessário saber o que é o lado direito porque o resultado só pode ser trueindependente do valor lá

Vamos comparar o comportamento em um exemplo simples:

public boolean longerThan(String input, int length) {
    return input != null && input.length() > length;
}

public boolean longerThan(String input, int length) {
    return input != null & input.length() > length;
}

A 2ª versão usa o operador sem curto-circuito &e lançará um NullPointerExceptionif inputis null, mas a 1ª versão retornará falsesem exceção.

Boêmio
fonte
9
Eu só gostaria de estender um pouco esta resposta. O operador & = é uma abreviação para x = x & expression e, portanto, NÃO causa curto-circuito. O mesmo é verdade para o operador | =.
Stormcloud
11
Uma coisa que gostaria de destacar, | e & são operadores binários, enquanto && e || são operadores condicionais (lógicos). | e & trabalham em mais do que apenas booleanos, enquanto && e || funcionam apenas em booleanos.
Um mito
1
Além de não avaliarem a expressão do lado direito, o código não é executado para que haja algo a avaliar. Este é um ponto crítico para entender se um efeito colateral seria produzido.
mckenzm
@mckenzm Qual é a diferença entre avaliado e executado?
Kronen
A execução do @Kronen pode resultar em mais do que a avaliação e produzir um efeito colateral, como uma exceção ou um atraso, não pagarei relevante para este exemplo.
mckenzm
9

SET A usa operadores booleanos de curto-circuito.

O que 'curto-circuito' significa no contexto de operadores booleanos é que para um conjunto de booleanos b1, b2, ..., bn, as versões de curto-circuito cessarão a avaliação assim que o primeiro desses booleanos for verdadeiro (|| ) ou falso (&&).

Por exemplo:

// 2 == 2 will never get evaluated because it is already clear from evaluating
// 1 != 1 that the result will be false.
(1 != 1) && (2 == 2)

// 2 != 2 will never get evaluated because it is already clear from evaluating
// 1 == 1 that the result will be true.
(1 == 1) || (2 != 2)
afrischke
fonte
Especifique que este é o caso de &&, ||funciona de forma diferente e interromperá a avaliação no primeiro operando que retorna verdadeiro;)
fge
1
Na verdade, para ser realmente completa, todos &&, ||, &e |avaliar esquerda para a direita. Para um conjunto de booleanos b1, b2, ..., bn, as versões de curto-circuito cessarão a avaliação quando o primeiro desses booleanos for true ( ||) ou false ( &&). Bah, o princípio está aí;)
fge
@fge: Sim, você está certo, é claro. Sua definição é mais exata que a minha. Eu atualizei minha resposta com a frase em seu comentário. Espero que você não se importe.
afrischke
Não se preocupe, o conhecimento não tem valor se não for compartilhado.
fge
4

Curto-circuito significa que o segundo operador não será verificado se o primeiro operador decidir o resultado final.

Por exemplo, a expressão é: Verdadeira || Falso

No caso de ||, tudo que precisamos é um dos lados para ser Verdadeiro. Portanto, se o lado esquerdo for verdadeiro, não há sentido em verificar o lado direito e, portanto, isso não será verificado de forma alguma.

Da mesma forma, False && True

No caso de &&, precisamos que ambos os lados sejam verdadeiros. Portanto, se o lado esquerdo é False, não há sentido em verificar o lado direito, a resposta tem que ser False. E, portanto, isso não será verificado.

Bhushan
fonte
4
boolean a = (x < z) && (x == x);

Este tipo entrará em curto-circuito, ou seja, se for (x < z)avaliado como falso, o último não aserá avaliado, será falso, caso contrário &&também será avaliado (x == x).

& é um operador bit a bit, mas também um operador booleano AND que não causa curto-circuito.

Você pode testá-los da seguinte maneira (veja quantas vezes o método é chamado em cada caso):

public static boolean getFalse() {
    System.out.println("Method");
    return false;
}

public static void main(String[] args) {
    if(getFalse() && getFalse()) { }        
    System.out.println("=============================");        
    if(getFalse() & getFalse()) { }
}
Bhesh Gurung
fonte
-1 Sua resposta sugere que &é apenas um operador bit a bit, mas isso não é verdade. É também a "ou" operador booleano.
Bohemian
@Bohemian: Obrigado pelo aviso. true & falseavalia como falso. Você pode explicar este "booleano" ou "operador"? Talvez eu não esteja entendendo o que você está tentando dizer.
Bhesh Gurung
Desculpe - eu quis dizer booleano AND, não OR! ou seja, true & falseé uma sintaxe válida. -1 removido :)
Boêmio
4

Em termos simples, curto-circuito significa interromper a avaliação quando você sabe que a resposta não pode mais mudar. Por exemplo, se você está avaliando uma cadeia de ANDs lógicos e descobre um FALSEno meio dessa cadeia, sabe que o resultado será falso, não importa quais são os valores do resto das expressões na cadeia. O mesmo vale para uma cadeia de ORs: depois de descobrir a TRUE, você sabe a resposta imediatamente e, portanto, pode pular a avaliação do restante das expressões.

Você indica ao Java que deseja curto-circuito usando em &&vez de &e em ||vez de |. O primeiro conjunto em sua postagem é o curto-circuito.

Observe que isso é mais do que uma tentativa de salvar alguns ciclos da CPU: em expressões como esta

if (mystring != null && mystring.indexOf('+') > 0) {
    ...
}

curto-circuito significa uma diferença entre a operação correta e uma falha (no caso em que mystring é nula).

dasblinkenlight
fonte
2

Java fornece dois operadores booleanos interessantes não encontrados na maioria das outras linguagens de computador. Essas versões secundárias de AND e OR são conhecidas como operadores lógicos de curto-circuito . Como você pode ver na tabela anterior, o operador OR resulta em verdadeiro quando A é verdadeiro, não importa o que B seja.

Da mesma forma, o operador AND resulta em falso quando A é falso, não importa o que B seja. Se você usar os formulários ||e &&, em vez dos formulários |e &desses operadores, o Java não se preocupará em avaliar apenas o operando direito. Isso é muito útil quando o operando da direita depende do esquerdo ser verdadeiro ou falso para funcionar corretamente.

Por exemplo, o fragmento de código a seguir mostra como você pode aproveitar as vantagens da avaliação lógica de curto-circuito para ter certeza de que uma operação de divisão será válida antes de avaliá-la:

if ( denom != 0 && num / denom >10)

Como a forma de curto-circuito de AND ( &&) é usada, não há risco de causar uma exceção de tempo de execução ao dividir por zero. Se esta linha de código foi escrita usando a única &versão de AND, ambos os lados teriam que ser avaliados, causando uma exceção de tempo de execução quando denomfor zero.

É prática padrão usar as formas de curto-circuito de AND e OR em casos envolvendo lógica booleana, deixando as versões de um caractere exclusivamente para operações bit a bit. No entanto, existem excepções a esta regra. Por exemplo, considere a seguinte declaração:

 if ( c==1 & e++ < 100 ) d = 100;

Aqui, usar um único &garante que a operação de incremento será aplicada ese cfor igual a 1 ou não.

Dileep Kumar
fonte
2

OR lógico: - retorna verdadeiro se pelo menos um dos operandos for avaliado como verdadeiro. Ambos os operandos são avaliados antes de aplicar o operador OR.

Curto-circuito OU: - se o operando do lado esquerdo retornar verdadeiro, ele retornará verdadeiro sem avaliar o operando do lado direito.

Dimansha Malrindu
fonte
2

Existem algumas diferenças entre os operadores &e &&. As mesmas diferenças se aplicam a |e ||. O mais importante a se ter em mente é que &&é um operador lógico que se aplica apenas a operandos booleanos, enquanto &é um operador bit a bit que se aplica a tipos inteiros e também a booleanos.

Com uma operação lógica, você pode fazer um curto-circuito porque em certos casos (como o primeiro operando de &&ser false, ou o primeiro operando de ||ser true), você não precisa avaliar o resto da expressão. Isso é muito útil para fazer coisas como verificar nullantes de acessar um campo ou método e verificar possíveis zeros antes de dividir por eles. Para uma expressão complexa, cada parte da expressão é avaliada recursivamente da mesma maneira. Por exemplo, no seguinte caso:

(7 == 8) || ( (1 == 3) && (4 == 4))

Apenas as partes enfatizadas serão avaliadas. Para calcular o ||, primeiro verifique se 7 == 8é true. Se fosse, o lado direito seria totalmente ignorado. O lado direito apenas verifica se 1 == 3é false. Visto que é, 4 == 4não precisa ser verificado e toda a expressão é avaliada como false. Se o lado esquerdo fosse true, por exemplo, em 7 == 7vez de 7 == 8, todo o lado direito seria ignorado porque a ||expressão inteira seria trueindependente.

Com uma operação bit a bit, você precisa avaliar todos os operandos porque, na verdade, está apenas combinando os bits. Booleanos são efetivamente um inteiro de um bit em Java (independentemente de como os internos funcionam), e é apenas uma coincidência que você possa fazer um curto-circuito para operadores bit a bit nesse caso especial. A razão pela qual você não pode curto-circuitar um número inteiro geral &ou |operação é que alguns bits podem estar ativados e alguns podem estar desativados em qualquer operando. Algo como 1 & 2resulta em zero, mas você não tem como saber disso sem avaliar os dois operandos.

Físico Louco
fonte
1
if(demon!=0&& num/demon>10)

Como a forma de curto-circuito de AND (&&) é usada, não há risco de causar uma exceção de tempo de execução quando o demônio é zero.

Ref. Java 2 Quinta Edição por Herbert Schildt

Nitesh Verma
fonte