How to PROVE the precedence of '&&' and '||' by coding in Java?
I know from somewhere that logical AND: &&
has a higher precedence than logical OR: ||
in Java, but until now I haven't found any clue about how this precedence really acts. What would happen 开发者_运维百科if I didn't know about the precedence of the two and what mistake would I make?
I tried to write some code to PROVE the precedence of &&
and ||
but failed, for example:
boolExp1 || boolExp2 && boolExp3 || boolExp4
The code above produces the same results no matter the precedence of &&
and ||
, that is,
false || false && true || false
results in false
no matter what the precedence is.
I want a method or function that can PROVE the precedence of &&
and ||
. It should produce different results depending on the precedence of &&
and ||
. Is it possible?
Let's take your example expression:
boolExp1 || boolExp2 && boolExp3 || boolExp4
Now we believe that acts as:
boolExp1 || (boolExp2 && boolExp3) || boolExp4
right?
So let's suppose the opposite is true, and it's actually
(boolExp1 || boolExp2) && (boolExp3 || boolExp4)
What values of boolExp1
etc would give us different results?
Well, let's take:
boolExp1 = true
boolExp2 = false
boolExp3 = false
boolExp4 = false
Under the "&& has higher precedence" rules, the result would be true. Under the "|| has higher precedence rules", the result would be false. A quick test shows that the expression evaluates to true, however.
Of course, this doesn't actually prove that && has higher precedence than || - merely that || doesn't have higher precedence than &&. We could consider whether they have equal precedence - and test that with other expressions in a similar way... find a sample expression and values which would give different results under different precedence rules, and test them.
Ultimately though, I prefer:
- To trust the spec unless I have specific doubts
- To use parentheses to make my intentions clear
I wouldn't use the first expression "as is" in the first place... because unless you actually know the precedence rules (and I suspect many Java devs don't - I couldn't swear that I'd have got && and || right) you're in the dark. Better to make it explicit and clear where there's any doubt.
If &&
didn't have higher precedence than ||
, then this expression:
a || b && c
would be evaluated like this:
(a || b) && c
To verify if this is the case or not,
you can generate all combinations of a
, b
, and c
,
and compare the result of these two expressions,
to see if they are always equal or not, that is:
- For all combinations of
a
,b
, andc
- Verify that:
(a || b && c) == ((a || b) && c)
Sample code:
for (int i = 0; i < 8; ++i) {
boolean a = ((i >> 2) & 1) == 1;
boolean b = ((i >> 1) & 1) == 1;
boolean c = (i & 1) == 1;
boolean x1 = (a || b && c);
boolean x2 = ((a || b) && c);
if (x1 != x2) {
System.out.println(String.format("%s %s %s", a, b, c));
System.out.println(String.format(" %s || %s && %s => %s", a, b, c, x1));
System.out.println(String.format(" (%s || %s) && %s => %s", a, b, c, x2));
}
}
The output:
true false false true || false && false => true (true || false) && false => false true true false true || true && false => true (true || true) && false => false
As such, &&
has higher precedence than ||
.
I too had this same question but the answer was practically giving to me. Here is my example:
true || true && false
is equivalent to
true || (true && false)
So with this example it is easy to see that under the hood in Java the logical && has a higher precedence than ||.
You cannot prove anything useful about a programming language by just writing / running examples. For all you know, the compiler might be implemented so as to compile code in an illogical, inconsistent or non-deterministic fashion.
Even if you assume deterministic compilation and deterministic execution, the only thing that compiling / running an example proves is that that particular example exhibits a particular behavior. You cannot logically generalize from one example to another one, because without reference to a specification the compiler is just a black box. (Your very next example could be the one that is handled in a totally counter-intuitive fashion.)
The correct way to develop an understanding of a programming language is to read the language specification, a good textbook or a good tutorial. Combine this with writing code to confirm your understanding.
If you rely solely on reading example code and writing test programs, you are liable to pick up misconceptions, and bad habits that can be painful to unlearn.
I was looking at the java specification to see if they defined operator precedence for &&
and ||
Both are defined as left-associative and no operator precedence is defined.
See s. 15.7.3 a bit down from s. 17.7,
&&
s. 15.23,
||
s. 15.24
i.e. Java defines:
boolExp1 || boolExp2 && boolExp3 || boolExp4
As:
((((boolExp1) || boolExp2) && boolExp3) || boolExp4)
A simple test is:
boolean a = true || false && false;
boolean b = false && false || true;
if (a == b) { // different precedence
if (a == true) {
System.out.println("&& has higher precedence than ||");
} else { // a == false
System.out.println("|| has higher precedence than &&");
}
} else { // a != b, same precedence
if (a == true) { // and b == false
System.out.println("&& and || have equal precedence, and are executed right to left.");
} else { // a == false, b == true
System.out.println("&& and || have equal precedence, and are executed left to right.");
}
}
Note that this accounts for the possibility that &&
and ||
could have equal precedence, and then, in that case, determines if they're executed left to right, or right to left.
Unfortunately, this does not account for precedence that changes or precedence based on inside to outside or outside to inside, or many other possible orders of operation, not to mention it can be defeated by malicious or broken compilers, malicious or broken computers, and cosmic rays.
Anyway, it's really hard to prove your compiler/computer/universe isn't messing with you. So check the language specification in addition to testing.
This is relyed upon all the time in lines like the following.
Clearly these examples would blow up if the first expression were not always evaluated and the second expression not evaluated conditionally.
// second expression on evaluated if text != null in both cases.
String text = ??
if (text != null && text.length() > 0)
if (text == null || text.length() == 0
public static void main(String[] args) {
boolean res = b(false,1) || b(true,2) && b(false,3) || b(false,4);
System.out.println(res);
}
static boolean b(boolean b, int i){
System.out.println(i);
return b;
}
// 1 2 3 4 false
Both && and || have the same precedence, Evaluation happens from left to right. Let me explain with an example.
public static void main(String[] args) {
System.out.println("Result = " + (arg1() || arg2() && arg3() || arg4()));
}
private static boolean arg1() {
System.out.println("arg1");
return false;
}
private static boolean arg2() {
System.out.println("arg2");
return true;
}
private static boolean arg3() {
System.out.println("arg3");
return true;
}
private static boolean arg4() {
System.out.println("arg4");
return false;
}
this evaluates to :-
arg1
arg2
arg3
Result = true
But now let me change arg3() to return false
private static boolean arg3() {
System.out.println("arg3");
return false;
}
this results in :-
arg1
arg2
arg3
arg4
Result = false
So to conclude.. the evaluation takes place form left to right i.e
arg1 || arg2 && arg3 || arg4
output && arg3 || arg4
output || arg4
output
Hope this helps.
精彩评论