3

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).

Community
  • 1
  • 1
kszosze
  • 341
  • 4
  • 9
  • The Elvis operator is something different -- the null coalescing operator -- and it doesn't exist in Java. – Patrick Collins Sep 02 '14 at 09:02
  • Yes, for that reason I use -- a.getItem().getOtherItem() != null -- insted -- a.getItem().getOtherItem()? --, I know the elvis operator in java is boolean. But I guess that will affect the operator precedence – kszosze Sep 02 '14 at 09:05
  • `:` is used to make a `if-else` statement, boolean running = value1.equals("run")? true `:` false; – Ker p pag Sep 02 '14 at 09:05
  • 1
    @kszosze I think you're misunderstanding: there is nothing called an Elvis operator in Java, that's not a feature that Java has. – Patrick Collins Sep 02 '14 at 09:06
  • So that `code`if-else`code` has more precedence that && operator? in that case.. why when I encapsulate it between `code`( )`code` works fine. – kszosze Sep 02 '14 at 09:08
  • @PatrickCollins ok I used bad the name. No Elvis operator, then I must say ternary operator – kszosze Sep 02 '14 at 09:10

3 Answers3

6

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.

Holger
  • 285,553
  • 42
  • 434
  • 765
  • The example was only an easy way to express the question. I know I can rewrite with the ternary operator. Just happen that I notices that making some tests looking for an error. The main question is if && has precedence over ?: and && is a short circuit operator why the ternary operator is evaluated if the left branch in the case the left branch is false. – kszosze Sep 02 '14 at 13:39
  • @kszosze: read my first paragraph. You get completely wrong what *precedence* means. It means that `a && b? c: d` is equivalent to `(a && b)? c: d`. And short circuiting means, that the evaluation of `b` can be skipped, nothing else. Your expectation is the opposite, that would be the case if `? :` had a higher precedence. – Holger Sep 02 '14 at 13:50
  • Holger ok, I got it Thanks – kszosze Sep 02 '14 at 13:54
0

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.

Janick Bernet
  • 20,544
  • 2
  • 29
  • 55
  • I know the way I make the example is strange. That line was only an example making some test to catch an error, and see this. As you say `code`&&`code` has precedence over `code`?:`code` and `code`&&`code` is a short circuit evaluated, so I don't understand why I get a NullPointerException if no use curve brackets – kszosze Sep 02 '14 at 13:47
0

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

danizmax
  • 2,446
  • 2
  • 32
  • 41
  • Why the most inner part must be evaluated first if the precedence say the the left branch must be executed first and the `code`&&`code` is a short circuit operator. Don't find any sense. – kszosze Sep 02 '14 at 13:51