Java applications process data by evaluating *expressions*, which are combinations of literals, method calls, variable names, and operators. Expression evaluation typically produces a new value, which can be stored in a variable, used to make a decision, and so on. In this article, I'll show you how to create expressions for your programs. Many expressions involve operators, including additive, array-index, bitwise, conditional, and equality types. I'll introduce each operator and its operands, and also discuss important concepts such as operator overloading and operator precedence. We'll conclude with a primer on operator type conversion, including a small program that you can use to practice type conversions on your own. Note that examples in this article are based on Java 8.

## Evaluating simple expressions

A *simple expression* is a literal, variable name, or method call. No operators are involved. Here are some examples of simple expressions:

```
52 // integer literal
age // variable name
System.out.println("ABC"); // method call
"Java" // string literal
98.6D // double precision floating-point literal
89L // long integer literal
```

A simple expression has a type, which is either a primitive type or a reference type. In these examples, `52`

is an integer (`int`

), `System.out.println("ABC");`

is void (`void`

) because it returns no value, `"Java"`

is a string (`String`

), `98.6D`

is a double precision floating-point value (`double`

), and `89L`

is a long integer (`long`

). We don't know `age`

's type.

## Evaluating compound expressions with operators

A *compound expression* consists of one or more simple expressions integrated into a larger expression via an *operator*, which is a sequence of instructions symbolically represented in source code. The operator transforms its expression *operand(s)* into another value. For example, in `6 * 5`

, the multiplication operator (`*`

) transforms operands `6`

and `5`

into 30.

Compound expressions can be combined into larger expressions. For example, `6 * 5 + 10`

presents compound expression `6 * 5`

and a compound expression consisting of their product, addition operator `+`

, and `10`

. The order of their evaluation (multiply first and then add) is dictated by Java's **rules of precedence**, which we'll get to shortly.

Java's operators are classified by their number of operands. Operators with one operand (e.g., unary minus [`-`

], as in `-5`

) are *unary operators*. Operators with two operands (e.g., multiplication and addition) are *binary operators*. Finally, operators with three operands (e.g., conditional [`?:`

]) are *ternary operators*.

Java's operators are also classified by position. A *prefix operator* is a unary operator that precedes its operand (e.g., `-5`

), a *postfix operator* is a unary operator that follows its operand (e.g., `age++;`

-- add 1 to `age`

's numeric value), and an *infix operator* is a binary or ternary operator between the operator's operands (e.g., `age + 5`

).

Java provides many operators, which I discuss in the following sections.

## Additive operators

The *additive operators* increase or decrease a numeric value through addition and subtraction. Additive operators include addition (`+`

), subtraction (`-`

), postdecrement (`--`

), postincrement (`++`

), predecrement (`--`

), and preincrement (`++`

). String concatenation (`+`

) is also considered to be additive. Here's a formal definition for each of these operators:

- Addition: Given

, where each operand must be of character or numeric type, add*operand1*+*operand2*to`operand2`

and return the sum. Example:`operand1`

`4 + 6`

- Subtraction: Given

, where each operand must be of character or numeric type, subtract*operand1*-*operand2*from`operand2`

and return the difference. Example:`operand1`

`4 - 6`

- Postdecrement: Given

, where*variable*--must be of character or numeric type, subtract 1 from`variable`

's value (storing the result in`variable`

) and return the original value. Example:`variable`

`x--;`

- Postincrement: Given

, where*variable*++must be of character or numeric type, add 1 to`variable`

's value (storing the result in`variable`

) and return the original value. Example:`variable`

`x++;`

- Predecrement: Given
`--`

, where*variable*must be of character or numeric type, subtract 1 from its value, store the result in`variable`

, and return the new decremented value. Example:`variable`

`--x;`

- Preincrement: Given
`++`

, where*variable*must be of character or numeric type, add 1 to its value, store the result in`variable`

, and return the new incremented value. Example:`variable`

`++x;`

- String concatenation: Given

, where at least one operand is of*operand1*+*operand2*`String`

type, append's string representation to`operand2`

's string representation and return the result. Example:`operand1`

`"A" + "B"`

The addition, subtraction, postdecrement, postincrement, predecrement, and preincrement operators can generate values that overflow the limits of the result type. For example, adding two large positive 64-bit integer values can produce a value that cannot be represented in 64 bits. The resulting overflow is not detected or reported by Java's additive operators.

I've created a small application for playing with Java's additive operators. Listing 1 presents its source code.

#### Listing 1. AddOp.java

```
class AddOp
{
public static void main(String[] args)
{
System.out.println(125 + 463);
System.out.println(2.0 - 6.3);
int age = 65;
System.out.println(age);
System.out.println(age--);
System.out.println(age++);
System.out.println(--age);
System.out.println(++age);
System.out.println("A" + "B");
}
}
```

In the previous article, we used the JDK's `javac`

