Java statements and expressions usually contain some form of Java operator. You’ve been exposed to several operators already, namely, the assignment operator, the addition operator, and the new operator (=, +, new). Table 6-4 lists the operators and gives a brief description of each. You will be gradually exposed to most of these operators as you progress through the text.
Operator | Precedence | Associativity | Operands | Description |
---|---|---|---|---|
++ | 15 | Left to Right | variable | postfix increment operator |
-- | 15 | Left to Right | variable | postfix decrement operator |
(args) | 15 | Left to Right | method, argument list | method invocation |
[] | 15 | Left to Right | array, int | array element access |
. | 15 | Left to Right | object, member | object member access |
! | 14 | Right to Left | boolean | boolean NOT operator |
~ | 14 | Right to Left | int | bitwise complement |
+ | 14 | Right to Left | number | unary plus operator |
- | 14 | Right to Left | number | unary minus operator |
++ | 14 | Right to Left | variable | prefix increment operator |
-- | 14 | Right to Left | variable | prefix decrement operator |
(type) | 13 | Right to Left | type, any | type conversion (cast) operator |
new | 13 | Right to Left | class, argument | list object creation operator |
* | 12 | Left to Right | number, number | multiplication operator |
/ | 12 | Left to Right | number, number | division operator |
% | 12 | Left to Right | int, int | integer remainder (modulus) operator |
+ | 11 | Left to Right | number, number | addition operator |
- | 11 | Left to Right | number, number | subtraction operator |
+ | 11 | Left to Right | string, any | string concatenation operator |
<< | 10 | Left to Right | int, int | left shift operator |
>> | 10 | Left to Right | int, int | right shift with sign extension operator |
>>> | 10 | Left to Right | int, int | right shift with zero extension operator |
instanceof | 9 | Left to Right | reference, type | type comparison operator |
< | 9 | Left to Right | number, number | less than operator |
<= | 9 | Left to Right | number, number | less than or equal to operator |
> | 9 | Left to Right | number, number | greater than operator |
>= | 9 | Left to Right | number, number | greater than or equal to operator |
!= | 8 | Left to Right | reference, reference | not equal (different objects) operator |
== | 8 | Left to Right | reference, reference | equality (the same object) operator |
!= | 8 | Left to Right | primitive, primitive | not equal (different values) operator |
== | 8 | Left to Right | primitive, primitive | equality (same value) operator |
& | 7 | Left to Right | boolean, boolean | boolean AND operator |
& | 7 | Left to Right | int, int | bitwise AND operator |
^ | 6 | Left to Right | boolean, boolean | boolean XOR operator |
^ | 6 | Left to Right | int, int | bitwise XOR operator |
| | 5 | Left to Right | boolean, boolean | boolean OR operation |
| | 5 | Left to Right | int, int | bitwise OR operator |
&& | 4 | Left to Right | boolean. boolean | conditional AND operator |
|| | 3 | Left to Right | boolean, boolean | conditional OR operator |
?: | 2 | Right to Left | boolean, any, any | ternary conditional operator |
*=, /=, %=, +=, -=, <<=, >>=, >>>=, &=, ^=, |= | 1 | Right to Left | variable, any | Combines assignment with operation |
= |
1 |
Right to Left |
variable, any | assignment |
The operators are listed by descending precedence order. The higher the precedence number the tighter the operator binds to its operands. Some operators associate left to right while others associate right to left. The operands column specifies what type of operands the operator expects. Some operators are overloaded to perform a similar operation on different types of operands.
In some cases it will be clear how you intend an operator to be applied, associated, and evaluated in an expression. Take, for example, the following piece of code:
some_variable = 4 + 6;
In this case the expression 4 + 6 will be evaluated first to yield a value of 10 which is then assigned to some_variable. However, consider for a moment the following expression:
some_variable = 7 * 8 / 3 + 22 - 38;
A strict evaluation according to the precedence of each operator will yield one value being assigned to some_variable but the application of parentheses will yield another:
some_variable = 7 * (8 / (3 + (22 - 38)));
Using parentheses to explicitly force operator association makes your code easier to read and reduces the possibility of making a mistake in an expression.
This section presents a detailed discussion of most of the Java operators. Those not covered below will be discussed in greater detail later in the text. It’s important to know not only what kind of operators are available for your use but also what, if any, limitations or concerns you should be aware of when you use an operator.
The arithmetic operators perform the familiar operations of addition, subtraction, multiplication, and division. They take as operands all the numeric primitive data types. These include byte, short, int, long, float, and double.
You should remember at all times that you are not adding, subtracting, multiplying, or dividing actual numbers, but machine representations of numbers. Each primitive numeric data type has a range of authorized values. If you are not careful you may find that your programs behave in unexpected ways because you have unknowingly exceeded the range of a particular type.
Pay particular attention to operator precedence. The multiplication ‘*’ and division’/’ operators take precedence over addition ‘+’ and subtraction ‘-’. I recommend using parentheses to explicitly force the particular order of evaluation you desire. Doing so benefits you rather than the computer as it forces you to think about the code you are writing.
Another aspect of usage to consider is when operators are applied to different data types in the same expression. For example, the byte data type holds a very small positive and negative value when compared with the int or long data type. The float and double data types store decimal values but the integer types do not. The capability of one numeric data type to store a larger value than another makes that larger data type more precise. Any attempt to assigned the value of a larger data type to a smaller, less precise, data type, will result in a compiler error warning of a possible loss of precision.
When you are performing division and expect a very small positive decimal value you should use the float or double data types. Study the code shown in example 6.16 below and compare it with its output shown in figure 6-16.
Example 6.16: DivisionTest.java
1 public class DivisionTest { 2 3 public static void main(String[] args){ 4 int int_i = 0; 5 int int_j = 1; 6 int int_k = 320; 7 8 float float_i = 0.0f; 9 float float_j = 1.0f; 10 float float_k = 320.0f; 11 12 int_i = int_j/int_k; 13 System.out.println(int_i); 14 15 float_i = int_j/int_k; 16 System.out.println(float_i); 17 18 /******** generates loss of precision error ******** 19 int_i = int_j/float_k; 20 System.out.println(int_i); 21 ****************************************************/ 22 23 float_i = int_j/float_k; 24 System.out.println(float_i); 25 26 float_i = float_j/int_k; 27 System.out.println(float_i); 28 29 } 30 }
Figure 6-16: Results of Running Example 6.16
Referring to example 6.16, several division operations are performed with a combination of int and float data type variables. The value 1 is divided by the value 320. On line 12 all data types involved in the expression are int. This results in the value 0 being assigned to the variable int_i. Line 15 produces the same result even though the receiving variable is a float.
Lines 23 and 26 produce the desired result. When one of the division operands is a floating point type the result of the division is automatically converted (cast) by the compiler to a floating point type. If the receiving variable is a floating point type then all will go well. If not, as is the case with line 19, then a compiler error will result warning of a possible loss of precision.
The plus symbol is also used in Java to perform String concatenation. The String concatenation operator is used to create a new String by joining one or more Strings or by joining a String with another data type. The other data type will be converted to a String and then combined with the existing String value to form a new String object. Example 6.17 offers a few examples of its use.
Example 6.17: StringOperatorTest.java
1 public class StringOperatorTest { 2 public static void main(String[] args){ 3 String salutation = "Hello "; 4 String welcome_msg = "Welcome to Java For Artists"; 5 String name = args[0]; 6 7 String complete_msg = salutation + args[0] + ", " + welcome_msg + '!'; 8 9 System.out.println(complete_msg); 10 } 11 }
Figure 6-17: Results of Running Example 6.17
Example 6.16 takes a command-line argument String and concatenates it with the other program String variables to form a complete welcome message that is displayed when the program is executed.
The modulus operator performs integer division and returns the remainder. Example 6.18 shows the modulus operator in action. Figure 6-18 shows the results of running this program.
Example 6.18: ModulusOperatorTest.java
1 public class ModulusOperatorTest { 2 public static void main(String[] args){ 3 System.out.println(100 % 1); 4 System.out.println(100 % 2); 5 System.out.println(100 % 3); 6 System.out.println(100 % 4); 7 System.out.println(100 % 6); 8 System.out.println(100 % 11); 9 System.out.println(100 % 12); 10 System.out.println(100 % 13); 11 System.out.println(100 % 23); 12 System.out.println(100 % 27); 13 System.out.println(100 % 100); 14 } 15 }
Figure 6-18: Results of Running Example 6.18
The greater-than and less-than operators, including the greater-than-or-equals-to and less-than-or-equals-to operators, operate on numeric primitive data types and return a boolean value of either true or false. Example 6.19 shows these operators in action.
Example 6.19: GreaterLessThanTest.java
1 public class GreaterLessThanTest { 2 public static void main(String[] args){ 3 System.out.println(2 > 1); 4 System.out.println(2 < 1); 5 System.out.println(2 >= 1); 6 System.out.println(2 <= 1); 7 System.out.println(2 > 2); 8 System.out.println(2 < 2); 9 System.out.println(2 >= 2); 10 System.out.println(2 <= 2); 11 } 12 }
Figure 6-19: Results of Running Example 6.19
The equality and inequality operators can be applied to primitive and reference data types. When applied to primitive types the operators compare actual values. When applied to reference data types the operators compare the memory location values to determine if the objects are the same object or not. These operators return a boolean value of true or false. Example 6.20 shows these operators in action. Figure 6-20 shows the results of running this program.
Example 6.20: EqualityOpTest.java
1 public class EqualityOpTest { 2 public static void main(String[] args){ 3 4 Object object_1 = new Object(); 5 Object object_2 = new Object(); 6 Object object_3 = object_2; 7 int int_i = 0; 8 int int_j = 1; 9 10 System.out.println(object_1 == object_2); 11 System.out.println(object_1 != object_2); 12 System.out.println(object_2 == object_3); 13 System.out.println(object_2 != object_3); 14 System.out.println(int_i == int_j); 15 System.out.println(int_i != int_j); 16 System.out.println(5 == 6); 17 System.out.println('r' != 's'); 18 } 19 }
Figure 6-20: Results of Running Example 6.20
The conditional operators perform conditional AND and OR operations. Their operands must be expressions that evaluate to the boolean values true or false. The && (conditional AND) operator will return true only if all operand expressions evaluate to true. If the first operand evaluates to false the second operand is not evaluated.
The || (conditional OR) operator will return true if any of its operand expressions evaluate to true. If the first operand is true the second operand is not evaluated.
Example 6.21 shows the conditional operators in action. Figure 6-21 shows the results of running this program.
Example 6.21
ConditionalOpTest.java 1 public class ConditionalOpTest { 2 public static void main(String[] args){ 3 Object object_1 = new Object(); 4 Object object_2 = new Object(); 5 Object object_3 = object_2; 6 int int_i = 0; 7 int int_j = 1; 8 9 System.out.println((object_1 != null) && (object_2 != null)); 10 System.out.println((object_1 != object_2) && (int_i != int_j)); 11 System.out.println((object_2 == object_3) || (int_i != int_j)); 12 System.out.println((object_2 != object_3) || (5 == 6)); 13 System.out.println((int_i == int_j) || (int_i != int_j)); 14 System.out.println((int_i != int_j) && ('r' != 's')); 15 System.out.println((5 == 6) || ('r' != 's')); 16 System.out.println(('r' != 's') && ('r' != 't')); 17 } 18 }
Figure 6-21: Results of Running Example 6.21
The boolean operators & and | perform similar operations to the conditional operators && and ||. They take boolean operands and return a boolean value of true or false. The difference is that the & and | operators will evaluate both of their operands regardless of the result of the first operand expression evaluation. These operators are infrequently used.
The boolean NOT operator will return the opposite value of the expression to which it is applied. This operator is used extensively.
The boolean XOR (Exclusive OR) will return true if exactly one of its operand expressions evaluates to true.
Example 6.22 shows these operators in action. Figure 6-22 shows the results of running this program.
Example 6.22: BooleanOpTest.java
1 public class BooleanOpTest { 2 public static void main(String[] args){ 3 Object object_1 = new Object(); 4 Object object_2 = new Object(); 5 Object object_3 = object_2; 6 int int_i = 0; 7 int int_j = 1; 8 9 System.out.println((object_1 != null) & (object_2 != null)); 10 System.out.println((object_1 != object_2) | (int_i != int_j)); 11 System.out.println((object_2 == object_3) | (int_i != int_j)); 12 System.out.println((object_2 == object_3) ^ (!(int_i != int_j))); 13 System.out.println((object_2 != object_3) | (5 == 6)); 14 System.out.println((int_i == int_j) | (int_i != int_j)); 15 System.out.println((int_i != int_j) ^ ('r' != 's')); 16 System.out.println((5 == 6) | ('r' != 's')); 17 System.out.println(('r' != 's') & ('r' != 't')); 18 } 19 }
Figure 6-22: Results of Running Example 6.22
It takes a while for novice programmers to warm up to the ternary conditional operator. It is strange to look at but provides some cool functionality. The operator takes three operands. The first is an expression that evaluates to a boolean value of true or false. The second two operands can be of any type so long as they are both the same. The operator returns the value of the second or third operand depending on if the first operand evaluates to true or false. Example 6.23 shows this unique operator in action. This program takes two integers as command-line arguments, converts the Strings to ints, then compares the values to determine if the first argument is less than the second.
Example 6.23: TernaryOpTest.java
1 public class TernaryOpTest { 2 public static void main(String[] args){ 3 int int_i = Integer.parseInt(args[0]); 4 int int_j = Integer.parseInt(args[1]); 5 6 System.out.println("Is " + int_i + " less than " + int_j + '?'); 7 String answer = (int_i < int_j) ? "Yes" : "No"; 8 System.out.println(answer); 9 10 int smallest = (int_i < int_j) ? int_i : int_j; 11 System.out.println("Smallest value is: " + smallest); 12 } 13 }
Figure 6-23 shows the program being run twice, first with the values 6 and 7, then with the values 7 and 6. Notice how the ternary operator is used with String data types on line 7 and then with int data types on line 10.
Figure 6-23: Results of Running Example 6.23
The left and right shift operators take two integer operands. The left-hand operand is the variable whose bits are to be shifted and the right-hand operand is the amount by which the bits are to be shifted.
The left shift operator << will shift a variable’s bits to the left while shifting in zeros from the right to replace the shifted bit values.
The right shift operator >> shifts with sign extension, meaning that if the integer variable contains a negative value the sign bit, which is a 1, will be carried in from the left.
The unsigned right shift operator >>> will replace shifted bit values with zeros. Example 6.24 shows the left and right shift operators in action. Figure 6.24 shows the results of running this program.
Example 6.24: ShiftOpTest.java
1 public class ShiftOpTest { 2 public static void main(String[] args){ 3 4 byte byte_1 = 15; //00001111 5 int int_1 = 0x0002; //00000000000000000000000000000010 6 7 System.out.println(byte_1 << 1); // shift left 1 bit 8 System.out.println(byte_1 >> 1); // right shift 2 bits 9 System.out.println(byte_1 >> 2); // right shift 2 bits 10 System.out.println(byte_1 >>> 1); //unsigned right shift 1 bit 11 System.out.println(int_1 << 4); //left shift 4 bits 12 System.out.println(int_1 >>> 6); //unsigned right shift 6 bits 13 } 14 }
Figure 6-24: Results of Running Example 6.24
The instanceof operator is used to test objects to see if they belong to particular class types. The operator returns a boolean value of true or false depending on the results of the comparison. Example 6.25 shows the instanceof operator in action. Figure 6.25 gives the results of running this program.
Example 6.25: InstanceofOpTest.java
1 public class InstanceofOpTest { 2 public static void main(String[] args){ 3 Object object_1 = new Object(); 4 String string_1 = "I love Java!"; 5 6 System.out.println(object_1 instanceof Object); 7 System.out.println(string_1 instanceof String); 8 System.out.println(string_1 instanceof Object); 9 System.out.println(object_1 instanceof String); 10 } 11 }
Figure 6-25: Results of Running Example 6.25
Notice that the use of the instanceof operator on line 8 returns true because class String descends from class Object, therefore a String is an Object. However, an Object is not a String as is shown by the use of the instanceof operator on line 9.
The unary prefix and postfix increment and decrement operators take one operand and increment or decrement it by one. The operands can be any numeric type. The prefix operators are evaluated and the results applied to the current expression. The postfix versions are evaluated after the expression in which they appear. Example 6.26 shows these operators in action. Figure 6.26 gives the results of running this program.
Example 6.26: IncDecOpTest.java
1 public class IncDecOpTest { 2 public static void main(String[] args){ 3 int int_i = 0; 4 float float_i = 0.0f; 5 6 System.out.println(++int_i); //now it's 1 7 System.out.println(int_i++); //now it's 2, but after 1 is printed 8 System.out.println(--int_i); // 2 - 1 = 1 9 System.out.println(int_i--); // 1 - 1 = 0, but after 1 is printed 10 System.out.println(int_i); // now print 0 11 12 System.out.println(++float_i); //now it's 1 13 System.out.println(float_i++); //now it's 2, but after 1 is printed 14 System.out.println(--float_i); //2 - 1 = 1 15 System.out.println(float_i--); //1 - 1 = 0, but after 1 is printed 16 System.out.println(float_i); //now print 0 17 } 18 }
Figure 6-26: Results of Running Example 6.26
The member access operator is used to access a class or object’s public member fields and methods. An object’s fields and methods are accessed via a reference variable while a class’s static fields and methods are accessed via the class name. You have seen the member access operator in action in several examples in this and previous chapters. Namely, when a String is converted to an int via the Integer.parseInt() method. You’ve also seen it used to call the System.out.println() method. You will be introduced to the member access operator in greater detail in chapter 9.
The bitwise operators perform logical operations on the bits of integer operands according to the truth tables shown in figure 6.27.
Figure 6-27: Bitwise Operator Truth Tables
Example 6.27 shows these operators in use. Figure 6.28 shows the results of running this program.
Example 6.27: BitwiseOpTest.java
1 public class BitwiseOpTest { 2 public static void main(String[] args){ 3 int int_i = 0xFFFFFFFF; //11111111111111111111111111111111 4 int int_j = 0; //00000000000000000000000000000000 5 6 System.out.println(~int_i); 7 System.out.println(~int_j); 8 System.out.println(int_i & int_j); 9 System.out.println(int_i | int_j); 10 System.out.println(int_i ^ int_j); 11 } 12 }
Figure 6-28: Results of Running Example 6.27
The combination assignment operators combine assignment with the designated operation. These operators provide a shortcut way of writing expressions like the following:
operand_1 = operand_1 op operand_2;
The operands must be of a type normally compatible with the primary operator. Example 6.28 shows a few of these operators in action. Figure 6.29 shows the results of running this program.
Example 6.28: CombinationOpTest.java
1 public class CombinationOpTest { 2 public static void main(String[] args){ 3 int int_i = 0; 4 int int_j = 1; 5 int int_k = 2; 6 7 int_i += int_j; // same as int_i = int_i + int_j 8 System.out.println(int_i); 9 int_i *= (int_k *= int_k); 10 System.out.println(int_i); 11 int_i /= int_k; 12 System.out.println(int_i); 13 } 14 }
Figure 6-29: Results of Running Example 6.28