Operators
The countChars method uses several operators including
= , != , ++ , and + , which are
highlighted in this listing:
import java.io.*;
public class Count {
public static void countChars(Reader in) throws IOException
{
int count = 0;
while (in.read() != -1)
count++;
System.out.println("Counted " + count + " chars.");
}
// ... main method omitted ...
}
Operators perform some function on either one or two operands or three
operands. Operators that require one operand are called unary operators.
For example, ++ is a unary operator that increments the value
of its operand by 1. Operators that require two operands are binary
operators. For example, = is a binary operator that
assigns the value from its right-hand operand to its left-hand operand. And
finally ternary operators are those that require three operands.
The Java language has one ternary operator, ?: , which is a
short-hand if -else statement.
Java's unary operators can use either prefix or postfix notation. Prefix
notation means that the operator appears before its operand:
operator op
Postfix notation means that the operator appears after its
operand:
op operator
All of Java's binary operators use infix notation, which means that the
operator appears between its operands:
op1 operator op2
Java's only ternary operator is also infix; each component of the
operator appears between operands:
expr ? op1 : op2
In addition to performing the operation, an operator also returns a
value. The value and its type depends on the operator and the type of its
operands. For example, the arithmetic operators, which perform basic
arithmetic operations such as addition and subtraction, return numbers-the
result of the arithmetic operation. The data type returned by the arithmetic
operators depends on the type of its operands: If you add two integers, you
get an integer back. An operation is said to evaluate to its
result.
It's useful to divide Java's operators into these categories: arithmetic,
relational and conditional, bitwise and logical, and assignment. These are
discussed in the following sections.
Arithmetic Operators
The Java language supports various arithmetic operators for all
floating-point and integer numbers. These include +
(addition), - (subtraction), * (multiplication),
/ (division), and % (modulo). For example, you
can use this Java code to add two numbers:
addThis + toThis
Or you can use the following Java code to compute the remainder that
results from dividing divideThis by byThis :
divideThis % byThis
This table summarizes Java's binary arithmetic operations:
Operator |
Use |
Description |
+ |
op1 + op2 |
Adds op1 and op2 |
- |
op1 - op2 |
Subtracts op2 from op1 |
* |
op1 * op2 |
Multiplies op1 by op2 |
/ |
op1 / op2 |
Divides op1 by op2 |
% |
op1 % op2 |
Computes the remainder of dividing op1 by op2
|
Note: The Java language extends the definition of
the + operator to include string concatenation. The
countChars method uses + to concatenate "Counted
", the value of count , and " chars. ",
as shown here:
System.out.println("Counted " + count + " chars.");
This operation automatically coerces the value count to
a String . You'll see more about this in
Arrays and Strings.
The + and - operators have unary versions
that perform the following operations:
Operator |
Use |
Description |
+ |
+op |
Promotes + to int if it's a byte ,
short , or char |
- |
-op |
Arithmetically negates op |
There also are two short cut arithmetic operators, ++
which increments its operand by 1, and -- which decrements
its operand by 1. The countChars method uses ++
to increment the count variable each time it reads a
character from the input source with this statement:
count++;
Note that the ++ operator appears after its operand in
this example. This is the postfix version of the operator.
++ also has a prefix version in which ++
appears before its operand. Both the prefix and postfix versions of this
operator increment the operand by 1. So why are there two different
versions? Because each version evaluates a different value: op++
evaluates to the value of the operand before the increment
operation, and ++op evaluates the value of the operand
after the increment operation.
In the countChars method, suppose that count
is say, 5, before the following statement is executed:
count++;
After the statement is executed the value of count is 6.
No surprises there. However, the statement count++ evaluates
to 5. In the same scenario the prefix version of ++ would
also set count to 6. However the statement ++count
does not evaluate to 5 like the postfix version of ++ does;
rather, it evaluates to 6:
++count;
This difference is unimportant in countChars but is
critical in situations where the value of the statement is used in the
middle of a more complex computation, for flow control, or for something
else. For example, the following loop will execute one less time if you
change count++ to ++count :
do {
. . .
} while (count++ < 6);
Similarly, -- also has prefix and postfix versions, which
function in the same way as ++ . The operations of these
operators are summarized in the following table:
Operator |
Use |
Description |
++ |
op++ |
Increments op by 1; evaluates to value before
incrementing |
++ |
++op |
Increments op by 1; evaluates to value after
incrementing |
-- |
op-- |
Decrements op by 1; evaluates to value before
decrementing |
-- |
--op |
Decrements op by 1; evaluates to value after
decrementing |
Relational and Conditional Operators
A relational operator compares two values and determines the
relationship between them. For example, != returns true
if the two operands are unequal. The countChars method uses
!= to determine whether the value returned by in.read
is not equal to -1 . This table summarizes Java's relational
operators:
Operator |
Use |
Return true if |
> |
op1 > op2 |
op1 is greater than op2 |
>= |
op1 >= op2 |
op1 is greater than or equal to op2 |
< |
op1 < op2 |
op1 is less than op2 |
<= |
op1 <= op2 |
op1 is less than or equal to op2 |
== |
op1 == op2 |
op1 and op2 are equal |
!= |
op1 != op2 |
op1 and op2 are not equal |
Relational operators often are used with the conditional operators to
construct more complex decision-making expressions. One such operator is
&& , which performs the boolean and operation. For
example, you can use two different relational operators along with
&& to determine if both relationships are true. The following line
of code uses this technique to determine if an array index is between two
boundaries. It determines if the index is both greater than 0 and less
than NUM_ENTRIES (which is a previously defined constant
value):
0 < index && index < NUM_ENTRIES
Note that in some instances, the second operand to a conditional
operator may not be evaluated. Consider this statement:
((count > NUM_ENTRIES) && (in.read() != -1))
If count is less than NUM_ENTRIES , the
left-hand operand for && evaluates to false. The &&
operator will return true only if both operands are true. So in
this situation, the return value of && can be determined
without evaluating the right-hand operand. In such a case, Java will not
evaluate the right-hand operand. Thus, in.read won't get
called and a character will not be read from standard input.
The operator & is similar to && if both of
its operands are of boolean type. However, & always evaluates
both of its operands and returns true if both are true .
Likewise, | is similar to || if both of its
operands are boolean. This operator always evalutes both of its operands
and returns false if they are both false .
Java supports five binary conditional operators, shown in the following
table:
Operator |
Use |
Returns true if |
&& |
op1 && op2 |
op1 and op2 are both true ,
conditionally evaluates op2 |
|| |
op1 || op2 |
either op1 or op2 is true ,
conditionally evaluates op2 |
! |
! op |
op is false |
& |
op1 & op2 |
op1 and op2 are both true ,
always evaluates op1 and op2 |
| |
op1 | op2 |
either op1 or op2 is true ,
always evaluates op1 and op2 |
In addition, Java supports one other conditional operator--the ?:
operator. This operator is a ternary operator and is basically short-hand
for an if -else statement:
expression ? op1 : op2
The ?: operator evaluates expression and
returns op1 if it's true and op2 if it's false.
Bitwise Operators
A bitwise operator allows you to perform bit manipulation on data. This
table summarizes the bitwise and logical operators available in the Java
language.
Operator |
Use |
Operation |
>> |
op1 >> op2 |
shift bits of op1 right by distance op2
|
<< |
op1 << op2 |
shift bits of op1 left by distance op2
|
>>> |
op1 >>> op2 |
shift bits of op1 right by distance op2
(unsigned) |
& |
op1 & op2 |
bitwise and |
| |
op1 | op2 |
bitwise or |
^ |
op1 ^ op2 |
bitwise xor |
~ |
~op2 |
bitwise complement |
The three shift operators simply shift the bits of the left-hand
operand over by the number of positions indicated by the right-hand
operand. The shift occurs in the direction indicated by the operator
itself. For example, the following statement, shifts the bits of the
integer 13 to the right by one position:
13 >> 1;
The binary representation of the number 13 is 1101. The result of the
shift operation is 1101 shifted to the right by one position--110 or 6 in
decimal. Note that the bit farthest to the right falls off the end into
the bit bucket. A right shift of 1 bit is equivalent to, but more
efficient than, dividing the left-hand operand by 2. A left shift of 1 bit
is equivalent to multiplying by 2.
op1 |
op2 |
Result |
0 |
0 |
0 |
0 |
1 |
0 |
1 |
0 |
0 |
1 |
1 |
1 |
The bitwise and operation performs the "and" function on each parallel
pair of bits in each operand. The "and" function sets the resulting bit to
1 if both operands are 1.
Suppose you were to "and" the values 12 and 13:
12 & 13
The result of this operation is 12. Why? Well, the binary
representation of 12 is 1100, and the binary representation of 13 is 1101.
The "and" function sets the resulting bit to 1 if both operand bits are 1,
otherwise, the resulting bit is 0. So, if you line up the two operands and
perform the "and" function, you can see that the two high-order bits (the
two bits farthest to the left of each number) of each operand are 1. Thus
the resulting bit in the result is also 1. The low-order bits evaluate to
0 because either one or both bits in the operands are 0:
1101
& 1100
------
1100
The | operator performs the inclusive or operation and
^ performs the exclusive or operation. Inclusive or means
that if either of the two bits are 1 then the result is 1. The following
table shows the results of your inclusive or operations:
op1 |
op2 |
Result |
0 |
0 |
0 |
0 |
1 |
1 |
1 |
0 |
1 |
1 |
1 |
1 |
Exclusive or means that if the two operand bits are different the
result is 1, otherwise the result is 0. The following table shows the
results of your exclusive or operation.
op1 |
op2 |
Result |
0 |
0 |
0 |
0 |
1 |
1 |
1 |
0 |
1 |
1 |
1 |
0 |
And finally, the complement operator inverts the value of each bit of
the operand: if the operand bit is 1 the result is 0 and if the operand
bit is 0 the result is 1.
Among other things, bitwise manipulations are useful for managing sets
of boolean flags. Suppose for example, that you had several boolean flags
in your program that indicated the state of various components in your
program: is it visible, is it draggable, and so on. Rather than define a
separate boolean variable to hold each flag, you could define a single
variable, flags , for all of them. Each bit within flags
would represent the current state of one of the flags. You would then use
bit manipulations to set and get each flag.
First, set up constants that indicated the various flags for your
program. These flags should each be a different power of two to ensure
that the "on" bit didn't overlap with another flag. Define a variable,
flags , whose bits would be set according to the current state
of each flag. The following code sample initializes flags to
0 which means that all flags are false (none of the bits are set).
final int VISIBLE = 1;
final int DRAGGABLE = 2;
final int SELECTABLE = 4;
final int EDITABLE = 8;
int flags = 0;
To set the "visible" flag when something became visible you would use
this statement:
flags = flags | VISIBLE;
To test for visibility, you could then write:
flags & VISIBLE
Assignment Operators
You use the basic assignment operator, = , to assign one
value to another. The countChars method uses =
to initialize count with this statement:
int count = 0;
Java also provides several short cut assignment operators that allow
you to perform an arithmetic, logical, or bitwise operation and an
assignment operation all with one operator. Suppose you wanted to add a
number to a variable and assign the result back into the variable, like
this:
i = i + 2;
You can shorten this statement using the short cut operator += .
i += 2;
The two previous lines of code are equivalent.
This table lists the shortcut assignment operators and their lengthy
equivalents:
Operator |
Use |
Equivalent to |
+= |
op1 += op2 |
op1 = op1 + op2 |
-= |
op1 -= op2 |
op1 = op1 - op2 |
*= |
op1 *= op2 |
op1 = op1 * op2 |
/= |
op1 /= op2 |
op1 = op1 / op2 |
%= |
op1 %= op2 |
op1 = op1 % op2 |
&= |
op1 &= op2 |
op1 = op1 & op2 |
|= |
op1 |= op2 |
op1 = op1 | op2 |
^= |
op1 ^= op2 |
op1 = op1 ^ op2 |
<<= |
op1 <<= op2 |
op1 = op1 << op2 |
>>= |
op1 >>= op2 |
op1 = op1 >> op2 |
>>>= |
op1 >>>= op2 |
op1 = op1 >>> op2 |
|