tool to compile Java source code and the `java`

tool to run the resulting application. Execute the following command to compile Listing 1:

`javac AddOp.java`

Assuming successful compilation, you should observe an `AddOp.class`

file in the current directory. Execute the following command to run it:

`java AddOp`

`AddOp`

responds by producing the following output:

```
588
-4.3
65
65
64
64
65
AB
```

The output provides insight into the postincrement, postdecrement, preincrement, and predecrement operators. For postincrement/postdecrement, `age`

's current value is output before the increment/decrement operation. For preincrement/predecrement, the operation is performed and its result is stored in `age`

, and then `age`

's new value is output.

## Array index operator

The *array index operator* (`[]`

) accesses an array element by providing the element's *index* (position). This operator is placed after the array variable's name, as in `grades[0]`

(access the first element in the array assigned to `grades`

; the first element is stored at index 0). This operator is formally defined below:

- Given

, where*variable*[*index*]must be of integer (`index`

`int`

) type, read a value from or store a value into's storage element at location`variable`

. Example:`index`

`temperatures[1]`

The value passed to * index* is a 32-bit integer that is either 0 or a positive value ranging to one less than the array's length, which is indicated by appending

`.length`

to the name of the array. For example, `grades.length`

returns the number of elements in the array assigned to `grades`

.Listing 2 presents the source code to an `ArrayIndexOp`

application that lets you play with the array index operator.

#### Listing 2. ArrayIndexOp.java

```
class ArrayIndexOp
{
public static void main(String[] args)
{
int[] grades = { 89, 90, 68, 73, 79 };
System.out.println(grades[1]);
grades[1] = 91;
System.out.println(grades[1]);
int index = 4;
System.out.println(grades[index]);
System.out.println(grades['C' - 'A']);
// System.out.println(grades[1D]);
}
}
```

Listing 2 is somewhat more interesting than Listing 1. After creating a five-element, one-dimensional array of integers (via an array initializer) and assigning the array's reference to `grades`

, `main()`

proceeds to access various elements. There are two items of interest:

- The array index operator's index must ultimately be a 32-bit integer (0 or a positive value). You can specify the name of an integer variable (e.g.,
`index`

), which contains the index value, as the index. - You can specify a calculation involving character literals. When I discuss type conversions later in this article, you will discover why
`'C' - 'A'`

produces an integer (2), which serves as a valid index.

The final example, which passes `1D`

as an index to the array index operator, is commented out because it will not compile. If you uncomment the line and attempt to compile Listing 2, you will receive an error message about incompatible types: "possible lossy conversion from `double`

to `int.`

"

Compile Listing 2 (`javac ArrayIndexOp.java`

) and run the application (`java ArrayIndexOp`

). You should observe the following output:

```
90
91
79
68
```

## Assignment operators

The *assignment operator* (`=`

) assigns an expression's value to a variable (e.g., `i = 6;`

), including an array element (e.g., `x[0] = 15;`

). The expression and variable must be assignment compatible: their types must agree. For example, you cannot assign a string literal to an integer variable. I'll have more to say about this topic when I discuss type conversions.

The compound assignment operators (`+=`

, `-=`

, `*=`

, `/=`

, `%=`

, `&=`

, `|=`

, `^=`

, `<<=`

, `>>=`

, `>>>=`

) evaluate expressions and assign the results to variables in one step. Each expression and variable must be assignment compatible. Each operator serves as a useful shortcut. For example, instead of specifying `x = x + 3;`

, you can specify the shorter and equivalent `x += 3;`

.

## Bitwise operators

The *bitwise operators* modify the binary values of their operands, which must be of an integer (`byte`

, `short`

, `int`

, or `long`

) or character type. These operators include bitwise AND (`&`

), bitwise complement (`~`

), bitwise exclusive OR (`^`

), and bitwise inclusive OR (`|`

); and are formally defined below:

- Bitwise AND: Given

, where each operand must be of character or an integer type, bitwise AND their corresponding bits and return the result. A result bit is set to 1 when each operand's corresponding bit is 1. Otherwise, the result bit is set to 0. Example:*operand1*&*operand2*`1 & 0`

- Bitwise complement: Given
`~`

, where*operand*must be of character or an integer type, flip`operand`

's bits (1s to 0s and 0s to 1s) and return the result. Example:`operand`

`~1`

- Bitwise exclusive OR: Given

, where each operand must be of character or an integer type, bitwise exclusive OR their corresponding bits and return the result. A result bit is set to 1 when one operand's corresponding bit is 1 and the other operand's corresponding bit is 0. Otherwise, the result bit is set to 0. Example:*operand1*^*operand2*`1 ^ 0`

- Bitwise inclusive OR: Given
*operand1*|*operand2*, which must be of character or an integer type, bitwise inclusive OR their corresponding bits and return the result. A result bit is set to 1 when either (or both) of the operands' corresponding bits is 1. Otherwise, the result bit is set to 0. Example:`1 | 0`

