An expression computes a value, denotes a variable, or, for a call of a
void method, gives nothing. Its type is known at compile time
(JLS chapter 15). Lambdas and method references
and switch expressions have
their own pages.
Precedence and associativity
The grammar fixes precedence; this table summarises it, from the tightest binding to the loosest. Operators in the same row have equal precedence.
| Level | Operators | Associativity |
|---|---|---|
| 1 | Primary: literals, this, (expr), new, a.b, a[i], f(x), T::m, T.class | left to right |
| 2 | Postfix x++ x-- | left to right |
| 3 | Prefix ++x --x, unary + - ~ !, cast (T) x | right to left |
| 4 | Multiplicative * / % | left to right |
| 5 | Additive + - | left to right |
| 6 | Shift << >> >>> | left to right |
| 7 | Relational < > <= >= instanceof | left to right (but a < b < c is a type error) |
| 8 | Equality == != | left to right |
| 9 | Bitwise or logical AND & | left to right |
| 10 | Bitwise or logical XOR ^ | left to right |
| 11 | Bitwise or logical OR | | left to right |
| 12 | Conditional AND && | left to right |
| 13 | Conditional OR || | left to right |
| 14 | Conditional ? : | right to left |
| 15 | Assignment = += -= *= /= %= &= |= ^= <<= >>= >>>=; lambda ->; switch expression | right to left |
Things to watch: &, ^ and | bind looser
than ==, so (flags & MASK) != 0 needs its parentheses;
and a cast binds tighter than arithmetic, so (int) a / b casts only
a.
Evaluation order
Java fixes the order of evaluation (JLS 15.7), unlike C:
- The left operand of a binary operator is fully evaluated before the right.
- Every operand is evaluated before the operation, except for
&&,||and? :, which may skip one. - Arguments are evaluated left to right, before the method is called.
- In a compound assignment
a op= b, the value ofais saved beforebis evaluated. - Parentheses change grouping, not order: in
f() + (g() * h()),fstill runs first.
int i = 1;
i = i++ + i; // 1 + 2: i is 3
int j = 5;
j += j++; // 5 + 5: j is 10, the increment is lost
int[] a = {0, 0};
int k = 0;
a[k] = k = 1; // a[0] is set: the index was evaluated first
Primary expressions
| Expression | Example | Notes |
|---|---|---|
| Literal | 42, "s", null | See Literals |
| Class literal | String.class, int.class, void.class | A Class object; Java 1.1 |
this | this, Outer.this | The current object, or an enclosing instance |
| Parenthesised | (a + b) | Same value; not a variable for assignment |
| Class instance creation | new ArrayList<>(10), outer.new Inner(), new Runnable() { … } | Runs a constructor; may declare an anonymous class |
| Array creation | new int[n], new int[] {1, 2} | See Arrays |
| Field access | p.x, super.x, Outer.super.x | Chosen by the static type, not overridden |
| Array access | a[i] | Checked for null and bounds |
| Method invocation | s.length(), super.m(), Iface.super.m(), List.<T>of() | Below |
| Method reference | String::length | See Lambdas |
Method invocation
A method call is resolved in two stages (JLS 15.12):
- At compile time the compiler finds the class or interface to search (from the qualifier, or the innermost enclosing class that has a method of that name), collects the accessible methods of that name, and finds the applicable ones in up to three phases: strict, loose, then varargs. Of those, it picks the most specific; if no single one is most specific, the call is ambiguous and an error.
- At run time the target reference is evaluated (a
nullone throwsNullPointerException), then the arguments, left to right. For an instance method that is not private, the method actually run is the one that overrides the chosen signature in the object’s run-time class: dynamic dispatch. Static, private andsuper.calls are not dispatched.
class A { String who() { return "A"; } static String s() { return "A"; } }
class B extends A { String who() { return "B"; } static String s() { return "B"; } }
A x = new B();
x.who(); // "B": dynamic dispatch on the object's class
x.s(); // "A": static methods are chosen by the declared type (and this form is discouraged)
Operators
Arithmetic
+, -, *, / and %
apply numeric promotion and
work in int, long, float or
double. Integer overflow wraps; integer / and
% by zero throw ArithmeticException; floating-point
operations never throw (see Types).
Unary - of the most negative int or long is
itself.
++ and -- work on a variable of any numeric type,
including char and wrappers, and the result has the variable’s type.
The prefix form gives the new value, the postfix form the old one.
String concatenation
If either operand of + is a String, the other is
converted by string
conversion and the two are joined. + groups from the left, so
1 + 2 + "x" is "3x" and "x" + 1 + 2 is
"x12". += works on a String variable. The result
is a new string unless the whole expression is a constant.
Shifts
| Operator | Meaning | Example |
|---|---|---|
a << n | Shift left, filling with zeros | 1 << 4 is 16 |
a >> n | Shift right, copying the sign bit | -16 >> 2 is −4 |
a >>> n | Shift right, filling with zeros | -16 >>> 28 is 15 |
Each operand is promoted separately; the result has the left operand’s type. Only
the low 5 bits of the shift distance are used for an int, and the low
6 bits for a long, so 1 << 32 is 1.
Relational and equality
<,>,<=and>=compare numbers after promotion. Any comparison with NaN is false.==and!=compare numbers (after promotion), booleans, or references. On references they test identity: two differentStringobjects with the same text are not==. Comparing a wrapper with a primitive unboxes the wrapper. Comparing references of types that cannot be cast to each other, such asStringandInteger, is an error.
instanceof
InstanceofExpression:
RelationalExpression instanceof ReferenceType
RelationalExpression instanceof Pattern
x instanceof T is true if x is not null and
can be cast to T without a ClassCastException. Since
Java 16 the right side can be a pattern,
which also declares variables bound to the matched value:
if (o instanceof String s && !s.isEmpty()). It is an error if the
test can never be true because the types are unrelated.
Bitwise and logical
| Operator | On integers | On booleans |
|---|---|---|
~ | Bitwise NOT | not allowed (use !) |
! | not allowed | Logical NOT |
& | Bitwise AND | Logical AND, both sides evaluated |
| | Bitwise OR | Logical OR, both sides evaluated |
^ | Bitwise XOR | Logical XOR (the same as !=) |
&& | not allowed | AND that skips the right side when the left is false |
|| | not allowed | OR that skips the right side when the left is true |
Conditional operator
c ? a : b evaluates c, then only one of a
and b. Its type depends on the operands (JLS 15.25):
- both
booleanorBoolean: abooleanconditional; - both numeric (or wrappers): a numeric conditional, whose type comes from numeric
promotion, with the special case that a
byte,shortorcharoperand keeps its type when the other is a constantintthat fits; - otherwise a reference conditional: in an assignment or invocation context it is a poly expression checked against the target; standalone, its type is the least upper bound of the boxed operand types.
A numeric conditional with a primitive and a wrapper operand unboxes the wrapper,
which can surprise. In Integer n = flag ? 0 : map.get(key); the
operands are int and Integer, so the result is an
int, and when flag is false and get returns
null, unboxing throws NullPointerException.
Assignment
a = bstoresb, converted by an assignment conversion, and its value is the stored value, soa = b = 0works.- A compound assignment
a op= bmeansa = (T) (a op b), whereTis the type ofaandais evaluated once. The cast is implicit, sobyte b = 10; b += 300;compiles and silently narrows. - The left side must be a variable: a local, a field, or an array element. It may
not be a
finalvariable that is already assigned.
Casts
CastExpression:
( PrimitiveType ) UnaryExpression
( ReferenceType {AdditionalBound} ) UnaryExpressionNotPlusMinus
( ReferenceType {AdditionalBound} ) LambdaExpression
A cast converts its operand in a casting
context. A cast to a reference type is checked at run time and may throw
ClassCastException. Because the grammar cannot tell
(a) - b from a cast, a reference cast cannot be applied to an operand
starting with + or -. Additional bounds give an
intersection type,
mostly for lambdas.
Constant expressions
A constant expression is computed at compile time (JLS 15.29). It has a primitive
type or String and is built only from:
- literals of primitive type and string literals (including text blocks);
- casts to primitive types and to
String; - the unary operators
+,-,~and!(not++or--); - the multiplicative, additive, shift, relational (not
instanceof), equality, bitwise and logical operators,&&,||and? :; - parenthesised constant expressions;
- simple names, and qualified names
TypeName.Identifier, of constant variables.
Constant expressions are needed for case labels, for annotation element values,
and for the narrowing of constants in assignments. Constant strings are interned, and
constant variables are inlined into the classes that use them, so changing one
requires recompiling its users. An expression that would throw, such as
1 / 0, is not a constant expression: it is evaluated at run time and
throws there (javac warns about it).