kszosze
kszosze

Reputation: 341

Java boolean precedence comparation with ternary operator

I'd found a nice situation that I don't understand at all related to Java boolean operator precedence. I know and verify with the oracle official documentation here that && and || have precedence against ternary operator ? :

Now I have a weird line in my code similar to that

if (a.getItem() != null && a.getItem().getOtherItem() != null?true:a.getItem().getOtherItem().getSomevalue())
{
......
}

What I get, well, a nice java.lang.NullPointerException at a.getItem().getOtherItem() becouse a.getItem() is null. How I can solve it, encapsulate it between parenthesis

if (a.getItem() != null && (a.getItem().getOtherItem() != null?true:a.getItem().getOtherItem().getSomevalue()))
{
......
}

So my question is why I get a NullPointerException if I follow the Oficial Documentation previously linked && has precedence against ?: and && is short circuit evaluated (answered also here in some questions).

Upvotes: 3

Views: 427

Answers (3)

Holger
Holger

Reputation: 298203

It seems you are confused about what “higher precedence” means. Let’s explain with a simple example:

The operator * has higher precedence than the operator '+'. This means that the expression a*b+c is evaluated like (a*b)+c. The same applies to the && operator and the ternary operator:

&& has higher precedence than the operator ? :. This means that the expression a&&b?c:d is evaluated as (a&&b)?c:d.


Hence the operator precedence works as documented in your example. It does exactly what you requested:

if (a.getItem() != null && a.getItem().getOtherItem() != null?
                                       true:a.getItem().getOtherItem().getSomevalue())

If a.getItem() is not null and a.getItem().getOtherItem() is not null evaluate to true, otherwise to a.getItem().getOtherItem().getSomevalue(). So when either of the values is null, the code will attempt to evaluate the third term which will yield to a NullPointerException.

It’s not clear what you actually want to achieve. In your second example you say:

if (a.getItem() != null && (a.getItem().getOtherItem() != null?
                            true: a.getItem().getOtherItem().getSomevalue()))

so you want to interpret the case when a.getItem() is null as false but in the braced term you request to interpret the case when a.getItem().getOtherItem() is not null as true while the case that a.getItem().getOtherItem() is null should cause getSomevalue() to be called on the reference that you just have proven to be null.

What you most likely want to do is to evaluate a.getItem().getOtherItem().getSomevalue() if the all values are not null:

if (a.getItem() != null && a.getItem().getOtherItem() != null?
                                     a.getItem().getOtherItem().getSomevalue(): false)

Note that you can express the same without the ternary operator at all. The equivalent statement would be:

if (a.getItem() != null && a.getItem().getOtherItem() != null
                        && a.getItem().getOtherItem().getSomevalue())

In the case the fall-back value ought to be true like in

if (a.getItem() != null && a.getItem().getOtherItem() != null?
                                     a.getItem().getOtherItem().getSomevalue(): true)

the same can be expressed as

if (a.getItem() == null || a.getItem().getOtherItem() == null
                        || a.getItem().getOtherItem().getSomevalue())

Whenever you see true or false in a compound boolean expression you can be sure that there is something wrong.

Upvotes: 6

danizmax
danizmax

Reputation: 2456

iI'd say that in your if statement

if (a.getItem() != null && a.getItem().getOtherItem() != null?true:a.getItem().getOtherItem().getSomevalue())

the following most inner part must be evaluated first

null?true:a.getItem().getOtherItem().getSomevalue()

so that the following part can be put together

if (a.getItem() != nulla.getItem().getOtherItem() !=<result_from_most_inner_part>)

In any case this if statement is ugly. Make the code rather readable and the compiler will do its part :P

Upvotes: 0

Janick Bernet
Janick Bernet

Reputation: 21194

The general use case for ? is to replace an if in a simple assignment branch, something like:

int a;
if(isOdd(b) || isPrime(b))
{
  a = b;
}
else
{
  a = -b;
}

into simply

int a = isOdd(b) || isPrime(b) ? b : -b;

And for this use case, it makes sense that && and || have precedence over ?.

The confusion arises only if ? returns boolean, the way you use it inside an if, which in my experience is very rare.

Upvotes: 0

Related Questions