Listing 3 presents the source code to a `BitwiseOp`

application that lets you play with the bitwise operators.

#### Listing 3. BitwiseOp.java

```
class BitwiseOp
{
public static void main(String[] args)
{
short x = 0B0011010101110010;
short y = 0B0110101011101011;
System.out.println(x & y);
System.out.println(~x);
System.out.println(x ^ y);
System.out.println(x | y);
}
}
```

Listing 3's `main()`

method initializes a pair of short integer variables and subsequently uses the bitwise operators to produce new values by operating on their bits; these values are then output.

Compile Listing 3 (`javac BitwiseOp.java`

) and run the application (`java BitwiseOp`

). You should observe the following output:

```
8290
-13683
24473
32763
```

Because it's difficult to see each operator's effect on its operands, I present the binary equivalent of the previous operators below -- you'll understand why each binary number is 32 bits long instead of 16 when I discuss type conversions:

```
00000000000000000010000001100010
11111111111111111100101010001101
00000000000000000101111110011001
00000000000000000111111111111011
```

## Cast operator

The *cast operator* -- `(`

-- attempts to convert the type of its operand to *type*)* type*. You can convert from one primitive type to another primitive type or from one reference type to another reference type, but not from primitive type to reference type or vice-versa.

For example, to convert double precision floating-point value 1.0 to its 32-bit integer equivalent, specify `(int) 1.0`

. Also, to convert `circle`

(of type `Circle`

) to its `Shape`

supertype, specify `(Shape) circle`

. There will be more to learn about cast when we get into type conversions later in this article. The cast operator is also important for inheritance, which is a subject for another day.

## Conditional operators

The *conditional operators* conditionally evaluate *Boolean expressions*, which are expressions that have Boolean type and evaluate to true or false. These operators include conditional (`?:`

), conditional AND (`&&`

), and conditional OR (`||`

); and are formally defined below:

- Conditional: Given

, where*operand1*?*operand2*:*operand3*must be of Boolean type, return`operand1`

when`operand2`

is true or`operand1`

when`operand3`

is false. The types of`operand1`

and`operand2`

must agree. Example:`operand3`

`boolean status = true; int statusInt = (status) ? 1 : 0;`

- Conditional AND: Given

, where each operand must be of Boolean type, return true when both operands are true. Otherwise, return false. When*operand1*&&*operand2*is false,`operand1`

isn't evaluated because the entire expression will be false anyway. This is known as`operand2`

*short-circuiting*. Example:`true && false`

- Conditional OR: Given

, where each operand must be of Boolean type, return true when at least one operand is true. Otherwise, return false. When*operand1*||*operand2*is true,`operand1`

isn't evaluated because the entire expression will be true anyway. This is known as`operand2`

*short-circuiting*. Example:`true || false`

Listing 4 presents the source code to a `CondOp`

application that lets you play with the conditional operators.

#### Listing 4. CondOp.java

```
class CondOp
{
public static void main(String[] args)
{
boolean sold_more_than_100_units = true;
int bonus_dollars = (sold_more_than_100_units) ? 50 : 0;
System.out.println(bonus_dollars);
System.out.println(true && true);
System.out.println(true && false);
System.out.println(false && true);
System.out.println(false && false);
System.out.println(true || true);
System.out.println(true || false);
System.out.println(false || true);
System.out.println(false || false);
int x = 0;
boolean status = true && ++x == 0;
System.out.println(x);
status = false && ++x == 0;
System.out.println(x);
status = true || ++x == 0;
System.out.println(x);
status = false || ++x == 0;
System.out.println(x);
}
}
```

Because of short-circuiting, `&&`

and `||`

won't always evaluate their right operands. Although short-circuiting can improve performance somewhat because only one expression is evaluated, it can also be a source of bugs when a *side-effect* (code that is executed as a byproduct of expression evaluation) is involved.

Listing 4 presents side effects in which variable `x`

is preincremented. Preincrement occurs for expressions `true && ++x == 0`

and `false || ++x == 0`

. However, this variable isn't incremented for expressions `false && ++x == 0`

and `true || ++x == 0`

because there's no need to evaluate the right operands in these contexts.

Compile Listing 4 (`javac CondOp.java`

) and run the application (`java CondOp`

). You should observe the following output:

```
50
true
false
false
false
true
true
true
false
1
1
1
2
```

## Equality operators

The *equality operators* compare their operands to determine if they are equal or unequal. These operators include equality (`==`

) and inequality (`!=`

). The former operator returns true when both operands are equal; the latter operator returns true when both operands are unequal. These operators are formally defined below:

- Equality: Given

, where both operands must be comparable (you cannot compare an integer with a Boolean value, for example), compare both operands for equality. Return true when these operands are equal. Otherwise, return false. Example:*operand1*==*operand2*`'A' == 'a'`

