Does Java have an operator precedence table? [duplicate] - java

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:
JLS Operators
JLS Precedence
JLS Evaluation Order
What are the rules for evaluation order in Java?
Java Glossary
Princeton
Oracle Tutorial
Conversions and Promotions
Usenet discussion
Additions or corrections welcome.

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.

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.

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.

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)

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

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.

Related

Why operator precedence being ignored here? [duplicate]

I am reading some Java text and got the following code:
int[] a = {4,4};
int b = 1;
a[b] = b = 0;
In the text, the author did not give a clear explanation and the effect of the last line is: a[1] = 0;
I am not so sure that I understand: how did the evaluation happen?
Let me say this very clearly, because people misunderstand this all the time:
Order of evaluation of subexpressions is independent of both associativity and precedence. Associativity and precedence determine in what order the operators are executed but do not determine in what order the subexpressions are evaluated. Your question is about the order in which subexpressions are evaluated.
Consider A() + B() + C() * D(). Multiplication is higher precedence than addition, and addition is left-associative, so this is equivalent to (A() + B()) + (C() * D()) But knowing that only tells you that the first addition will happen before the second addition, and that the multiplication will happen before the second addition. It does not tell you in what order A(), B(), C() and D() will be called! (It also does not tell you whether the multiplication happens before or after the first addition.) It would be perfectly possible to obey the rules of precedence and associativity by compiling this as:
d = D() // these four computations can happen in any order
b = B()
c = C()
a = A()
sum = a + b // these two computations can happen in any order
product = c * d
result = sum + product // this has to happen last
All the rules of precedence and associativity are followed there -- the first addition happens before the second addition, and the multiplication happens before the second addition. Clearly we can do the calls to A(), B(), C() and D() in any order and still obey the rules of precedence and associativity!
We need a rule unrelated to the rules of precedence and associativity to explain the order in which the subexpressions are evaluated. The relevant rule in Java (and C#) is "subexpressions are evaluated left to right". Since A() appears to the left of C(), A() is evaluated first, regardless of the fact that C() is involved in a multiplication and A() is involved only in an addition.
So now you have enough information to answer your question. In a[b] = b = 0 the rules of associativity say that this is a[b] = (b = 0); but that does not mean that the b=0 runs first! The rules of precedence say that indexing is higher precedence than assignment, but that does not mean that the indexer runs before the rightmost assignment.
(UPDATE: An earlier version of this answer had some small and practically unimportant omissions in the section which follows which I have corrected. I've also written a blog article describing why these rules are sensible in Java and C# here: https://ericlippert.com/2019/01/18/indexer-error-cases/)
Precedence and associativity only tell us that the assignment of zero to b must happen before the assignment to a[b], because the assignment of zero computes the value that is assigned in the indexing operation. Precedence and associativity alone say nothing about whether the a[b] is evaluated before or after the b=0.
Again, this is just the same as: A()[B()] = C() -- All we know is that the indexing has to happen before the assignment. We don't know whether A(), B(), or C() runs first based on precedence and associativity. We need another rule to tell us that.
The rule is, again, "when you have a choice about what to do first, always go left to right". However, there is an interesting wrinkle in this specific scenario. Is the side effect of a thrown exception caused by a null collection or out-of-range index considered part of the computation of the left side of the assignment, or part of the computation of the assignment itself? Java chooses the latter. (Of course, this is a distinction that only matters if the code is already wrong, because correct code does not dereference null or pass a bad index in the first place.)
So what happens?
The a[b] is to the left of the b=0, so the a[b] runs first, resulting in a[1]. However, checking the validity of this indexing operation is delayed.
Then the b=0 happens.
Then the verification that a is valid and a[1] is in range happens
The assignment of the value to a[1] happens last.
So, though in this specific case there are some subtleties to consider for those rare error cases that should not be occurring in correct code in the first place, in general you can reason: things to the left happen before things to the right. That's the rule you're looking for. Talk of precedence and associativity is both confusing and irrelevant.
People get this stuff wrong all the time, even people who should know better. I have edited far too many programming books that stated the rules incorrectly, so it is no surprise that lots of people have completely incorrect beliefs about the relationship between precedence/associativity, and evaluation order -- namely, that in reality there is no such relationship; they are independent.
If this topic interests you, see my articles on the subject for further reading:
http://blogs.msdn.com/b/ericlippert/archive/tags/precedence/
They are about C#, but most of this stuff applies equally well to Java.
Eric Lippert's masterful answer is nonetheless not properly helpful because it is talking about a different language. This is Java, where the Java Language Specification is the definitive description of the semantics. In particular, §15.26.1 is relevant because that describes the evaluation order for the = operator (we all know that it is right-associative, yes?). Cutting it down a little to the bits that we care about in this question:
If the left-hand operand expression is an array access expression (§15.13), then many steps are required:
First, the array reference subexpression of the left-hand operand array access expression is evaluated. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason; the index subexpression (of the left-hand operand array access expression) and the right-hand operand are not evaluated and no assignment occurs.
Otherwise, the index subexpression of the left-hand operand array access expression is evaluated. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason and the right-hand operand is not evaluated and no assignment occurs.
Otherwise, the right-hand operand is evaluated. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason and no assignment occurs.
[… it then goes on to describe the actual meaning of the assignment itself, which we can ignore here for brevity …]
In short, Java has a very closely defined evaluation order that is pretty much exactly left-to-right within the arguments to any operator or method call. Array assignments are one of the more complex cases, but even there it's still L2R. (The JLS does recommend that you don't write code that needs these sorts of complex semantic constraints, and so do I: you can get into more than enough trouble with just one assignment per statement!)
C and C++ are definitely different to Java in this area: their language definitions leave evaluation order undefined deliberately to enable more optimizations. C# is like Java apparently, but I don't know its literature well enough to be able to point to the formal definition. (This really varies by language though, Ruby is strictly L2R, as is Tcl — though that lacks an assignment operator per se for reasons not relevant here — and Python is L2R but R2L in respect of assignment, which I find odd but there you go.)
a[b] = b = 0;
1) array indexing operator has higher precedence then assignment operator (see this answer):
(a[b]) = b = 0;
2) According to 15.26. Assignment Operators of JLS
There are 12 assignment operators; all are syntactically right-associative (they group right-to-left). Thus, a=b=c means a=(b=c), which assigns the value of c to b and then assigns the value of b to a.
(a[b]) = (b=0);
3) According to 15.7. Evaluation Order of JLS
The Java programming language guarantees that the operands of operators appear to be evaluated in a specific evaluation order, namely, from left to right.
and
The left-hand operand of a binary operator appears to be fully evaluated before any part of the right-hand operand is evaluated.
So:
a) (a[b]) evaluated first to a[1]
b) then (b=0) evaluated to 0
c) (a[1] = 0) evaluated last
Your code is equivalent to:
int[] a = {4,4};
int b = 1;
c = b;
b = 0;
a[c] = b;
which explains the result.
Consider another more in-depth example below.
As a General Rule of Thumb:
It's best to have a table of the Order of Precedence Rules and Associativity available to read when solving these questions e.g. http://introcs.cs.princeton.edu/java/11precedence/
Here is a good example:
System.out.println(3+100/10*2-13);
Question: What's the Output of the above Line?
Answer: Apply the Rules of Precedence and Associativity
Step 1: According to rules of precedence: / and * operators take priority over + - operators. Therefore the starting point to execute this equation will the narrowed to:
100/10*2
Step 2: According to the rules and precedence: / and * are equal in precedence.
As / and * operators are equal in precedence, we need to look at the associativity between those operators.
According to the ASSOCIATIVITY RULES of these two particular operators,
we start executing the equation from the LEFT TO RIGHT i.e. 100/10 gets executed first:
100/10*2
=100/10
=10*2
=20
Step 3: The equation is now in the following state of execution:
=3+20-13
According to the rules and precedence: + and - are equal in precedence.
We now need to look at the associativity between the operators + and - operators. According to the associativity of these two particular operators,
we start executing the equation from the LEFT to RIGHT i.e. 3+20 gets executed first:
=3+20
=23
=23-13
=10
10 is the correct output when compiled
Again, it is important to have a table of the Order of Precedence Rules and Associativity with you when solving these questions e.g. http://introcs.cs.princeton.edu/java/11precedence/

