Site Search:

Use Java operators; including parentheses to override operator precedence

Back OCAJP


Study this section is like study mathematics. We will go through the rules, then practice, practice and practice, until executing these rules became no brainer.

The most common operators are arithmetic operators, we already know the rules from algebra class.
(5 + 5)/5*2 - 8%2 = ((5+5)/5)*2 - (8%2) = (10/5)*2 - 0 = 2*2 = 4

In algebra, +, -, *, % are straight forward, however / is tricky, since an integer divided by another integer can yield a fraction number. In java, when / is applied to two integers, the floor is returned.

OCAJP>cat test.java 
class test{
  public static void main(String[] args) {
    System.out.println(1/3);
    System.out.println(2/3);
    System.out.println(3/3);
    System.out.println(4/3);
    System.out.println(5/3);
    System.out.println(6/3);

    System.out.println();
    System.out.println(1%3);
    System.out.println(2%3);
    System.out.println(3%3);
    System.out.println(4%3);
    System.out.println(5%3);
    System.out.println(6%3);
    
  }
OCAJP>javac test.java 
OCAJP>java test
0
0
1
1
1
2

1
2
0
1
2
0

In algebra, we learned how to calculate when numbers with different precisions are mixed.
10.5 + 3 = 10.5 + 3.0 = 13.5
10.0001 + 3.1 = 10.0001 + 3.1000 = 13.1001

Java has similar rules when handle numeric primitives with different types -- the lower precision primitive types are promoted to higher precision primitive types before arithmetic calculating. Specifically byte and short are automatically promoted to int before any arithmetic calculations.





OCAJP>cat test.java 
class test{
byte b = 1;
short s = 1;
short s1 = 1;
int i = 2;
long l = 1L;
long ll = 1; //auto cast int 1 to 1L
float f = 1.1f;
double d = 1.1;
long l1 = i - l;  //i is converted from int to long
int i1 = b + s;  //byte and short are automatically promoted to int
long l2 = b + l;  //byte is automatically promoted to int, then to long when work with long.
double d1 = f * d;  //float promote to double
double d2 = l + d;  //long promote to double
float f1 = l + f;  //long promote to float
float f2 = b / f;  //byte promote to float
float f3 = f % i;  //int promote to float
double d3 = b++ * --f + s/b*d - (++i % 7.8f);  //the highest precision type is double at right side
//short s3 = s + s1;  //not compile
//short s4 = b + s;  //not compile
OCAJP>javac test.java 
OCAJP>
======
Besides addition (+), substraction(-), multiplication(*), division(/), modulus(%), java have increment(++) and decrement(--) operators.
++i (--i) increases (decreases) i by 1 then returns the value, i++ (i--) returns the value of i, then increases(decreases) i by 1.


int i = 5; int j = 5;
System.out.println(i++);  //5
System.out.println(i);  //6
System.out.println(i--); //6
System.out.println(i);  //5
System.out.println(++j);  //6
System.out.println(j);  //6
System.out.println(--j);  //5
System.out.println(j);  //5


++ and -- take precedence when working with arithmetic operators.


OCAJP>cat test.java 
class test{
public static void main(String[] a){
  int i = 5;
  System.out.println(i++ + 10/--i);  //7
  System.out.println(i);  //5
}} 
OCAJP>javac test.java 
OCAJP>java test
7
5

i++ + 10/--i
equivalent to (i++) + 10/(--i)
execute i++ returns 5, i has value 6
5 + 10/(--i)
execute --i returns 5, i have value 5
5 + 10/5 = 5 + 2 = 7

Java also allows type casting among arbitrary numeric primitive types. However, casting from longer/preciser types to shorter/less precise types is a "possible lossy conversion", where overflow happens.


OCAJP>cat test.java 
class test{
public static void main(String[] a){
  System.out.println(Long.MAX_VALUE);
  System.out.println((int)Long.MAX_VALUE);  //for OCA, don't have to know the exact number
}} 
OCAJP>javac test.java 
OCAJP>java test
9223372036854775807
-1

Compound assignment operators (+=, -=, *=, /=)  automatically do the type cast, so that we don't have to worry about compilation error due to type mismatch.


OCAJP>cat test.java 
class test{
public static void main(String args[]){
  int i = 10;
  long l = 10L;
  //int i1 = i*l;  //not compile
  //int i1 = (int)i*l;  //not compile
  int i1 = (int)(i*l);

  int i2 = 3;
  //i2 = i2 + l;  //not compile
  i2 = (int)(i2 + l);
  i2 += l;  //equivalent to the previous line

  long l2 = 3L;
  l2 = l2 * i;
  l2 = (long)(l2 * i);  //type cast is redundant here
  l2 *= i;  //equivalent to previous line
}} 
OCAJP>javac test.java 
OCAJP>


Assignment operator also returns the value of the assignment. For example, (x = 5) returns value 5.
Knowing this, we can assign (x=5) to another variable y.


OCAJP>cat test.java
class test{
  public static void main(String...args) {
    int x = 5;
    int y = (x = 5);
    System.out.println("x="+x+", y="+y);
    int i;
    int j;
    System.out.println((j=((i=1)+3)+2));
  }
}
OCAJP>javac test.java 
OCAJP>java test
x=5, y=5
6
OCAJP>



Besides arithmetic operators and assignment operators discussed so far, JCA also test logical operators:
AND (&)


OR(|)


EXCLUSIVE OR (^)


Notice !^ does not equivalent to &, beyond A, B, there is universe !(A|B). Visually, the true/false is relative, left circle have different definition of true/false than that of the right circle, they agree on the meaning of false in the !(A|B), and agree on the meaning of true in A|B, in A^B, their definition of true/false conflicts. Beyond context, true, false does not exist. Am I pretty? "yes", "no"; "who cares?" then wait for your girlfriend to throw RunTimeException; say nothing, give a hug; "wait, author, what's your point, OCA?";... (don't worry, OCA won't test english, you only have to calculate boolean result one step at a time).

!(A^B) = ((A&B) | !(A|B))



OCAJP>cat test.java 
class test{
  public static void main(String...args) {
    boolean[] x = {true, false};
    boolean[] y = {true, false};
    System.out.println("AND (&)");
    for(boolean i: x) {
      for(boolean j: y) {System.out.println(new Boolean(i).toString() + " & " + new Boolean(j).toString() + " =  " + new Boolean(i&j).toString());} 
    }
    System.out.println("OR (|)");
    for(boolean i: x) {
      for(boolean j: y) {System.out.println(new Boolean(i).toString() + " | " + new Boolean(j).toString() + " =  " + new Boolean(i|j).toString());} 
    }
    System.out.println("XOR (^)");
    for(boolean i: x) {
      for(boolean j: y) {System.out.println(new Boolean(i).toString() + " ^ " + new Boolean(j).toString() + " =  " + new Boolean(i^j).toString());} 
    }
    System.out.println("NOT (!)");
    for(boolean i: x) {System.out.println("!" + new Boolean(i).toString() + " = " + new Boolean(!i).toString());}

    System.out.println("!(A^B) = ((A&B)|!(A|B)) ");
    for(boolean i: x) {
      for(boolean j: y) {System.out.println(new Boolean(i).toString() + " !(^) " + new Boolean(j).toString() + " =  "  + new Boolean((!(i^j))).toString() + " " + new Boolean(((i&j)|!(i|j))).toString());} 
    }
  }

}
OCAJP>javac test.java 
OCAJP>java test
AND (&)
true & true =  true
true & false =  false
false & true =  false
false & false =  false
OR (|)
true | true =  true
true | false =  true
false | true =  true
false | false =  false
XOR (^)
true ^ true =  false
true ^ false =  true
false ^ true =  true
false ^ false =  false
NOT (!)
!true = false
!false = true
!(A^B) = ((A&B)|!(A|B)) 
true !(^) true =  true true
true !(^) false =  false false
false !(^) true =  false false
false !(^) false =  true true
OCAJP>



The conditional operators AND (&&), OR (||) is the same as logical operators, except that, they search the first match from left to right, once || found the first true, && found the first false, then the the rest of the conditional tests are skipped.
Programmer often uses them to test before act, in order to avoid NullPointerException, ArrayIndexOutOfBoundsException etc. If you know what you want, use the straight forward &&; if you know what you don't want, use the hesitate ||.


OCAJP>cat test.java 
class test{
  //match criteria: the first character of the first argument is 'k'
  public static void main(String...args) {
    System.out.println(args.length);  //hey, scientist
    if(args == null || !(args instanceof Object[]) || args.length != 1 || args[0] == null || !(args[0] instanceof String) ||args[0].length() != 1 || args[0].charAt(0) != 'k' ){
      // args.length != 1 instead of (args.length == 2 || args.length == 5...|| args.length ==1000...)
      System.out.println("fall in || trap, either throw run time exception, or a non-match");
    } else {
      //hope your trap have caught all the bad, and only bad
      System.out.println("survived || trap, should be the one matches requirement");
    } 
    if(args != null && args instanceof Object[] && args.length == 1 && args[0] != null && args[0] instanceof String && args[0].length() == 1 && args[0].charAt(0) == 'k'){
      System.out.println("pass && filter, matched all requirement");
    } else {
      //hope your filter have all the rules, and only the wanted rules
      System.out.println("filter out by && filter, should be the one either throw run time exception or a non-match");
    }
  }
}
OCAJP>javac test.java 
OCAJP>java test
0
fall in || trap, either throw run time exception, or a non-match
filter out by && filter, should be the one either throw run time exception or a non-match
OCAJP>java test a
1
fall in || trap, either throw run time exception, or a non-match
filter out by && filter, should be the one either throw run time exception or a non-match
OCAJP>java test a b
2
fall in || trap, either throw run time exception, or a non-match
filter out by && filter, should be the one either throw run time exception or a non-match
OCAJP>java test kk
1
fall in || trap, either throw run time exception, or a non-match
filter out by && filter, should be the one either throw run time exception or a non-match
OCAJP>java test k
1
survived || trap, should be the one matches requirement
pass && filter, matched all requirement




The above code, though cautious,  should never exist in production, since we all know java parameters is an array of String and is not null. Unfortunately, this kind of code are everywhere.


OCAJP>cat test.java 
class test{
  public static void main(String...args) {
    //simple version
    System.out.println(args.length);
    if(args.length > 0 && args[0].length() > 0 && args[0].charAt(0) == 'k') {
      System.out.println("found"); 
    }
  }
}
OCAJP>javac test.java 
OCAJP>java test
0
OCAJP>java test a
1
OCAJP>java test a b
2
OCAJP>java test k
1
found
OCAJP>java test kk
1
found

Finally, we just list relational operators without explanations, since their names say it all: LESS THAN (<), LESS THAN OR EQUAL TO (<=), GREATER THAN (>), GREATER THAN OR EQUAL TO (>=), EQUAL TO (==), NOT EUQAL TO (!=).

The order of operator precedence is listed below, the upper lines takes precedence over the lower lines in the list.

post-unary operators i++, i--
pre-unary operators ++i, --i
positive(+), negative(-), negate(!)
multiplication(*), devision(/), modulus(%)
addition(+), subtraction(-)
signed left shift(<<), signed right shift(>>), unsigned right shift(>>>), unary bitwise complement operator(~)
<, >, <=, >=, instance of
==, !=
AND(&), OR(|), XOR(^)
AND(&&), OR(||)
boolean expression ? expression1 : expression2
=, +=, -=, *=, /=, %=, &=, |=, ^=, !=, <<=, >>=, >>>=, ~=

When operators have the same precedence, the execution is from left to right, and parentheses can override operator precedence.


OCAJP>cat test.java 
class test{
public static void main(String[] a){
  int i = 2;
  System.out.println(i++ + 10/--i);  //7
  System.out.println(i);  //2
  System.out.println(++i + 10/--i);  //8
  System.out.println(i);  //2
}} 
OCAJP>javac test.java 
OCAJP>java test
7
2
8
2

i= 2
i++ + 10/--i  equivalents to
(i++) + (10/(--i)) executes from left to right
left: (i++) returns 2, i is 3
right: (--i) returns 2, i is 2, 10/2 = 5
2 + 5 = 7

++i + 10/--i equivalents to
(++i) + (10/(--i)) executes from left to right
left: (++i) returns 3, i is 3
right: (--i) executes firstly, returns 2, i is 2,  10/2 = 5
3 + 5 = 8

Next we will introduce java statement and flow control.

The plan is, we will revisit the topics learned here again and again and again: mixing operators with java statements, to intentionally makes them hard. We spent a lot time on these topics because OCAJP exam has many questions in this area, we need to answer them quickly. On the other hand, syntax sugar is everywhere when you do code reviews, you need to quickly go through and understand what the code is doing.

Back OCAJP