- Inequality: Given

, where both operands must be comparable (you cannot compare a floating-point value with a string literal, for example), compare both operands for inequality. Return true when these operands are not equal. Otherwise, return false. Example:*operand1*!=*operand2*`'A' != 'a'`

You will need to be careful when comparing floating-point values because not all floating-point values can be represented accurately in memory. For example, 0.1 cannot be represented accurately. For this reason, some expressions involving these operands will return false when you think they should return true.

These operators can be used to compare primitive values or object references. However, you cannot compare a primitive value with an object reference. For example, you might have two `Employee`

objects whose references are stored in `e1`

and `e2`

. Expression `e1 == e2`

returns true only when variables `e1`

and `e2`

refer to the same `Employee`

object.

String comparison is a little unusual. You can attempt to compare two string literals, as in `"A" == "B"`

. However, because string literals are really `String`

objects, you are really comparing references to these objects and not comparing their characters. As a result, true returns only when both operands reference the same `String`

object.

Listing 5 presents the source code to an `EqualityOp`

application that lets you play with the equality operators.

#### Listing 5. EqualityOp.java

```
class EqualityOp
{
public static void main(String[] args)
{
int x = 0;
System.out.println(x == 0);
System.out.println(x != 0);
double d = 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1;
System.out.println(d);
System.out.println(d == 0.9);
System.out.println("A" == "A");
System.out.println("A" == "B");
System.out.println("AB" == "A" + "B");
String s = "B";
System.out.println("AB" == "A" + s);
}
}
```

Compile Listing 5 (`javac EqualityOp.java`

) and run the application (`java EqualityOp`

). You should observe the following output:

```
true
false
0.8999999999999999
false
true
false
true
false
```

The first two output lines are unsurprising given that `x`

contains 0. The next two output lines reveal that 0.1 cannot be stored exactly in memory: summing nine instances of 0.1 doesn't equal nine. For this reason, it's unwise to control an iteration's duration via an equality expression involving floating-point values. I'll say more about this in the next article.

The remaining output lines prove that Java creates exactly one `String`

object for each unique string literal. For example, there is one `String`

object for `"A"`

, another `String`

object for `"B"`

, and a third `String`

object for `"AB"`

. In `"A" == "A"`

, both `"A"`

literals refer to the same `"A"`

object, so true is the result. However, in `"A" == "B"`

, `"A"`

and `"B"`

refer to the `"A"`

object and to a `"B"`

object. Because of different references, false is the result. Next, in `"AB" == "A" + "B"`

, the string concatenation produces a reference to the same `"AB"`

object as is referenced by literal `"AB"`

, so true is the result. Finally, `String s = "B";`

creates a new `String`

object that contains `B`

and whose reference is assigned to `s`

. This object (and reference) is separate from the object (and reference) associated with `"B"`

. As a result, in `"AB" == "A" + s`

, we end up with the `"AB"`

`String`

object's reference being compared with a reference to a different `String`

object containing `AB`

, and this comparison results in false as the result. I will have more to say about string comparison when I explore the `String`

class in a future article.

## Logical operators

The *logical operators* are the Boolean equivalent of the bitwise operators. Instead of working on the bit values of integral operands, they work on their Boolean operands. These operators include logical AND (`&`

), logical complement (`!`

), logical exclusive OR (`^`

), and logical inclusive OR (`|`

); and are formally defined below:

- Logical AND: Given

, where each operand must be of Boolean type, return true when both operands are true. Otherwise, return false. In contrast to conditional AND, logical AND doesn't perform short-circuiting. Example:*operand1*&*operand2*`true & false`

- Logical complement: Given
`!`

, where*operand*must be of Boolean type, flip`operand`

's value (true to false or false to true) and return the result. Example:`operand`

`!false`

- Logical exclusive OR: Given

, where each operand must be of Boolean type, return true when one operand is true and the other operand is false. Otherwise, return false. Example:*operand1*^*operand2*`true ^ false`

- Logical inclusive OR: Given

, where each operand must be of Boolean type, return true when at least one operand is true. Otherwise, return false. In contrast to conditional OR, logical inclusive OR doesn't perform short-circuiting. Example:*operand1*|*operand2*`true | false`

Listing 6 presents the source code to a `LogicalOp`

application that lets you play with the logical operators.

#### Listing 6. LogicalOp.java

```
class LogicalOp
{
public static void main(String[] args)
{
int x = 0;
System.out.println(false & ++x == 0);
System.out.println(x);
System.out.println(!false);
System.out.println(true ^ true);
System.out.println(true ^ false);
System.out.println(true | ++x == 0);
System.out.println(x);
}
}
```

Compile Listing 6 (`javac LogicalOp.java`

) and run the application (`java LogicalOp`

). You should observe the following output:

