The other answers are correct to an extent, but don't explain the whole thing.
First off, the doubled operators, &&
and ||
, function sort of like nested if
statements:
if (expression_a && expression_b) {
do_something;
}
is equivalent to
if (expression_a) {
if (expression_b) {
do_something;
}
}
In both cases, if expression_a
evaluates to false
then expression_b
will not be evaluated -- a feature referred to as "short-circuiting". (The ||
case is similar but a hair more complicated.)
Additionally, in Java (but not in C/C++) the &&
and ||
operators apply only to boolean values -- you cannot use &&
or ||
on an int
, eg.
The single operators, &
and |
, on the other hand, are relatively "pure" operators (commutative and associative with respect to themselves), with none of the "short-circuiting" of the double operators. Additionally, they can operate on any integer type -- boolean, char, byte, short, int, long. They perform a bit-by-bit operation -- bit N of the left operand is ANDed or ORed with bit N of the right operand to produce the Nth bit in a result value that is the same bit width as the two operands (after they are widened as appropriate for binary operators). In this regard, their operation with boolean
is just the degenerate case (albeit one that is somewhat special-cased).
Normally, one would use only the doubled operators for combining boolean expressions in an if
statement. There is no great harm in using the single operators if the boolean expressions involved are "safe" (cannot result in a null pointer exception, eg), but the doubled operators tend to be slightly more efficient and the short-circuiting is often desired (as in if (a != null && a.b == 5)
, eg), so it's generally wise to cultivate the habit of using the doubled forms. The only thing to beware of is that if you want the second expression to be evaluated (for it's side-effects), the doubled operator will not guarantee this happens.