Arrow (->) operator precedence/priority is lowest, or priority of assignment/combined assignment is lowest?

JLS:
The lowest precedence operator is the arrow of a lambda expression
(->), followed by the assignment operators.
Followed in which direction (increasing priority, decreasing priority)? - "followed" means assignment has higher priority or lower priority (with respect to arrow operator)? I guess, in increasing, because "lowest" (for arrow) means absolutely lowest.
As I understand, arrow (->) should be at the very bottom of this Princeton operator precedence table (that is below all assignment operators), thus arrow (->) having 0 (zero) priority Level (as per that table).
Am I correct in my understanding?
ExamTray seems to say that arrow priority is at least same as assignment... Plus clarified that arrow associativity is Left->To->Right (unlike assignment). I didn't find any JLS quote for arrow associativity.
I always used to think that assignment priority is principally lowest for a reason.
Note the sentence preceding the quoted JLS text:
Precedence among operators is managed by a hierarchy of grammar productions.
The grammar of the Java language determines which constructs are possible and implicitly, the operator precedence.
Even the princeton table you’ve linked states:
There is no explicit operator precedence table in the Java Language Specification. Different tables on the web and in textbooks disagree in some minor ways.
So, the grammar of the Java language doesn’t allow lambda expressions to the left of an assignment operator and likewise, doesn’t allow assignments to the left of the ->. So there’s no ambiguity between these operators possible and the precedence rule, though explicitly stated in the JLS, becomes meaningless.
This allows to compile, e.g. such a gem, without ambiguity:
static Consumer<String> C;
static String S;
public static void main(String[] args)
{
Runnable r;
r = () -> C = s -> S = s;
}
First, let's explain the practical issue here.
Assuming you have a definition like
IntUnaryOperator op;
The following is syntactically accepted, and works as expected:
op = x -> x;
That is, we have an identity function on int assigned to the op variable. But if = had a higher priority, we'd expect Java to interpret this as
(op = x) -> x;
Which is not syntactically valid, thus should be a compile error. Hence, assignment does not, in practice, have higher precedence than the arrow.
But the following is also OK (assume t is a class/instance variable of type int):
op = x -> t = x;
This compiles, and the function, if applied, assigns the value of the operand to t and also returns it.
This means that the arrow doesn't have higher precedence than the assignment t = x. Otherwise it would have been interpreted as
op = ( x -> t ) = x
and clearly, this is not what happens.
So it seems that the operations have equal precedence. What's more, that they are right-associative. This is implied from the grammar at JLS chapter 19:
Expression:
LambdaExpression
AssignmentExpression
LambdaExpression:
LambdaParameters -> LambdaBody
...
LambdaBody:
Expression
Block
So the right side of the lambda body gets us back to Expression, which means we can either have a (higher priority) lambda inside it, or a (higher priority) assignment in it. What I mean by "higher priority" is that the deeper you go through the production rules, the earlier the expression will be evaluated.
The same is true for the assignment operator:
AssignmentExpression:
ConditionalExpression
Assignment
Assignment:
LeftHandSide AssignmentOperator Expression
Once again, the right side of the assignment throws us back to Expression, so we can have a lambda expression or an assignment there.
So rather than relying on the JLS text, the grammar gives us a well defined description of the situation.

