21

Misunderstanding Java operator precedence is a source of frequently asked questions and subtle errors. I was intrigued to learn that even the Java Language Specification says, "It is recommended that code not rely crucially on this specification." JLS §15.7 Preferring clear to clever, are there any useful guidelines in this area?

As noted here, this problem should be studied in the context of Evaluation Order, detailed here. Here are a number of resources on the topic:

Additions or corrections welcome.

5
  • 7
    When in doubt, add more parentheses. Commented Jan 26, 2010 at 17:03
  • 9
    And when there's too many parentheses, refactor. Commented Jan 27, 2010 at 4:36
  • 5
    That JLS quote (in context) encourages decomposition of statements that have multiple side-effects (or side-effects in sub-expressions) to avoid uncertainty about the relative timing of said side-effects in left and right sub-expressions. This cannot be accomplished by adding parentheses. In other words, the JLS advises against relying on Java's Evaluation Order, not against relying on operator precedence. The difference between these is explained below, and here. Commented Dec 5, 2012 at 18:23
  • 3
    ((When)(in)((doubt)(,)(add more)((parentheses)?)) No, thank you. Add the minimal amount, please. Commented May 7, 2014 at 17:12
  • 2
    @KevinPanko: For example. Commented May 7, 2014 at 17:22

6 Answers 6

20

As far as the "Real World" is concerned, it's probably fair to say:

  • enough programmers know that multiplication/division take precedence over addition/subtraction, as is mathematically the convention
  • hardly any programmers can remember any of the other rules of precedence

So, apart from the specific case of */ vs +-, I'd really just use brackets to explicitly define the precedence intended.

Sign up to request clarification or add additional context in comments.

14 Comments

Did you mean brackets or parenthesis'?
The reason programmers hardly can remember is because each language is slightly different.
You can also rely on relational operators (<, <=, ==, >=', >') having precedence over logical operators (&&, ||.)
@Neil - when talking to IT folks, it is best to stick to conventional IT / typographic terminology. '()' are parentheses (or round brackets), '[]' are brackets (or square brackets) and '{}' are braces (or curly brackets).
In the context of operator precedence, "brackets" can really only mean "round brackets".
|
5

Another related source of bugs is how rounding errors accumulate. Not an operator precedence order issue per se, but a source of surprise when you get a different result after rearranging operands in an arithmetically-equivalent way. Here's a sun.com version of David Goldberg's What Every Computer Scientist Should Know About Floating-Point Arithmetic.

Comments

4

The quote (from the Java Language Specification §15.7) should be read in the context of Evaluation Order. As discussed here, that section concerns evaluation order, which is not related to operator precedence (or associativity).

Precedence and associativity influence the structure of the expression tree (i.e. which operators act on which operands), while "evaluation order" merely influences the order in which the expression tree is traversed when the expression is evaluated. Evaluation order (or "traversal order") does not have any effect unless some sub-expressions have side-effects that affect the result (or side-effects) of other sub-expressions.

For example, if x==1 initially, the expression ++x/++x would evaluate as 2/3 (which evaluates to 0) since Java has left-to-right evaluation order. Had evaluation order in Java been right-to-left, x would have been incremented twice before the numerator is evaluated, and the expression would have evaluated as 3/2 (which evaluates to 1). Had evaluation order been undefined, the expression could have evaluated to either of these results.

The quote in question, together with its context, ...

The Java programming language guarantees that the operands of operators appear to be evaluated in a specific evaluation order, namely, from left to right.

It is recommended that code not rely crucially on this specification. Code is usually clearer when each expression contains at most one side effect, as its outermost operation

...discourages the reader from depending on the left-to-rightness of Java's evaluation order (as in the example above). It does not encourage unnecessary parentheses.

Edit: Resource: Java operator precedence table that also serves as an index into sections of the JLS containing the syntactic grammar from which each precedence level is inferred.

5 Comments

Evaluation order refers to the order in which sub expressions are evaluated, for example (a+b)/(c+d). It is guaranteed to be left before right. It doesn't affect how the / operator itself is evaluated in the slightest. Your example about 2/3 as against 3/2 is completely incorrect. It has nothing to do with tree traversal either: it is a property of the generated code, where there is no expression tree at all, just RPN.
@EJP Well RPN is just a way of encoding an expression tree, and processing RPN sequentially amounts to exactly the traversal that I was referring to. As for your assertion that my example is "completely incorrect", are you in fact claiming that ++x/++x would evaluate to the same result under LTR and RTL evaluation order?
Thank you for this helpful colloquy. I intended to focus on how the "language respects the order of evaluation indicated explicitly by parentheses and implicitly by operator precedence," but I see that both (parentheses and precedence) must be taken in the overall context of Evaluation Order. Isak: I see no such claim by EJP. EJP: I inferred that Isak was writing hypothetically.
Well +1 for diplomacy @trashgod. People have different opinions on the answer to your question. I just thought it could be useful to point out that the JLS doesn't offer the opinion you thought it does, in that quote.
@EJP has guided me more than once, so I generally assume ignorance on my part, rather than error on his. I've edited my question to include the link you cited and revised your answer to emphasize the larger context. You might replace your comment on the question with one citing this answer.
2

Also, don't forget the logical && and || are shortcut operators, avoid something like:

sideeffect1() || sideeffect2() 

If sideeffect1() is evaluating to true, sideeffect2() isn't going to be executed. The same goes for && and false. This is not entirely related to precendence, but in these extreme cases the assiociativity can also be an important aspect that normally is really irrelevant (at least as far as i am concerned)

1 Comment

In Java, the & and | operators can be boolean logical (as well as bitwise integer). These are the non-short-circuiting operators. Using || instead of | is an explicit request for conditional operand evaluation, much like ?:.
2

The JLS does not give an explicit operator precedence table; it is implied when the JLS describes various operators. For example, the grammar for ShiftExpression is this:

ShiftExpression: AdditiveExpression ShiftExpression << AdditiveExpression ShiftExpression >> AdditiveExpression ShiftExpression >>> AdditiveExpression 

This means that additive operators (+ and -) have a higher precedence than the left-associative shift operators (<<, >> and >>>).

Comments

1

It seems to me that the truth of this is that 'most programmers' think 'most other programmers' don't know or can't remember operator precedence, so they indulge in what is indulgently called 'defensive programming' by 'inserting the missing parentheses', just to 'clarify' that. Whether remembering this third-grade stuff is a real problem is another question. It just as arguable that all this is a complete waste of time and if anything makes things worse. My own view is that redundant syntax is to be avoided wherever possible, and that computer programmers should know the language they are programming in, and also perhaps raise their expectations of their colleagues.

2 Comments

Sorry, to me this is argumentative. I agree more with the JLS 15.7. Will they ever change the order? Who knows. But I can tell you that I've worked on projects with both C++ and Java code, which have subtle differences in precedence (e.g.: defined vs undefined precedence), and most of our developers would rather be sure of the order of evaluation when they might be coding Java one day and C++ the next.
@OgrePsalm33 (a) Of course it's 'argumentative': if you mean 'debatable', the question invited a debate; (b) JLS 15.7 isn't about operator precedence, it is about evaluation order; (c) no, they will never change the operator precedence; (d) there is no undefined operator precedence in either Java or C++, or any other language I am aware of: it is impossible to construct a parser with an undefined grammar; (e) parentheses do not control evaluation order.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.