Java's logical OR operator does not evaluate right hand side despite that right hand side has a unary operator?

StackOverflow https://stackoverflow.com/questions/18575993

Pergunta

Given that:

Object x = null;

Consider code snippet #1:

if (x == null || !x.equals(new Object()))
    System.out.println("I print!");

Code snippet #1 does not throw a NullPointerException as I first thought it should have. I can provoke the exception with a little bit of help from the | operator. Code snippet #2:

if (x == null | !x.equals(new Object()))
    System.out.println("This will throw a NullPointerException..");

How come then that my first code snippet never evaluated the right expression that has a unary NOT operator in it (the exclamation !)? According to.. well all web sites out there.. the unary NOT operator has higher precedence that that of the logical OR operator (||).

Foi útil?

Solução

the unary NOT operator has higher precedence that that of the logical OR operator (||).

Yes it's true. But the precedence thing will come into effect, if you use NOT on the first expression of logical OR.

Consider the condition:

if (!x.equals(y) || y.equals(z))

In this case, the negation will be applied first on the result of x.equals(y), before the logical OR. So, had the precedence of || been greater than !, then the expression would have been evaluated as:

if (!(x.equals(y) || y.equals(z)))

But it's not. As you know why.

However, if the NOT operator is on the second expression, the precedence is not a point here. The first expression will always be evaluated first before the 2nd expression. And short-circuit behaviour will come into play.

Outras dicas

It is a common misconception that precedence == order of evaluation. This is not always the case. Precedence determines the order the compiler builds the expression and this can lead the code generated to match that order, but in some cases, e.g. post increment and short curcuit operators that this doesn't apply.

All precedence means is to where the implied brackets are e.g.

if (x == null || !x.equals(new Object()))

is the same as

if ((x == null) || (!(x.equals(new Object()))))

This is explained in this Java tutorial. The || and && short circuit execution if the first boolean expression results in true or false, respectively.

The unary ! has higher precedence than the bitwise OR |. See here for precedence rules.

Read up on short-circuit evaluation - in the logical OR statement (||) the second argument is only evaluated if the first is false.

With the second operator (a bitwise inclusive or, |), both arguments are evaluated (it doesn't short-circuit). Therefore, because x is null, the second one will throw a NullPointerException while the first won't.

If Java is anything like C# on this front, logical operators like || and && are evaluated left-to-right. if p == true then p OR q == true, by definition, so evaluating the right-hand of the OR is pointless.

This is stops you having to do things like this (and, of course, is more efficient than evaluating a load of redundant expressions):

if (x != null)
{
    if (x.Property > 0)
    {
        ....
    }
}

I'm not really sure how precedence is relevant here, as the NOT excludes the first expression in the provided conditional, so the value of the right hand has no bearing on the value of the left hand anyway.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top