What does Strictfp means in java?

If anyone can explain me what is strictfp in java with an example and a good explanation then that will be great.
I have already search the internet but still I am unable to get the clear solution for the same
Thanks in advance :)
The explanation given by the JLS seems pretty clear:
Within an FP-strict expression, all intermediate values must be elements of the float value set or the double value set, implying that the results of all FP-strict expressions must be those predicted by IEEE 754 arithmetic on operands represented using single and double formats.
Within an expression that is not FP-strict, some leeway is granted for an implementation to use an extended exponent range to represent intermediate results; the net effect, roughly speaking, is that a calculation might produce "the correct answer" in situations where exclusive use of the float value set or double value set might result in overflow or underflow.
For a discussion of when one might use strictfp, see When should I use the "strictfp" keyword in java?

How does expression evaluation order differ between C++ and Java?

I've had my brain wrinkled from trying to understand the examples on this page:
http://answers.yahoo.com/question/index?qid=20091103170907AAxXYG9
More specifically this code:
int j = 4;
cout << j++ << j << ++j << endl;
gives an output: 566
Now this makes sense to me if the expression is evaluated right to left, however in Java a similar expression:
int j = 4;
System.out.print("" + (j++) + (j) + (++j));
gives an output of: 456
Which is more intuitive because this indicates it's been evaluated left to right. Researching this across various sites, it seems that with C++ the behaviour differs between compilers, but I'm still not convinced I understand. What's the explanation for this difference in evaluation between Java and C++? Thanks SO.
When an operation has side effects, C++ relies on sequence points rule to decide when side effects (such as increments, combined assignments, etc.) have to take effect. Logical and-then/or-else (&& and ||) operators, ternary ? question mark operators, and commas create sequence points; +, -, << and so on do not.
In contrast, Java completes side effects before proceeding with further evaluation.
When you use an expression with side effects multiple times in the absence of sequence points, the resulting behavior is undefined in C++. Any result is possible, including one that does not make logical sense.
Java guarantees that the operands of operators appear to be evaluated in a specific evaluation order, namely, from left to right. The left-hand operand of a binary operator appears to be fully evaluated before any part of the right-hand operand is evaluated. Java also guarantees that every operand of an operator (except the conditional operators &&, ||, and ?:) appears to be fully evaluated before any part of the operation itself is performed. See Java language specification §15.7 for more details.
C++, on the other hand, happily let's you get away with undefined behavior if the expression is ambiguous because language itself doesn't guarantee any order of evaluation of sub-expressions. See Sequence Point for more details.
In C++ the order of evalulations of subexpressions isn't left-to-right nor right-to-left. It is undefined.

Does Android support short circuiting?

This seems to be a stupid question since Java does short circuit, but I remembered how Android doesn't quite use Java in the same sense as I assume, so say in this bit of code I wrote:
... code omitted ...
else if (mimeType.equals("application/x-tar")
|| mimeType.equals("application/x-rar-compressed")
|| mimeType.equals("application/stuffit")
|| mimeType.equals("application/zip")
|| mimeType.equals("application/x-gzip"))
...would it be better for me to put the more common things (zip/rar) before the less common things (tarballs/gzip)?
The fact that I wasn't able to find a similar question on SO probably gives me the answer to this, but better safe than sorry.
Short circuiting is supported with ||.
If you are trying to optimize this case you should try putting each value in a static Set and then check to see if typeSet.contains(mimeType).
Yes, the || (conditional-or) operator is a short-circuit operator. To quote the Java Language Specification:
The || operator is like | (§15.22.2), but evaluates its right-hand operand only if the value of its left-hand operand is false. It is syntactically left-associative (it groups left-to-right). It is fully associative with respect to both side effects and result value; that is, for any expressions a, b, and c, evaluation of the expression ((a)||(b))||(c) produces the same result, with the same side effects occurring in the same order, as evaluation of the expression (a)||((b)||(c)).

Categories

Resources