```
false
1
true
false
true
true
2
```

## Member access operator

The* member access operator* (`.`

) accesses class or object members (e.g., methods). For example, assuming that `name`

is of type `String`

and is initialized to a string, `name.length()`

returns the length of that string. Essentially, this operator is accessing the `length()`

member of the `name`

object.

Java regards arrays as special objects with a single `length`

member whose value (an `int`

) denotes the number of elements in the array. For example, `grades.length`

returns the length of (the number of elements in) the array that `grades`

references. In other words, this operator is accessing the `length`

member of the `grades`

array.

I'll have more to say about classes, objects, class/object members, and arrays in future articles.

## Method call operator

The *method call operator* -- `()`

-- signifies that a method is being called and identifies the number, order, and types of expressions being passed to the method. For example, in `System.out.println("Java");`

, `()`

signifies that method `println`

, which is a member of the `System`

class's `out`

member, is being called with one argument: `"Java"`

.

## Multiplicative operators

The *multiplicative operators* greatly increase or decrease a numeric value through the equivalent of multiple additions or subtractions (e.g., 4 times 3 is equivalent to adding three 4s, and 12 divided by 3 is equivalent to repeatedly subtracting 3 from 12 until the remainder is less than 3 (0, in this example). These operators include multiplication (`*`

), division (`/`

), and remainder (`%`

); and are formally defined below:

- Multiplication: Given

, where each operand must be of character or numeric type, multiply*operand1***operand2*by`operand1`

and return the product. Example:`operand2`

`4 * 3`

- Division: Given

, where each operand must be of character or numeric type, divide*operand1*/*operand2*by`operand1`

and return the quotient. Example:`operand2`

`12 / 3`

- Remainder: Given

, where each operand must be of character or numeric type, divide*operand1*%*operand2*by`operand1`

and return the remainder. Also known as the`operand2`

*modulus operator*. Example:`12 % 3`

The multiplication operator can generate a product that overflows the limits of the result type, and doesn't detect and report an overflow. If you need to detect an overflow, you'll want to work with the `Math`

class's `multiplyExact()`

methods.

Listing 7 presents the source code to a `MulOp`

application that lets you play with the multiplicative operators.

#### Listing 7. MulOp.java

```
class MulOp
{
public static void main(String[] args)
{
System.out.println(64.0 * 3.0);
System.out.println(64 / 3);
System.out.println(64 % 3);
System.out.println(10.0 / 0.0);
System.out.println(-10.0 / 0.0);
System.out.println(0.0 / 0.0);
System.out.println(10 / 0);
}
}
```

Listing 7 is fairly straightforward until you encounter the division-by-zero expressions. Dividing a numeric value by 0 (via the division or remainder operator) results in interesting behavior:

- Dividing a floating-point/double precision floating-point value by 0 causes the operator to return one of the following special values: +infinity (the dividend is positive), -infinity (the dividend is negative), or NaN -- Not a Number -- (the dividend and divisor are both 0).
- Dividing an integer value by integer 0 causes the operator to throw an
`ArithmeticException`

object. We'll explore exceptions in a future Java 101 article.

Compile Listing 7 (`javac MulOp.java`

) and run the application (`java MulOp`

). You should observe the following output:

```
192.0
21
1
Infinity
-Infinity
NaN
Exception in thread "main" java.lang.ArithmeticException: / by zero
at MulOp.main(MulOp.java:11)
```

## Object creation operator

The *object creation operator* (`new`

) is used to create an object from a class or to create an array. This operator is formally defined below:

- Given
`new`

, allocate memory for object and call constructor specified as*identifier*(*argument list*)

. Example:*identifier*(*argument list*)`new String("ABC")`

- Given
`new`

, allocate a one-dimensional array of values. Example:*identifier*[*integer size*]`new int[5]`

To create a two-dimensional array, the syntax changes to

(e.g.,*identifier*[*integer size*][*integer size*]`new double[5][5]`

). For additional dimensions, append an`[`

per dimension.*integer size*]

Object and array creation is a rich topic, so we'll dive into it another time.

## Relational operators

The *relational operators* impose an ordering on their operands by determining which operand is greater, lesser, and so on. These operators include greater than (`>`

), greater than or equal to (`>=`

), less than (`<`

), and less than or equal to (`<=`

). Type checking (`instanceof`

) is also considered to be relational. These operators are formally defined below:

- Greater than: Given

, where each operand must be of character or numeric type, return true when*operand1*>*operand2*is greater than`operand1`

. Otherwise, return false. Example:`operand2`

`65.3 > 22.5`

- Greater than or equal to: Given

, where each operand must be of character or numeric type, return true when*operand1*>=*operand2*is greater than or equal to`operand1`

. Otherwise, return false. Example:`operand2`

`0 >= 0`

- Less than: Given

, where each operand must be of character or numeric type, return true when*operand1*<*operand2*is less than`operand1`

. Otherwise, return false. Example:`operand2`

`x < 15`

- Less than or equal to: Given

, where each operand must be of character or numeric type, return true when*operand1*<=*operand2*is less than or equal to`operand1`

. Otherwise, return false. Example:`operand2`

`0 <= 0`

- Type checking: Given

, where*operand1*instanceof*operand2*is an object and`operand1`

is a class (or other user-defined type), return true when`operand2`

is an instance of`operand1`

. Otherwise, return false.`operand2`

Listing 8 presents the source code to a `RelOp`

application that lets you play with the relational operators.

#### Listing 8. RelOp.java

```
class RelOp
{
public static void main(String[] args)
{
int x = 10;
System.out.println(x > 10);
System.out.println(x >= 10);
System.out.println(x < 10);
System.out.println(x <= 10);
System.out.println("A" instanceof String);
}
}
```

Compile Listing 8 (`javac RelOp.java`

) and run the application (`java RelOp`

). You should observe the following output:

```
false
true
false
true
true
```

The final output line is interesting because it proves that a string literal (e.g., `"A"`

) is in fact a `String`

object.

## Shift operators

The *shift operators* let you shift an integral value left or right by a specific number of bit positions. These operators include left shift (`<<`

), signed right shift (`>>`

), and unsigned right shift (`>>>`

); and are formally defined below:

- Left shift: Given

, where each operand must be of character or integer type, shift*operand1*<<*operand2*'s binary representation left by the number of bits that`operand1`

specifies. For each shift, a 0 is shifted into the rightmost bit and the leftmost bit is discarded. Only the five low-order bits of`operand2`

are used when shifting a 32-bit integer (to prevent shifting more than the number of bits in a 32-bit integer). Only the six low-order bits of`operand2`

are used when shifting a 64-bit integer (to prevent shifting more than the number of bits in a 64-bit integer). The shift preserves negative values. Furthermore, it's equivalent to (but faster than) multiplying by a multiple of 2. Example:`operand2`

`3 << 2`

- Signed right shift: Given

, where each operand must be of character or integer type, shift*operand1*>>*operand2*'s binary representation right by the number of bits that`operand1`

specifies. For each shift, a copy of the sign bit (the leftmost bit) is shifted to the right and the rightmost bit is discarded. Only the five low-order bits of`operand2`

are used when shifting a 32-bit integer (to prevent shifting more than the number of bits in a 32-bit integer). Only the six low-order bits of`operand2`

are used when shifting a 64-bit integer (to prevent shifting more than the number of bits in a 64-bit integer). The shift preserves negative values. Furthermore, it's equivalent to (but faster than) dividing by a multiple of 2. Example:`operand2`

`-5 >> 2`

- Unsigned right shift: Given

, where each operand must be of character or integer type, shift*operand1*>>>*operand2*'s binary representation right by the number of bits that`operand1`

specifies. For each shift, a zero is shifted into the leftmost bit and the rightmost bit is discarded. Only the five low-order bits of`operand2`

are used when shifting a 32-bit integer (to prevent shifting more than the number of bits in a 32-bit integer). Only the six low-order bits of`operand2`

are used when shifting a 64-bit integer (to prevent shifting more than the number of bits in a 64-bit integer). The shift doesn't preserve negative values. Furthermore, it's equivalent to (but faster than) dividing by a multiple of 2. Example:`operand2`

`42 >>> 2`

Listing 9 presents the source code to a `ShiftOp`

application that lets you play with the shift operators.

#### Listing 9. ShiftOp.java

```
class ShiftOp
{
public static void main(String[] args)
{
System.out.println(1 << 8);
System.out.println(8 >> 2);
System.out.println(-1 >> 1);
System.out.println(-1 >>> 1);
}
}
```

Compile Listing 9 (`javac ShiftOp.java`

) and run the application (`java ShiftOp`

). You should observe the following output:

```
256
2
-1
2147483647
```

The output reveals that bit shifting is equivalent to multiplying or dividing by multiples of 2 (but is faster). The first output line is equivalent to the value derived from `2 * 2 * 2 * 2 * 2 * 2 * 2 * 2`

and the second output line is equivalent to the value derived from `8 / 4`

. The final two output lines show the difference between preserving and not preserving the sign bit where negative values are concerned.

## Unary minus/plus operators

The final operators that Java supports are *unary minus* (`-`

) and *unary plus* (`+`

). Unary minus returns the negative of its operand (e.g., `-8`

returns -8 and `--8`

returns 8), whereas unary plus returns its operand unchanged (e.g., `+8`

returns 8 and `+-8`

returns -8). Unary plus is not commonly used, but is included in Java's set of operators for completeness.

## Precedence and associativity

I previously mentioned that Java's rules of *precedence* (priority in order) dictate the order in which compound expressions are evaluated. For the common arithmetic operators (e.g., addition and multiplication), Java follows the established precedence conventions (e.g., multiplication first and then addition). For other operators, order of evaluation isn't as clear. For example, how does Java evaluate `6 > 3 * 2`

? Does the comparison precede multiplication or vice-versa?

The following list shows you the precedence of Java's operators. Operators closer to the top have higher precedence than operators lower down. In other words, operators higher up in the list are performed first. Operators that have the same precedence are listed on the same line. When the Java compiler encounters multiple operators with the same precedence in the same compound expression, it generates code to perform the operations according to their associativity:

- Array index, member access, method call, postdecrement, postincrement
- Bitwise complement, cast, logical complement, object creation, predecrement, preincrement, unary minus, unary plus
- Division, multiplication, remainder
- Addition, string concatenation, subtraction
- Left shift, signed right shift, unsigned right shift
- Greater than, greater than or equal to, less than, less than or equal to, type checking
- Equality, inequality
- Bitwise AND, logical AND
- Bitwise exclusive OR, logical exclusive OR
- Bitwise inclusive OR, logical inclusive OR
- Conditional AND
- Conditional OR
- Conditional
- Assignment, compound assignment

You won't always want to follow this order. For example, you might want to perform addition before multiplication. Java lets you violate precedence by placing subexpressions between round brackets (parentheses). A parenthesized subexpression is evaluated first. Parentheses can be nested, in which a parenthesized subexpression can be located within a parenthesized subexpression. In this case, the innermost parenthesized subexpression is evaluated first.

During evaluation, operators with the same precedence level (e.g., addition and subtraction) are processed according to their *associativity* (how operators having the same precedence are grouped when parentheses are absent). For example, `10 * 4 / 2`

is evaluated as if it was `(10 * 4) / 2`

because `*`

and `/`

are left-to-right associative operators. In contrast, `a = b = c = 50;`

is evaluated as if it was `a = (b = (c = 50));`

(`50`

is assigned to `c`

, `c`

's value is assigned to `b`

, and `b`

's value is assigned to `a`

-- all three variables contain 50) because `=`

is a right-to-left associative operator.

Most of Java's operators are left-to-right associative. Right-to-left associative operators include assignment, bitwise complement, cast, compound assignment, conditional, logical complement, object creation, predecrement, preincrement, unary minus, and unary plus.

I've created a small application for playing with precedence and associativity. Listing 10 presents its source code.

#### Listing 10. PA.java

```
class PA
{
public static void main(String[] args)
{
System.out.println(10 * 4 + 2);
System.out.println(10 * (4 + 2));
int a, b, c;
a = b = c = 50;
System.out.println(a);
System.out.println(b);
System.out.println(c);
}
}
```

Compile Listing 10 (`javac PA.java`

) and run the application (`java PA`

). You should observe the following output:

```
42
60
50
50
50
```

In Listing 10, suppose I specified `(a = b) = c = 50;`

instead of `a = b = c = 50;`

because I want `a = b`

to be evaluated first. How would the compiler respond -- and why?

## Converting between types

My previous binary and ternary operator examples presented operands having the same type (e.g., each of `6 * 5`

's operands is an `int`

). In many cases, operands will not have the same type, and the Java compiler will need to generate bytecode that converts an operand from one type to another before generating bytecode that performs the operation. For example, when confronted by `5.1 + 8`

, the compiler generates bytecode to convert 32-bit integer `8`

to its double precision floating-point equivalent followed by bytecode to add these double precision values. (In the example, the compiler would generate an `i2d`

instruction to convert from `int`

to `double`

and then a `dadd`

instruction to add the two `double`

s.)

How does the compiler know which operand to convert? For primitive-type operands, its choice is based on the following widening rules, which essentially convert from a type with a narrower set of values to a type with a wider set of values:

- Convert byte integer to short integer, integer, long integer, floating-point, or double precision floating-point.
- Convert short integer to integer, long integer, floating-point, or double precision floating-point.
- Convert character to integer, long integer, floating-point, or double precision floating-point.
- Convert integer to long integer, floating-point, or double precision floating-point.
- Convert long integer to floating-point or double precision floating-point.
- Convert floating-point to double precision floating-point.

Regarding expression `5.1 + 8`

, we can see that the compiler chooses to convert `8`

to a `double`

based on the rule for converting an integer to double precision floating-point. If it converted `5.1`

to an `int`

, which is a narrower type, information would be lost because the fractional part would be effectively truncated. Therefore, the compiler always chooses to widen a type so information isn't lost.

These rules also help to explain why, in `BitwiseOp.java`

, the binary values resulting from expressions such as `System.out.println(~x);`

were 32 bits long instead of 16 bits long. The compiler converts the short integer in `x`

to a 32-bit integer value before performing bitwise complement, via `iconst_m1`

and `ixor`

instructions -- exclusive OR the 32-bit integer value with 32-bit integer -1 and produce a 32-bit integer result. The Java virtual machine provides no `sconst_m1`

and `sxor`

instructions for performing bitwise complement on short integers. Byte integers and short integers are always widened to 32-bit integers.

Earlier, I mentioned that you would discover why `'C' - 'A'`

in (`grades['C' - 'A']`

) produces an integer index. Character literals `'C'`

and `'A'`

are represented in memory by their Unicode values, which are unsigned 16-bit integers. When it encounters this expression, the Java compiler generates an `iconst_2`

instruction, which is `int`

value 2. In this case, no subtraction is performed because of optimization. However, if I replaced `'C' - 'A'`

with `'C' - base`

, where `base`

is a `char`

variable initialized to `'A'`

, the compiler would generate the following bytecode:

```
bipush 65 ; Push 8-bit Unicode value for A, which is sign-extended to 32-bit int, onto stack.
istore_1 ; Pop this 32-bit value into a special int variable.
...
bipush 67 ; Push 8-bit Unicode value for C, which is sign-extended to 32-bit int, onto stack.
iload_1 ; Push 32-bit Unicode value for A onto stack.
isub ; Subtract 65 (A) from 67 (C). Push 32-bit result onto stack.
```

The `bi`

in `bipush`

stands for the byte integer type; the `i`

in `istore_1`

, `iload_1`

, and `isub`

stands for the 32-bit integer type. The compiler has converted the expression into an `int`

value. It makes sense to do so because of the close relationship between character literals (really, unsigned Unicode integers) and Java's signed integers.

In addition to the previous widening rules, Java provides a special widening rule for use with `String`

objects (e.g., string literals). When either operand of the string concatenation operator is not a string, that operand is converted to a string before the concatenation operation is performed. For example, when confronted with `"X" + 3`

, the compiler generates code to convert `3`

to `"3"`

before performing the concatenation.

Sometimes, you'll need to deliberately narrow a type where information may be lost. For example, you're drawing a mathematical curve with floating-point coordinates (for accuracy). Because the screen's pixels use integer coordinates, you must convert from floating-point to integer before you can plot a pixel. Java lets you narrow a type via a cast operator. Cast operators are available to perform the following primitive-type conversions:

- Convert from byte integer to character.
- Convert from short integer to byte integer or character.
- Convert from character to byte integer or short integer.
- Convert from integer to byte integer, short integer, or character.
- Convert from long integer to byte integer, short integer, character, or integer.
- Convert from floating-point to byte integer, short integer, character, integer, or long integer.
- Convert from double precision floating-point to byte integer, short integer, character, integer, long integer, or floating-point.

For example, the `(float)`

cast in `float circumference = (float) 3.14159 * 10 * 10;`

is necessary to convert from double precision floating-point to floating-point.

A cast operator isn't always necessary for the above primitive-type conversions. For example, consider conversion from 32-bit integer to 8-bit byte integer. You don't need to supply a cast operation when assigning a 32-bit integer literal that ranges from -128 to 127 to a variable of byte integer type. For example, you could specify `byte b = 100;`

and the compiler wouldn't complain because no information is lost. (This is why I was previously able to specify `short x = 0B0011010101110010;`

, where the binary literal is of 32-bit integer type, without requiring a `(short)`

cast operator, as in `short x = (short) 0B0011010101110010;`

.) However, if you specified `int i = 2; byte b = i;`

, the compiler would complain because `i`

could contain a value outside the valid range of integers that can be assigned to a byte integer variable.

A short application should help to clarify all of this theory. Check out Listing 11's `Convert`

source code.

#### Listing 11. Convert.java

```
class Convert
{
public static void main(String[] args)
{
float f = 1000;
System.out.println("f = " + f);
long l = 5000;
System.out.println("l = " + l);
System.out.println("'C' - 'A' = " + ('C' - 'A'));
char base = 'A';
System.out.println("'C' - base = " + ('C' - base));
int i = (int) 2.5;
System.out.println(i);
byte b = 25;
System.out.println(b);
b = (byte) 130;
System.out.println(b);
i = 2;
b = (byte) i;
System.out.println(b);
}
}
```

Listing 11 reveals a good way to identify variables when outputting their values (for debugging or another purpose). Simply concatenate a variable (of arbitrary type) to a string label, as in `"f = " + f`

.

Compile Listing 11 (`javac Convert.java`

) and run the application (`java Convert`

). You should observe the following output:

```
f = 1000.0
l = 5000
'C' - 'A' = 2
'C' - base = 2
2
25
-126
2
```

## In conclusion

Java's support for expressions is extensive and there is a lot of theory to grasp. I encourage you re-read this article while trying out the sample applications and modifying them to reinforce your understanding of expressions. This knowledge will come in handy when you encounter statements in the next article, which wraps up this three-part mini-series on Java's fundamental language features.