Reputation: 341
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
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
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
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