Movatterモバイル変換


[0]ホーム

URL:


Oracle Logo

Java SE >Java SE Specifications >Java Language Specification

Chapter 15. Expressions
Prev   Next

Chapter 15. Expressions

Table of Contents

15.1. Evaluation, Denotation, and Result
15.2. Forms of Expressions
15.3. Type of an Expression
15.4. FP-strict Expressions
15.5. Expressions and Run-Time Checks
15.6. Normal and Abrupt Completion of Evaluation
15.7. Evaluation Order
15.7.1. Evaluate Left-Hand Operand First
15.7.2. Evaluate Operands before Operation
15.7.3. Evaluation Respects Parentheses and Precedence
15.7.4. Argument Lists are Evaluated Left-to-Right
15.7.5. Evaluation Order for Other Expressions
15.8. Primary Expressions
15.8.1. Lexical Literals
15.8.2. Class Literals
15.8.3.this
15.8.4. Qualifiedthis
15.8.5. Parenthesized Expressions
15.9. Class Instance Creation Expressions
15.9.1. Determining the Class being Instantiated
15.9.2. Determining Enclosing Instances
15.9.3. Choosing the Constructor and its Arguments
15.9.4. Run-Time Evaluation of Class Instance Creation Expressions
15.9.5. Anonymous Class Declarations
15.9.5.1. Anonymous Constructors
15.10. Array Creation and Access Expressions
15.10.1. Array Creation Expressions
15.10.2. Run-Time Evaluation of Array Creation Expressions
15.10.3. Array Access Expressions
15.10.4. Run-Time Evaluation of Array Access Expressions
15.11. Field Access Expressions
15.11.1. Field Access Using a Primary
15.11.2. Accessing Superclass Members usingsuper
15.12. Method Invocation Expressions
15.12.1. Compile-Time Step 1: Determine Class or Interface to Search
15.12.2. Compile-Time Step 2: Determine Method Signature
15.12.2.1. Identify Potentially Applicable Methods
15.12.2.2. Phase 1: Identify Matching Arity Methods Applicable by Strict Invocation
15.12.2.3. Phase 2: Identify Matching Arity Methods Applicable by Loose Invocation
15.12.2.4. Phase 3: Identify Methods Applicable by Variable Arity Invocation
15.12.2.5. Choosing the Most Specific Method
15.12.2.6. Method Invocation Type
15.12.3. Compile-Time Step 3: Is the Chosen Method Appropriate?
15.12.4. Run-Time Evaluation of Method Invocation
15.12.4.1. Compute Target Reference (If Necessary)
15.12.4.2. Evaluate Arguments
15.12.4.3. Check Accessibility of Type and Method
15.12.4.4. Locate Method to Invoke
15.12.4.5. Create Frame, Synchronize, Transfer Control
15.13. Method Reference Expressions
15.13.1. Compile-Time Declaration of a Method Reference
15.13.2. Type of a Method Reference
15.13.3. Run-Time Evaluation of Method References
15.14. Postfix Expressions
15.14.1. Expression Names
15.14.2. Postfix Increment Operator++
15.14.3. Postfix Decrement Operator--
15.15. Unary Operators
15.15.1. Prefix Increment Operator++
15.15.2. Prefix Decrement Operator--
15.15.3. Unary Plus Operator+
15.15.4. Unary Minus Operator-
15.15.5. Bitwise Complement Operator~
15.15.6. Logical Complement Operator!
15.16. Cast Expressions
15.17. Multiplicative Operators
15.17.1. Multiplication Operator*
15.17.2. Division Operator/
15.17.3. Remainder Operator%
15.18. Additive Operators
15.18.1. String Concatenation Operator+
15.18.2. Additive Operators (+ and-) for Numeric Types
15.19. Shift Operators
15.20. Relational Operators
15.20.1. Numerical Comparison Operators<,<=,>, and>=
15.20.2. Type Comparison Operatorinstanceof
15.21. Equality Operators
15.21.1. Numerical Equality Operators== and!=
15.21.2. Boolean Equality Operators== and!=
15.21.3. Reference Equality Operators== and!=
15.22. Bitwise and Logical Operators
15.22.1. Integer Bitwise Operators&,^, and|
15.22.2. Boolean Logical Operators&,^, and|
15.23. Conditional-And Operator&&
15.24. Conditional-Or Operator||
15.25. Conditional Operator? :
15.25.1. Boolean Conditional Expressions
15.25.2. Numeric Conditional Expressions
15.25.3. Reference Conditional Expressions
15.26. Assignment Operators
15.26.1. Simple Assignment Operator=
15.26.2. Compound Assignment Operators
15.27. Lambda Expressions
15.27.1. Lambda Parameters
15.27.2. Lambda Body
15.27.3. Type of a Lambda Expression
15.27.4. Run-Time Evaluation of Lambda Expressions
15.28. Constant Expressions

Much of the work in a program is done by evaluatingexpressions, either for their side effects, such as assignments to variables, or for their values, which can be used as arguments or operands in larger expressions, or to affect the execution sequence in statements, or both.

This chapter specifies the meanings of expressions and the rules for their evaluation.

15.1. Evaluation, Denotation, and Result

When an expression in a program isevaluated (executed), the result denotes one of three things:

  • A variable (§4.12) (in C, this would be called anlvalue)

  • A value (§4.2,§4.3)

  • Nothing (the expression is said to be void)

If an expression denotes a variable, and a value is required for use in further evaluation, then the value of that variable is used. In this context, if the expression denotes a variable or a value, we may speak simply of thevalue of the expression.

Value set conversion (§5.1.13) is applied to the result of every expression that produces a value, including when the value of a variable of typefloat ordouble is used.

An expression denotes nothing if and only if it is a method invocation (§15.12) that invokes a method that does not return a value, that is, a method declaredvoid (§8.4). Such an expression can be used only as an expression statement (§14.8) or as the single expression of a lambda body (§15.27.2), because every other context in which an expression can appear requires the expression to denote something. An expression statement or lambda body that is a method invocation may also invoke a method that produces a result; in this case the value returned by the method is quietly discarded.

Evaluation of an expression can produce side effects, because expressions may contain embedded assignments, increment operators, decrement operators, and method invocations.

An expression occurs in either:

  • The declaration of some (class or interface) type that is being declared: in a field initializer, in a static initializer, in an instance initializer, in a constructor declaration, in a method declaration, or in an annotation.

  • An annotation on a package declaration or on a top level type declaration.

15.2. Forms of Expressions

Expressions can be broadly categorized into one of the following syntactic forms:

Precedence among operators is managed by a hierarchy of grammar productions. The lowest precedence operator is the arrow of a lambda expression (->), followed by the assignment operators. Thus, all expressions are syntactically included in theLambdaExpression andAssignmentExpression nonterminals:

Expression:
LambdaExpression
AssignmentExpression

When some expressions appear in certain contexts, they are consideredpoly expressions. The following forms of expressions may be poly expressions:

  • Parenthesized expressions (§15.8.5)

  • Class instance creation expressions (§15.9)

  • Method invocation expressions (§15.12)

  • Method reference expressions (§15.13)

  • Conditional expressions (§15.25)

  • Lambda expressions (§15.27)

The rules determining whether an expression of one of these forms is a poly expression are given in the individual sections that specify these forms of expressions.

Expressions that are not poly expressions arestandalone expressions. Standalone expressions are expressions of the forms above when determined not to be poly expressions, as well as all expressions of all other forms. Expressions of all other forms are said to have astandalone form.

Some expressions have a value that can be determined at compile time. These areconstant expressions (§15.28).

15.3. Type of an Expression

If an expression denotes a variable or a value, then the expression has a type known at compile time. The type of a standalone expression can be determined entirely from the contents of the expression; in contrast, the type of a poly expression may be influenced by the expression's target type (§5 (Conversions and Contexts)). The rules for determining the type of an expression are explained separately below for each kind of expression.

The value of an expression is assignment compatible (§5.2) with the type of the expression, unless heap pollution occurs (§4.12.2).

Likewise, the value stored in a variable is always compatible with the type of the variable, unless heap pollution occurs.

In other words, the value of an expression whose type isT is always suitable for assignment to a variable of typeT.

Note that an expression whose type is a class typeF that is declaredfinal is guaranteed to have a value that is either a null reference or an object whose class isF itself, becausefinal types have no subclasses.

15.4. FP-strict Expressions

If the type of an expression isfloat ordouble, then there is a question as to what value set (§4.2.3) the value of the expression is drawn from. This is governed by the rules of value set conversion (§5.1.13); these rules in turn depend on whether or not the expression isFP-strict.

Every constant expression (§15.28) is FP-strict.

If an expression is not a constant expression, then consider all the class declarations, interface declarations, and method declarations that contain the expression. Ifany such declaration bears thestrictfp modifier (§8.1.1.3,§8.4.3.5,§9.1.1.2), then the expression is FP-strict.

If a class, interface, or method,X, is declaredstrictfp, thenX and any class, interface, method, constructor, instance initializer, static initializer, or variable initializer withinX is said to beFP-strict.

Note that an annotation's element value (§9.7) is always FP-strict, because it is always a constant expression.

It follows that an expression is not FP-strict if and only if it is not a constant expressionand it does not appear within any declaration that has thestrictfp modifier.

Within an FP-strict expression, all intermediate values must be elements of the float value set or the double value set, implying that the results of all FP-strict expressions must be those predicted by IEEE 754 arithmetic on operands represented using single and double formats.

Within an expression that is not FP-strict, some leeway is granted for an implementation to use an extended exponent range to represent intermediate results; the net effect, roughly speaking, is that a calculation might produce "the correct answer" in situations where exclusive use of the float value set or double value set might result in overflow or underflow.

15.5. Expressions and Run-Time Checks

If the type of an expression is a primitive type, then the value of the expression is of that same primitive type.

If the type of an expression is a reference type, then the class of the referenced object, or even whether the value is a reference to an object rather thannull, is not necessarily known at compile time. There are a few places in the Java programming language where the actual class of a referenced object affects program execution in a manner that cannot be deduced from the type of the expression. They are as follows:

  • Method invocation (§15.12). The particular method used for an invocationo.m(...) is chosen based on the methods that are part of the class or interface that is the type ofo. For instance methods, the class of the object referenced by the run-time value ofo participates because a subclass may override a specific method already declared in a parent class so that this overriding method is invoked. (The overriding method may or may not choose to further invoke the original overriddenm method.)

  • Theinstanceof operator (§15.20.2). An expression whose type is a reference type may be tested usinginstanceof to find out whether the class of the object referenced by the run-time value of the expression is assignment compatible (§5.2) with some other reference type.

  • Casting (§5.5,§15.16). The class of the object referenced by the run-time value of the operand expression might not be compatible with the type specified by the cast. For reference types, this may require a run-time check that throws an exception if the class of the referenced object, as determined at run time, is not assignment compatible (§5.2) with the target type.

  • Assignment to an array component of reference type (§10.5,§15.13,§15.26.1). The type-checking rules allow the array typeS[] to be treated as a subtype ofT[] ifS is a subtype ofT, but this requires a run-time check for assignment to an array component, similar to the check performed for a cast.

  • Exception handling (§14.20). An exception is caught by acatch clause only if the class of the thrown exception object is aninstanceof the type of the formal parameter of thecatch clause.

Situations where the class of an object is not statically known may lead to run-time type errors.

In addition, there are situations where the statically known type may not be accurate at run time. Such situations can arise in a program that gives rise to compile-time unchecked warnings. Such warnings are given in response to operations that cannot be statically guaranteed to be safe, and cannot immediately be subjected to dynamic checking because they involve non-reifiable types (§4.7). As a result, dynamic checks later in the course of program execution may detect inconsistencies and result in run-time type errors.

A run-time type error can occur only in these situations:

  • In a cast, when the actual class of the object referenced by the value of the operand expression is not compatible with the target type specified by the cast operator (§5.5,§15.16); in this case aClassCastException is thrown.

  • In an automatically generated cast introduced to ensure the validity of an operation on a non-reifiable type (§4.7).

  • In an assignment to an array component of reference type, when the actual class of the object referenced by the value to be assigned is not compatible with the actual run-time component type of the array (§10.5,§15.13,§15.26.1); in this case anArrayStoreException is thrown.

  • When an exception is not caught by anycatch clause of atry statement (§14.20); in this case the thread of control that encountered the exception first attempts to invoke an uncaught exception handler (§11.3) and then terminates.

15.6. Normal and Abrupt Completion of Evaluation

Every expression has a normal mode of evaluation in which certain computational steps are carried out. The following sections describe the normal mode of evaluation for each kind of expression.

If all the steps are carried out without an exception being thrown, the expression is said tocomplete normally.

If, however, evaluation of an expression throws an exception, then the expression is said tocomplete abruptly. An abrupt completion always has an associated reason, which is always athrow with a given value.

Run-time exceptions are thrown by the predefined operators as follows:

  • A class instance creation expression (§15.9.4), array creation expression (§15.10.2), method reference expression (§15.13.3), array initializer expression (§10.6), string concatenation operator expression (§15.18.1), or lambda expression (§15.27.4) throws anOutOfMemoryError if there is insufficient memory available.

  • An array creation expression (§15.10.2) throws aNegativeArraySizeException if the value of any dimension expression is less than zero.

  • An array access expression (§15.10.4) throws aNullPointerException if the value of the array reference expression isnull.

  • An array access expression (§15.10.4) throws anArrayIndexOutOfBoundsException if the value of the array index expression is negative or greater than or equal to thelength of the array.

  • A field access expression (§15.11) throws aNullPointerException if the value of the object reference expression isnull.

  • A method invocation expression (§15.12) that invokes an instance method throws aNullPointerException if the target reference isnull.

  • A cast expression (§15.16) throws aClassCastException if a cast is found to be impermissible at run time.

  • An integer division (§15.17.2) or integer remainder (§15.17.3) operator throws anArithmeticException if the value of the right-hand operand expression is zero.

  • An assignment to an array component of reference type (§15.26.1), a method invocation expression (§15.12), or a prefix or postfix increment (§15.14.2,§15.15.1) or decrement operator (§15.14.3,§15.15.2) may all throw anOutOfMemoryError as a result of boxing conversion (§5.1.7).

  • An assignment to an array component of reference type (§15.26.1) throws anArrayStoreException when the value to be assigned is not compatible with the component type of the array (§10.5).

A method invocation expression can also result in an exception being thrown if an exception occurs that causes execution of the method body to complete abruptly.

A class instance creation expression can also result in an exception being thrown if an exception occurs that causes execution of the constructor to complete abruptly.

Various linkage and virtual machine errors may also occur during the evaluation of an expression. By their nature, such errors are difficult to predict and difficult to handle.

If an exception occurs, then evaluation of one or more expressions may be terminated before all steps of their normal mode of evaluation are complete; such expressions are said to complete abruptly.

If evaluation of an expression requires evaluation of a subexpression, then abrupt completion of the subexpression always causes the immediate abrupt completion of the expression itself, with the same reason, and all succeeding steps in the normal mode of evaluation are not performed.

The terms "complete normally" and "complete abruptly" are also applied to the execution of statements (§14.1). A statement may complete abruptly for a variety of reasons, not just because an exception is thrown.

15.7. Evaluation Order

The Java programming language guarantees that the operands of operators appear to be evaluated in a specificevaluation order, namely, from left to right.

It is recommended that code not rely crucially on this specification. Code is usually clearer when each expression contains at most one side effect, as its outermost operation, and when code does not depend on exactly which exception arises as a consequence of the left-to-right evaluation of expressions.

15.7.1. Evaluate Left-Hand Operand First

The left-hand operand of a binary operator appears to be fully evaluated before any part of the right-hand operand is evaluated.

If the operator is a compound-assignment operator (§15.26.2), then evaluation of the left-hand operand includes both remembering the variable that the left-hand operand denotes and fetching and saving that variable's value for use in the implied binary operation.

If evaluation of the left-hand operand of a binary operator completes abruptly, no part of the right-hand operand appears to have been evaluated.

Example 15.7.1-1. Left-Hand Operand Is Evaluated First

In the following program, the* operator has a left-hand operand that contains an assignment to a variable and a right-hand operand that contains a reference to the same variable. The value produced by the reference will reflect the fact that the assignment occurred first.

class Test1 {    public static void main(String[] args) {        int i = 2;        int j = (i=3) * i;        System.out.println(j);    }}

This program produces the output:

9

It is not permitted for evaluation of the* operator to produce6 instead of9.


Example 15.7.1-2. Implicit Left-Hand Operand In Operator Of Compound Assigment

In the following program, the two assignment statements both fetch and remember the value of the left-hand operand, which is9, before the right-hand operand of the addition operator is evaluated, at which point the variable is set to3.

class Test2 {    public static void main(String[] args) {        int a = 9;        a += (a = 3);  // first example        System.out.println(a);        int b = 9;        b = b + (b = 3);  // second example        System.out.println(b);    }}

This program produces the output:

1212

It is not permitted for either assignment (compound fora, simple forb) to produce the result6.

See also the example in§15.26.2.


Example 15.7.1-3. Abrupt Completion of Evaluation of the Left-Hand Operand

class Test3 {    public static void main(String[] args) {        int j = 1;        try {            int i = forgetIt() / (j = 2);        } catch (Exception e) {            System.out.println(e);            System.out.println("Now j = " + j);        }    }    static int forgetIt() throws Exception {        throw new Exception("I'm outta here!");    }}

This program produces the output:

java.lang.Exception: I'm outta here!Now j = 1

That is, the left-hand operandforgetIt() of the operator/ throws an exception before the right-hand operand is evaluated and its embedded assignment of2 toj occurs.


15.7.2. Evaluate Operands before Operation

The Java programming language guarantees that every operand of an operator (except the conditional operators&&,||, and? :) appears to be fully evaluated before any part of the operation itself is performed.

If the binary operator is an integer division/ (§15.17.2) or integer remainder% (§15.17.3), then its execution may raise anArithmeticException, but this exception is thrown only after both operands of the binary operator have been evaluated and only if these evaluations completed normally.

Example 15.7.2-1. Evaluation of Operands Before Operation

class Test {    public static void main(String[] args) {        int divisor = 0;        try {            int i = 1 / (divisor * loseBig());        } catch (Exception e) {            System.out.println(e);        }    }    static int loseBig() throws Exception {        throw new Exception("Shuffle off to Buffalo!");    }}

This program produces the output:

java.lang.Exception: Shuffle off to Buffalo!

and not:

java.lang.ArithmeticException: / by zero

since no part of the division operation, including signaling of a divide-by-zero exception, may appear to occur before the invocation ofloseBig completes, even though the implementation may be able to detect or infer that the division operation would certainly result in a divide-by-zero exception.


15.7.3. Evaluation Respects Parentheses and Precedence

The Java programming language respects the order of evaluation indicated explicitly by parentheses and implicitly by operator precedence.

An implementation of the Java programming language may not take advantage of algebraic identities such as the associative law to rewrite expressions into a more convenient computational order unless it can be proven that the replacement expression is equivalent in value and in its observable side effects, even in the presence of multiple threads of execution (using the thread execution model in§17 (Threads and Locks)), for all possible computational values that might be involved.

In the case of floating-point calculations, this rule applies also for infinity and not-a-number (NaN) values.

For example,!(x<y) may not be rewritten asx>=y, because these expressions have different values if eitherx ory is NaN or both are NaN.

Specifically, floating-point calculations that appear to be mathematically associative are unlikely to be computationally associative. Such computations must not be naively reordered.

For example, it is not correct for a Java compiler to rewrite4.0*x*0.5 as2.0*x; while roundoff happens not to be an issue here, there are large values ofx for which the first expression produces infinity (because of overflow) but the second expression produces a finite result.

So, for example, the test program:

strictfp class Test {    public static void main(String[] args) {        double d = 8e+307;        System.out.println(4.0 * d * 0.5);        System.out.println(2.0 * d);    }}

prints:

Infinity1.6e+308

because the first expression overflows and the second does not.

In contrast, integer addition and multiplicationare provably associative in the Java programming language.

For examplea+b+c, wherea,b, andc are local variables (this simplifying assumption avoids issues involving multiple threads andvolatile variables), will always produce the same answer whether evaluated as(a+b)+c ora+(b+c); if the expressionb+c occurs nearby in the code, a smart Java compiler may be able to use this common subexpression.

15.7.4. Argument Lists are Evaluated Left-to-Right

In a method or constructor invocation or class instance creation expression, argument expressions may appear within the parentheses, separated by commas. Each argument expression appears to be fully evaluated before any part of any argument expression to its right.

If evaluation of an argument expression completes abruptly, no part of any argument expression to its right appears to have been evaluated.

Example 15.7.4-1. Evaluation Order At Method Invocation

class Test1 {    public static void main(String[] args) {        String s = "going, ";        print3(s, s, s = "gone");    }    static void print3(String a, String b, String c) {        System.out.println(a + b + c);    }}

This program produces the output:

going, going, gone

because the assignment of the string "gone" tos occurs after the first two arguments toprint3 have been evaluated.


Example 15.7.4-2. Abrupt Completion of Argument Expression

class Test2 {    static int id;    public static void main(String[] args) {        try {            test(id = 1, oops(), id = 3);        } catch (Exception e) {            System.out.println(e + ",oops");    }}

This program produces the output:

java.lang.Exception: oops, id=1

because the assignment of3 toid is not executed.


15.7.5. Evaluation Order for Other Expressions

The order of evaluation for some expressions is not completely covered by these general rules, because these expressions may raise exceptional conditions at times that must be specified. See the detailed explanations of evaluation order for the following kinds of expressions:

15.8. Primary Expressions

Primary expressions include most of the simplest kinds of expressions, from which all others are constructed: literals, object creations, field accesses, method invocations, method references, and array accesses. A parenthesized expression is also treated syntactically as a primary expression.

Primary:
PrimaryNoNewArray
ArrayCreationExpression
PrimaryNoNewArray:
Literal
ClassLiteral
this
TypeName.this
(Expression)
ClassInstanceCreationExpression
FieldAccess
ArrayAccess
MethodInvocation
MethodReference

This part of the grammar of the Java programming language is unusual, in two ways. First, one might expect simple names, such as names of local variables and method parameters, to be primary expressions. For technical reasons, names are grouped together with primary expressions a little later when postfix expressions are introduced (§15.14).

The technical reasons have to do with allowing left-to-right parsing of Java programs with only one-token lookahead. Consider the expressions(z[3]) and(z[]). The first is a parenthesized array access (§15.10.3) and the second is the start of a cast (§15.16). At the point that the look-ahead symbol is[, a left-to-right parse will have reduced thez to the nonterminalName. In the context of a cast we prefer not to have to reduce the name to aPrimary, but ifName were one of the alternatives forPrimary, then we could not tell whether to do the reduction (that is, we could not determine whether the current situation would turn out to be a parenthesized array access or a cast) without looking ahead two tokens, to the token following the[. The grammar presented here avoids the problem by keepingName andPrimary separate and allowing either in certain other syntax rules (those forClassInstanceCreationExpression,MethodInvocation,ArrayAccess, andPostfixExpression, but not forFieldAccess because this uses an identifier directly). This strategy effectively defers the question of whether aName should be treated as aPrimary until more context can be examined.

The second unusual feature avoids a potential grammatical ambiguity in the expression "new int[3][3]" which in Java always means a single creation of a multidimensional array, but which, without appropriate grammatical finesse, might also be interpreted as meaning the same as "(new int[3])[3]".

This ambiguity is eliminated by splitting the expected definition ofPrimary intoPrimary andPrimaryNoNewArray. (This may be compared to the splitting ofStatement intoStatement andStatementNoShortIf (§14.5) to avoid the "dangling else" problem.)

15.8.1. Lexical Literals

A literal (§3.10) denotes a fixed, unchanging value.

The following production from§3.10 is shown here for convenience:

The type of a literal is determined as follows:

  • The type of an integer literal (§3.10.1) that ends withL orl islong (§4.2.1).

    The type of any other integer literal isint (§4.2.1).

  • The type of a floating-point literal (§3.10.2) that ends withF orf isfloat and its value must be an element of the float value set (§4.2.3).

    The type of any other floating-point literal isdouble and its value must be an element of the double value set (§4.2.3).

  • The type of a boolean literal (§3.10.3) isboolean (§4.2.5).

  • The type of a character literal (§3.10.4) ischar (§4.2.1).

  • The type of a string literal (§3.10.5) isString (§4.3.3).

  • The type of the null literalnull (§3.10.7) is the null type (§4.1); its value is the null reference.

Evaluation of a lexical literal always completes normally.

15.8.2. Class Literals

Aclass literal is an expression consisting of the name of a class, interface, array, or primitive type, or the pseudo-typevoid, followed by a '.' and the tokenclass.

ClassLiteral:
TypeName {[]}.class
NumericType {[]}.class
boolean {[]}.class
void.class

The type ofC.class, whereC is the name of a class, interface, or array type (§4.3), isClass<C>.

The type ofp.class, wherep is the name of a primitive type (§4.2), isClass<B>, whereB is the type of an expression of typep after boxing conversion (§5.1.7).

The type ofvoid.class (§8.4.5) isClass<Void>.

It is a compile-time error if the named type is a type variable (§4.4) or a parameterized type (§4.5) or an array whose element type is a type variable or parameterized type.

It is a compile-time error if the named type does not denote a type that is accessible (§6.6) and in scope (§6.3) at the point where the class literal appears.

A class literal evaluates to theClass object for the named type (or forvoid) as defined by the defining class loader (§12.2) of the class of the current instance.

15.8.3. this

The keywordthis may be used only in the following contexts:

  • in the body of an instance method or default method (§8.4.7,§9.4.3)

  • in the body of a constructor of a class (§8.8.7)

  • in an instance initializer of a class (§8.6)

  • in the initializer of an instance variable of a class (§8.3.2)

  • to denote a receiver parameter (§8.4.1)

If it appears anywhere else, a compile-time error occurs.

The keywordthis may be used in a lambda expression only if it is allowed in the context in which the lambda expression appears. Otherwise, a compile-time error occurs.

When used as a primary expression, the keywordthis denotes a value that is a reference to the object for which the instance method or default method was invoked (§15.12), or to the object being constructed. The value denoted bythis in a lambda body is the same as the value denoted bythis in the surrounding context.

The keywordthis is also used in explicit constructor invocation statements (§8.8.7.1).

The type ofthis is the class or interface typeT within which the keywordthis occurs.

Default methods provide the unique ability to accessthis inside an interface. (All other interface methods are eitherabstract orstatic, so provide no access tothis.) As a result, it is possible forthis to have an interface type.

At run time, the class of the actual object referred to may beT, ifT is a class type, or a class that is a subtype ofT.

Example 15.8.3-1. Thethis Expression

class IntVector {    int[] v;    boolean equals(IntVector other) {        if (this == other)            return true;        if (v.length != other.v.length)            return false;        for (int i = 0; i < v.length; i++) {            if (v[i] != other.v[i]) return false;        }        return true;    }}

Here, the classIntVector implements a methodequals, which compares two vectors. If the other vector is the same vector object as the one for which theequals method was invoked, then the check can skip the length and value comparisons. Theequals method implements this check by comparing the reference to the other object tothis.


15.8.4. Qualifiedthis

Any lexically enclosing instance (§8.1.3) can be referred to by explicitly qualifying the keywordthis.

LetT be the type denoted byTypeName. Letn be an integer such thatT is then'th lexically enclosing type declaration of the class or interface in which the qualifiedthis expression appears.

The value of an expression of the formTypeName.this is then'th lexically enclosing instance ofthis.

The type of the expression isT.

It is a compile-time error if the expression occurs in a class or interface which is not an inner class of classT orT itself.

15.8.5. Parenthesized Expressions

A parenthesized expression is a primary expression whose type is the type of the contained expression and whose value at run time is the value of the contained expression. If the contained expression denotes a variable then the parenthesized expression also denotes that variable.

The use of parentheses affects only theorder of evaluation, except for a corner case whereby(-2147483648) and(-9223372036854775808L) are legal but-(2147483648) and-(9223372036854775808L) are illegal.

This is because the decimal literals2147483648 and9223372036854775808L are allowed only as an operand of the unary minus operator (§3.10.1).

In particular, the presence or absence of parentheses around an expression does not (except for the case noted above) affect in any way:

  • the choice of value set (§4.2.3) for the value of an expression of typefloat ordouble.

  • whether a variable is definitely assigned, definitely assigned whentrue, definitely assigned whenfalse, definitely unassigned, definitely unassigned whentrue, or definitely unassigned whenfalse (§16 (Definite Assignment)).

If a parenthesized expression appears in a context of a particular kind with target typeT (§5 (Conversions and Contexts)), its contained expression similarly appears in a context of the same kind with target typeT.

If the contained expression is a poly expression (§15.2), the parenthesized expression is also a poly expression. Otherwise, it is a standalone expression.

15.9. Class Instance Creation Expressions

A class instance creation expression is used to create new objects that are instances of classes.

ClassInstanceCreationExpression:
UnqualifiedClassInstanceCreationExpression
ExpressionName.UnqualifiedClassInstanceCreationExpression
Primary.UnqualifiedClassInstanceCreationExpression
UnqualifiedClassInstanceCreationExpression:
new [TypeArguments]ClassOrInterfaceTypeToInstantiate( [ArgumentList]) [ClassBody]
ClassOrInterfaceTypeToInstantiate:
{Annotation}Identifier {. {Annotation}Identifier} [TypeArgumentsOrDiamond]
TypeArgumentsOrDiamond:
TypeArguments
<>

The following production from§15.12 is shown here for convenience:

ArgumentList:

A class instance creation expression specifies a class to be instantiated, possibly followed by type arguments (§4.5.1) or adiamond (<>) if the class being instantiated is generic (§8.1.2), followed by (a possibly empty) list of actual value arguments to the constructor.

If the type argument list to the class is empty — the diamond form<> — the type arguments of the class are inferred. It is legal, though strongly discouraged as a matter of style, to have white space between the "<" and ">" of a diamond.

If the constructor is generic (§8.8.4), the type arguments to the constructor may similarly either be inferred or passed explicitly. If passed explicitly, the type arguments to the constructor immediately follow the keywordnew.

It is a compile-time error if a class instance creation expression provides type arguments to a constructor but uses the diamond form for type arguments to the class.

This rule is introduced because inference of a generic class's type arguments may influence the constraints on a generic constructor's type arguments.

IfTypeArguments is present immediately afternew, or immediately before(, then it is a compile-time error if any of the type arguments are wildcards (§4.5.1).

The exception types that a class instance creation expression can throw are specified in§11.2.1.

Class instance creation expressions have two forms:

  • Unqualified class instance creation expressions begin with the keywordnew.

    An unqualified class instance creation expression may be used to create an instance of a class, regardless of whether the class is a top level (§7.6), member (§8.5,§9.5), local (§14.3), or anonymous class (§15.9.5).

  • Qualified class instance creation expressions begin with aPrimary expression or anExpressionName.

    A qualified class instance creation expression enables the creation of instances of inner member classes and their anonymous subclasses.

Both unqualified and qualified class instance creation expressions may optionally end with a class body. Such a class instance creation expression declares ananonymous class (§15.9.5) and creates an instance of it.

A class instance creation expression is a poly expression (§15.2) if it uses the diamond form for type arguments to the class, and it appears in an assignment context or an invocation context (§5.2,§5.3). Otherwise, it is a standalone expression.

We say that a class isinstantiated when an instance of the class is created by a class instance creation expression. Class instantiation involves determining the class to be instantiated (§15.9.1), the enclosing instances (if any) of the newly created instance (§15.9.2), and the constructor to be invoked to create the new instance (§15.9.3).

15.9.1. Determining the Class being Instantiated

If the class instance creation expression ends in a class body, then the class being instantiated is an anonymous class. Then:

  • If the class instance creation expression is unqualified:

    TheClassOrInterfaceTypeToInstantiate must denote a class that is accessible, non-final, and not an enum type; or denote an interface that is accessible. Otherwise a compile-time error occurs.

    IfClassOrInterfaceTypeToInstantiate ends with<>, then a compile-time error occurs.

    IfClassOrInterfaceTypeToInstantiate ends withTypeArguments, thenClassOrInterfaceTypeToInstantiate must denote a well-formed parameterized type (§4.5), or a compile-time error occurs.

    LetT be the type denoted byClassOrInterfaceTypeToInstantiate. IfT denotes a class, then an anonymous direct subclass ofT is declared. IfT denotes an interface, then an anonymous direct subclass ofObject that implementsT is declared. In either case, the body of the subclass is theClassBody given in the class instance creation expression.

    The class being instantiated is the anonymous subclass.

  • If the class instance creation expression is qualified:

    TheClassOrInterfaceTypeToInstantiate must unambiguously denote an inner class that is accessible, non-final, not an enum type, and a member of the compile-time type of thePrimary expression or theExpressionName. Otherwise, a compile-time error occurs.

    IfClassOrInterfaceTypeToInstantiate ends with<>, then a compile-time error occurs.

    IfClassOrInterfaceTypeToInstantiate ends withTypeArguments, thenClassOrInterfaceTypeToInstantiate must denote a well-formed parameterized type, or a compile-time error occurs.

    LetT be the type denoted byClassOrInterfaceTypeToInstantiate. An anonymous direct subclass ofT is declared. The body of the subclass is theClassBody given in the class instance creation expression.

    The class being instantiated is the anonymous subclass.

If a class instance creation expression does not declare an anonymous class, then:

  • If the class instance creation expression is unqualified:

    TheClassOrInterfaceTypeToInstantiate must denote a class that is accessible, non-abstract, and not an enum type. Otherwise, a compile-time error occurs.

    IfClassOrInterfaceTypeToInstantiate ends with<>, but the class denoted byClassOrInterfaceTypeToInstantiate is not generic, then a compile-time error occurs.

    IfClassOrInterfaceTypeToInstantiate ends withTypeArguments, thenClassOrInterfaceTypeToInstantiate must denote a well-formed parameterized class, or a compile-time error occurs.

    The class being instantiated is the class denoted byClassOrInterfaceTypeToInstantiate.

  • If the class instance creation expression is qualified:

    TheClassOrInterfaceTypeToInstantiate must unambiguously denote an inner class that is accessible, non-abstract, not an enum type, and a member of the compile-time type of thePrimary expression or theExpressionName.

    IfClassOrInterfaceTypeToInstantiate ends with<>, and the class denoted byClassOrInterfaceTypeToInstantiate is not generic, then a compile-time error occurs.

    IfClassOrInterfaceTypeToInstantiate ends withTypeArguments, thenClassOrInterfaceTypeToInstantiate must denote a well-formed parameterized class, or a compile-time error occurs.

    The class being instantiated is the class denoted byClassOrInterfaceTypeToInstantiate.

15.9.2. Determining Enclosing Instances

LetC be the class being instantiated, and leti be the instance being created. IfC is an inner class, theni may have animmediately enclosing instance (§8.1.3), determined as follows:

  • IfC is an anonymous class, then:

    • If the class instance creation expression occurs in a static context, theni has no immediately enclosing instance.

    • Otherwise, the immediately enclosing instance ofi isthis.

  • IfC is a local class, then:

    • IfC occurs in a static context, theni has no immediately enclosing instance.

    • Otherwise, if the class instance creation expression occurs in a static context, then a compile-time error occurs.

    • Otherwise, letO be the immediately enclosing class ofC. Letn be an integer such thatO is then'th lexically enclosing type declaration of the class in which the class instance creation expression appears.

      The immediately enclosing instance ofi is then'th lexically enclosing instance ofthis.

  • IfC is an inner member class, then:

    • If the class instance creation expression is unqualified, then:

      • If the class instance creation expression occurs in a static context, then a compile-time error occurs.

      • Otherwise, ifC is a member of a class enclosing the class in which the class instance creation expression appears, then letO be the immediately enclosing class of whichC is a member. Letn be an integer such thatO is then'th lexically enclosing type declaration of the class in which the class instance creation expression appears.

        The immediately enclosing instance ofi is then'th lexically enclosing instance ofthis.

      • Otherwise, a compile-time error occurs.

    • If the class instance creation expression is qualified, then the immediately enclosing instance ofi is the object that is the value of thePrimary expression or theExpressionName.

IfC is an anonymous class, and its direct superclassS is an inner class, theni may have animmediately enclosing instance with respect toS, determined as follows:

  • IfS is a local class, then:

    • IfS occurs in a static context, theni has no immediately enclosing instance with respect toS.

    • Otherwise, if the class instance creation expression occurs in a static context, then a compile-time error occurs.

    • Otherwise, letO be the immediately enclosing class ofS. Letn be an integer such thatO is then'th lexically enclosing type declaration of the class in which the class instance creation expression appears.

      The immediately enclosing instance ofi with respect toS is then'th lexically enclosing instance ofthis.

  • IfS is an inner member class, then:

    • If the class instance creation expression is unqualified, then:

      • If the class instance creation expression occurs in a static context, then a compile-time error occurs.

      • Otherwise, ifS is a member of a class enclosing the class in which the class instance creation expression appears, then letO be the immediately enclosing class of whichS is a member. Letn be an integer such thatO is then'th lexically enclosing type declaration of the class in which the class instance creation expression appears.

        The immediately enclosing instance ofi with respect toS is then'th lexically enclosing instance ofthis.

      • Otherwise, a compile-time error occurs.

    • If the class instance creation expression is qualified, then the immediately enclosing instance ofi with respect toS is the object that is the value of thePrimary expression or theExpressionName.

15.9.3. Choosing the Constructor and its Arguments

LetC be the class being instantiated. To create an instance ofC,i, a constructor ofC is chosen at compile time by the following rules:

First, the actual arguments to the constructor invocation are determined:

  • IfC is an anonymous class with direct superclassS, then:

    • IfS is not an inner class, or ifS is a local class that occurs in a static context, then the arguments to the constructor are the arguments in the argument list of the class instance creation expression, if any, in the order they appear in the expression.

    • Otherwise, the first argument to the constructor is the immediately enclosing instance ofi with respect toS (§15.9.2), and the subsequent arguments to the constructor are the arguments in the argument list of the class instance creation expression, if any, in the order they appear in the class instance creation expression.

  • IfC is a local class or aprivate inner member class, then the arguments to the constructor are the arguments in the argument list of the class instance creation expression, if any, in the order they appear in the class instance creation expression.

  • IfC is a non-private inner member class, then the first argument to the constructor is the immediately enclosing instance ofi (§8.8.1,§15.9.2), and the subsequent arguments to its constructor are the arguments in the argument list of the class instance creation expression, if any, in the order they appear in the class instance creation expression.

  • Otherwise, the arguments to the constructor are the arguments in the argument list of the class instance creation expression, if any, in the order they appear in the expression.

Second, a constructor ofC and corresponding return type andthrows clause are determined:

  • If the class instance creation expression uses<> to elide class type arguments, a list of methodsm1...mn is defined for the purpose of overload resolution and type argument inference.

    Letc1...cn be the constructors of classC. Let#m be an automatically generated name that is distinct from all constructor and method names inC. For allj (1jn),mj is defined in terms ofcj as follows:

    • A substitutionθj is first defined to instantiate the types incj.

      LetF1...Fp be the type parameters ofC, and letG1...Gq be the type parameters (if any) ofcj. LetX1...Xp andY1...Yq be type variables with distinct names that are not in scope in the body ofC.

      θj is[F1:=X1, ...,Fp:=Xp,G1:=Y1, ...,Gq:=Yq].

    • The modifiers ofmj are those ofcj.

    • The type parameters ofmj areX1...Xp,Y1...Yq. The bound of each parameter, if any, isθj applied to the corresponding parameter bound inC orcj.

    • The return type ofmj isθj applied toC<F1,...,Fp>.

    • The name ofmj is#m.

    • The (possibly empty) list of argument types ofmj isθj applied to the argument types ofcj.

    • The (possibly empty) list of thrown types ofmj isθj applied to the thrown types ofcj.

    • The body ofmj is irrelevant.

    To choose a constructor, we temporarily considerm1...mn to be members ofC. Then one ofm1...mn is selected, as determined by the class instance creation's argument expressions, using the process specified in§15.12.2.

    If there is no unique most specific method that is both applicable and accessible, then a compile-time error occurs.

    Otherwise, wheremj is the selected method,cj is the chosen constructor. The return type andthrows clause ofcj are the same as the return type andthrows clause determined formj (§15.12.2.6).

  • Otherwise, the class instance creation expression does not use<> to elide class type arguments.

    LetT be the type denoted byC followed by any class type arguments in the expression. The process specified in§15.12.2, modified to handle constructors, is used to select one of the constructors ofT and determine itsthrows clause.

    If there is no unique most-specific constructor that is both applicable and accessible, then a compile-time error occurs (as in method invocations).

    Otherwise, the return type isT.

It is a compile-time error if an argument to a class instance creation expression is not compatible with its target type, as derived from the invocation type (§15.12.2.6).

If the compile-time declaration is applicable by variable arity invocation (§15.12.2.4), then where the last formal parameter type of the invocation type of the constructor isFn[], it is a compile-time error if the type which is the erasure ofFn is not accessible at the point of invocation.

The type of the class instance creation expression is the return type of the chosen constructor, as defined above.

Note that the type of the class instance creation expression may be an anonymous class type, in which case the constructor being invoked is an anonymous constructor (§15.9.5.1).

15.9.4. Run-Time Evaluation of Class Instance Creation Expressions

At run time, evaluation of a class instance creation expression is as follows.

First, if the class instance creation expression is a qualified class instance creation expression, the qualifying primary expression is evaluated. If the qualifying expression evaluates tonull, aNullPointerException is raised, and the class instance creation expression completes abruptly. If the qualifying expression completes abruptly, the class instance creation expression completes abruptly for the same reason.

Next, space is allocated for the new class instance. If there is insufficient space to allocate the object, evaluation of the class instance creation expression completes abruptly by throwing anOutOfMemoryError.

The new object contains new instances of all the fields declared in the specified class type and all its superclasses. As each new field instance is created, it is initialized to its default value (§4.12.5).

Next, the actual arguments to the constructor are evaluated, left-to-right. If any of the argument evaluations completes abruptly, any argument expressions to its right are not evaluated, and the class instance creation expression completes abruptly for the same reason.

Next, the selected constructor of the specified class type is invoked. This results in invoking at least one constructor for each superclass of the class type. This process can be directed by explicit constructor invocation statements (§8.8) and is specified in detail in§12.5.

The value of a class instance creation expression is a reference to the newly created object of the specified class. Every time the expression is evaluated, a fresh object is created.

Example 15.9.4-1. Evaluation Order and Out-Of-Memory Detection

If evaluation of a class instance creation expression finds there is insufficient memory to perform the creation operation, then anOutOfMemoryError is thrown. This check occurs before any argument expressions are evaluated.

So, for example, the test program:

class List {    int value;    List next;    static List head = new List(0);    List(int n) { value = n; next = head; head = this; }}class Test {    public static void main(String[] args) {        int id = 0, oldid = 0;        try {            for (;;) {                ++id;                new List(oldid = id);            }        } catch (Error e) {            List.head = null;            System.out.println(e.getClass() + ", " + (oldid==id));        }    }}

prints:

class java.lang.OutOfMemoryError, false

because the out-of-memory condition is detected before the argument expressionoldid = id is evaluated.

Compare this to the treatment of array creation expressions, for which the out-of-memory condition is detected after evaluation of the dimension expressions (§15.10.2).


15.9.5. Anonymous Class Declarations

An anonymous class declaration is automatically derived from a class instance creation expression by the Java compiler.

An anonymous class is neverabstract (§8.1.1.1).

An anonymous class is always implicitlyfinal (§8.1.1.2).

An anonymous class is always an inner class (§8.1.3); it is neverstatic (§8.1.1,§8.5.1).

15.9.5.1. Anonymous Constructors

An anonymous class cannot have an explicitly declared constructor. Instead, an anonymous constructor is implicitly declared for an anonymous class. The form of the anonymous constructor for an anonymous classC with direct superclassS is as follows:

  • IfS is not an inner class, or ifS is a local class that occurs in a static context, then the anonymous constructor has one formal parameter for each actual argument to the class instance creation expression in whichC is declared.

    The actual arguments to the class instance creation expression are used to determine a constructorcs ofS, using the same rules as for method invocations (§15.12). The type of each formal parameter of the anonymous constructor must be identical to the corresponding formal parameter ofcs.

    The constructor body consists of an explicit constructor invocation (§8.8.7.1) of the formsuper(...), where the actual arguments are the formal parameters of the constructor, in the order they were declared.

  • Otherwise, the first formal parameter of the constructor ofC represents the value of the immediately enclosing instance ofi with respect toS (§15.9.2,§15.9.3). The type of this parameter is the class type that immediately encloses the declaration ofS.

    The constructor has an additional formal parameter for each actual argument to the class instance creation expression that declared the anonymous class. Then'th formal parametere corresponds to then-1'th actual argument.

    The actual arguments to the class instance creation expression are used to determine a constructorcs ofS, using the same rules as for method invocations (§15.12). The type of each formal parameter of the anonymous constructor must be identical to the corresponding formal parameter ofcs.

    The constructor body consists of an explicit constructor invocation (§8.8.7.1) of the formo.super(...), whereo is the first formal parameter of the constructor, and the actual arguments are the subsequent formal parameters of the constructor, in the order they were declared.

In all cases, thethrows clause of an anonymous constructor must list all the checked exceptions thrown by the explicit superclass constructor invocation statement contained within the anonymous constructor, and all checked exceptions thrown by any instance initializers or instance variable initializers of the anonymous class.

Note that it is possible for the signature of the anonymous constructor to refer to an inaccessible type (for example, if such a type occurred in the signature of the superclass constructorcs). This does not, in itself, cause any errors at either compile-time or run-time.

15.10. Array Creation and Access Expressions

15.10.1. Array Creation Expressions

An array creation expression is used to create new arrays (§10 (Arrays)).

ArrayCreationExpression:
DimExprs:
DimExpr:

The following production from§4.3 is shown here for convenience:

Dims:

An array creation expression creates an object that is a new array whose elements are of the type specified by thePrimitiveType orClassOrInterfaceType.

It is a compile-time error if theClassOrInterfaceType does not denote a reifiable type (§4.7). Otherwise, theClassOrInterfaceType may name any named reference type, even anabstract class type (§8.1.1.1) or an interface type.

The rules above imply that the element type in an array creation expression cannot be a parameterized type, unless all type arguments to the parameterized type are unbounded wildcards.

The type of each dimension expression within aDimExpr must be a type that is convertible (§5.1.8) to an integral type, or a compile-time error occurs.

Each dimension expression undergoes unary numeric promotion (§5.6.1). The promoted type must beint, or a compile-time error occurs.

The type of the array creation expression is an array type that can denoted by a copy of the array creation expression from which thenew keyword and everyDimExpr expression and array initializer have been deleted.

For example, the type of the creation expression:

new double[3][3][]

is:

double[][][]

15.10.2. Run-Time Evaluation of Array Creation Expressions

At run time, evaluation of an array creation expression behaves as follows:

  • If there are no dimension expressions, then there must be an array initializer. A newly allocated array will be initialized with the values provided by the array initializer as described in§10.6. The value of the array initializer becomes the value of the array creation expression.

  • Otherwise, there is no array initializer, and:

    • First, the dimension expressions are evaluated, left-to-right. If any of the expression evaluations completes abruptly, the expressions to the right of it are not evaluated.

    • Next, the values of the dimension expressions are checked. If the value of anyDimExpr expression is less than zero, then aNegativeArraySizeException is thrown.

    • Next, space is allocated for the new array. If there is insufficient space to allocate the array, evaluation of the array creation expression completes abruptly by throwing anOutOfMemoryError.

    • Then, if a singleDimExpr appears, a one-dimensional array is created of the specified length, and each component of the array is initialized to its default value (§4.12.5).

    • Otherwise, ifnDimExpr expressions appear, then array creation effectively executes a set of nested loops of depthn-1 to create the implied arrays of arrays.

      A multidimensional array need not have arrays of the same length at each level.

Example 15.10.2-1. Array Creation Evaluation

In an array creation expression with one or more dimension expressions, each dimension expression is fully evaluated before any part of any dimension expression to its right. Thus:

class Test1 {    public static void main(String[] args) {        int i = 4;        int ia[][] = new int[i][i=3];        System.out.println(            "[" + ia.length + "," + ia[0].length + "]");    }}

prints:

[4,3]

because the first dimension is calculated as4 before the second dimension expression setsi to3.

If evaluation of a dimension expression completes abruptly, no part of any dimension expression to its right will appear to have been evaluated. Thus:

class Test2 {    public static void main(String[] args) {        int[][] a = { { 00, 01 }, { 10, 11 } };        int i = 99;        try {            a[val()][i = 1]++;        } catch (Exception e) {            System.out.println(e + ", i=" + i);        }    }    static int val() throws Exception {        throw new Exception("unimplemented");    }}

prints:

java.lang.Exception: unimplemented, i=99

because the embedded assignment that setsi to1 is never executed.


Example 15.10.2-2. Multi-Dimensional Array Creation

The declaration:

float[][] matrix = new float[3][3];

is equivalent in behavior to:

float[][] matrix = new float[3][];for (intd = 0;d < matrix.length;d++)    matrix[d] = new float[3];

and:

Age[][][][][] Aquarius = new Age[6][10][8][12][];

is equivalent to:

Age[][][][][] Aquarius = new Age[6][][][][];for (intd1 = 0;d1 < Aquarius.length;d1++) {    Aquarius[d1] = new Age[10][][][];    for (intd2 = 0;d2 < Aquarius[d1].length;d2++) {        Aquarius[d1][d2] = new Age[8][][];        for (intd3 = 0;d3 < Aquarius[d1][d2].length;d3++) {            Aquarius[d1][d2][d3] = new Age[12][];        }    }}

withd,d1,d2, andd3 replaced by names that are not already locally declared. Thus, a singlenew expression actually creates one array of length 6, 6 arrays of length 10, 6x10 = 60 arrays of length 8, and 6x10x8 = 480 arrays of length 12. This example leaves the fifth dimension, which would be arrays containing the actual array elements (references toAge objects), initialized only to null references. These arrays can be filled in later by other code, such as:

Age[] Hair = { new Age("quartz"), new Age("topaz") };Aquarius[1][9][6][9] = Hair;

A triangular matrix may be created by:

float triang[][] = new float[100][];for (int i = 0; i < triang.length; i++)    triang[i] = new float[i+1];

If evaluation of an array creation expression finds there is insufficient memory to perform the creation operation, then anOutOfMemoryError is thrown. If the array creation expression does not have an array initializer, then this check occurs only after evaluation of all dimension expressions has completed normally. If the array creation expression does have an array initializer, then anOutOfMemoryError can occur when an object of reference type is allocated during evaluation of a variable initializer expression, or when space is allocated for an array to hold the values of a (possibly nested) array initializer.

Example 15.10.2-3. OutOfMemoryError and Dimension Expression Evaluation

class Test3 {    public static void main(String[] args) {        int len = 0, oldlen = 0;        Object[] a = new Object[0];        try {            for (;;) {                ++len;                Object[] temp = new Object[oldlen = len];                temp[0] = a;                a = temp;            }        } catch (Error e) {            System.out.println(e + ", " + (oldlen==len));        }    }}

This program produces the output:

java.lang.OutOfMemoryError, true

because the out-of-memory condition is detected after the dimension expressionoldlen = len is evaluated.

Compare this to class instance creation expressions (§15.9), which detect the out-of-memory condition before evaluating argument expressions (§15.9.4).


15.10.3. Array Access Expressions

An array access expression refers to a variable that is a component of an array.

ArrayAccess:

An array access expression contains two subexpressions, thearray reference expression (before the left bracket) and theindex expression (within the brackets).

Note that the array reference expression may be a name or any primary expression that is not an array creation expression (§15.10).

The type of the array reference expression must be an array type (call itT[], an array whose components are of typeT), or a compile-time error occurs.

The index expression undergoes unary numeric promotion (§5.6.1). The promoted type must beint, or a compile-time error occurs.

The type of the array access expression is the result of applying capture conversion (§5.1.10) toT.

The result of an array access expression is a variable of typeT, namely the variable within the array selected by the value of the index expression.

This resulting variable, which is a component of the array, is never consideredfinal, even if the array reference expression denoted afinal variable.

15.10.4. Run-Time Evaluation of Array Access Expressions

At run time, evaluation of an array access expression behaves as follows:

  • First, the array reference expression is evaluated. If this evaluation completes abruptly, then the array access completes abruptly for the same reason and the index expression is not evaluated.

  • Otherwise, the index expression is evaluated. If this evaluation completes abruptly, then the array access completes abruptly for the same reason.

  • Otherwise, if the value of the array reference expression isnull, then aNullPointerException is thrown.

  • Otherwise, the value of the array reference expression indeed refers to an array. If the value of the index expression is less than zero, or greater than or equal to the array'slength, then anArrayIndexOutOfBoundsException is thrown.

  • Otherwise, the result of the array access is the variable of typeT, within the array, selected by the value of the index expression.

Example 15.10.4-1. Array Reference Is Evaluated First

In an array access, the expression to the left of the brackets appears to be fully evaluated before any part of the expression within the brackets is evaluated. For example, in the (admittedly monstrous) expressiona[(a=b)[3]], the expressiona is fully evaluated before the expression(a=b)[3]; this means that the original value ofa is fetched and remembered while the expression(a=b)[3] is evaluated. This array referenced by the original value ofa is then subscripted by a value that is element3 of another array (possibly the same array) that was referenced byb and is now also referenced bya.

Thus, the program:

class Test1 {    public static void main(String[] args) {        int[] a = { 11, 12, 13, 14 };        int[] b = { 0, 1, 2, 3 };        System.out.println(a[(a=b)[3]]);    }}

prints:

14

because the monstrous expression's value is equivalent toa[b[3]] ora[3] or14.


Example 15.10.4-2. Abrupt Completion of Array Reference Evaluation

If evaluation of the expression to the left of the brackets completes abruptly, no part of the expression within the brackets will appear to have been evaluated. Thus, the program:

class Test2 {    public static void main(String[] args) {        int index = 1;        try {            skedaddle()[index=2]++;        } catch (Exception e) {            System.out.println(e + ", index=" + index);        }    }    static int[] skedaddle() throws Exception {        throw new Exception("Ciao");    }}

prints:

java.lang.Exception: Ciao, index=1

because the embedded assignment of2 toindex never occurs.


Example 15.10.4-3. null Array Reference

If the array reference expression producesnull instead of a reference to an array, then aNullPointerException is thrown at run time, but only after all parts of the array access expression have been evaluated and only if these evaluations completed normally. Thus, the program:

class Test3 {    public static void main(String[] args) {        int index = 1;        try {            nada()[index=2]++;        } catch (Exception e) {            System.out.println(e + ", index=" + index);        }    }    static int[] nada() { return null; }}

prints:

java.lang.NullPointerException, index=2

because the embedded assignment of2 toindex occurs before the check for anull array reference expression. As a related example, the program:

class Test4 {    public static void main(String[] args) {        int[] a = null;        try {            int i = a[vamoose()];            System.out.println(i);        } catch (Exception e) {            System.out.println(e);        }    }    static int vamoose() throws Exception {        throw new Exception("Twenty-three skidoo!");    }}

always prints:

java.lang.Exception: Twenty-three skidoo!

ANullPointerException never occurs, because the index expression must be completely evaluated before any further part of the array access occurs, and that includes the check as to whether the value of the array reference expression isnull.


15.11. Field Access Expressions

A field access expression may access a field of an object or array, a reference to which is the value of either an expression or the special keywordsuper.

FieldAccess:
Primary.Identifier
super.Identifier
TypeName.super.Identifier

The meaning of a field access expression is determined using the same rules as for qualified names (§6.5.6.2), but limited by the fact that an expression cannot denote a package, class type, or interface type.

It is also possible to refer to a field of the current instance or current class by using a simple name (§6.5.6.1).

15.11.1. Field Access Using a Primary

The type of thePrimary must be a reference typeT, or a compile-time error occurs.

The meaning of the field access expression is determined as follows:

  • If the identifier names several accessible (§6.6) member fields in typeT, then the field access is ambiguous and a compile-time error occurs.

  • If the identifier does not name an accessible member field in typeT, then the field access is undefined and a compile-time error occurs.

  • Otherwise, the identifier names a single accessible member field in typeT, and the type of the field access expression is the type of the member field after capture conversion (§5.1.10).

At run time, the result of the field access expression is computed as follows: (assuming that the program is correct with respect to definite assignment analysis, i.e. every blankfinal variable is definitely assigned before access)

  • If the field isstatic:

    • ThePrimary expression is evaluated, and the result is discarded. If evaluation of thePrimary expression completes abruptly, the field access expression completes abruptly for the same reason.

    • If the field is a non-blankfinal field, then the result is the value of the specified class variable in the class or interface that is the type of thePrimary expression.

    • If the field is notfinal, or is a blankfinal and the field access occurs in a static initializer or class variable initializer, then the result is a variable, namely, the specified class variable in the class that is the type of thePrimary expression.

  • If the field is notstatic:

    • ThePrimary expression is evaluated. If evaluation of thePrimary expression completes abruptly, the field access expression completes abruptly for the same reason.

    • If the value of thePrimary isnull, then aNullPointerException is thrown.

    • If the field is a non-blankfinal, then the result is the value of the named member field in typeT found in the object referenced by the value of thePrimary.

    • If the field is notfinal, or is a blankfinal and the field access occurs in a constructor or instance variable initializer, then the result is a variable, namely the named member field in typeT found in the object referenced by the value of thePrimary.

Note that only the type of thePrimary expression, not the class of the actual object referred to at run time, is used in determining which field to use.

Example 15.11.1-1. Static Binding for Field Access

class S           { int x = 0; }class T extends S { int x = 1; }class Test1 {    public static void main(String[] args) {        T t = new T();        System.out.println("t.x=" + t.x + when("t", t));        S s = new S();        System.out.println("s.x=" + s.x + when("s", s));        s = t;        System.out.println("s.x=" + s.x + when("s", s));    }    static String when(String name, Object t) {        return " when " + name + " holds a "                        + t.getClass() + " at run time.";    }}

This program produces the output:

t.x=1 when t holds a class T at run time.s.x=0 when s holds a class S at run time.s.x=0 when s holds a class T at run time.

The last line shows that, indeed, the field that is accessed does not depend on the run-time class of the referenced object; even ifs holds a reference to an object of classT, the expressions.x refers to thex field of classS, because the type of the expressions isS. Objects of classT contain two fields namedx, one for classT and one for its superclassS.

This lack of dynamic lookup for field accesses allows programs to be run efficiently with straightforward implementations. The power of late binding and overriding is available, but only when instance methods are used. Consider the same example using instance methods to access the fields:

class S           { int x = 0; int z() { return x; } }class T extends S { int x = 1; int z() { return x; } }class Test2 {    public static void main(String[] args) {        T t = new T();        System.out.println("t.z()=" + t.z() + when("t", t));        S s = new S();        System.out.println("s.z()=" + s.z() + when("s", s));        s = t;        System.out.println("s.z()=" + s.z() + when("s", s));    }    static String when(String name, Object t) {        return " when " + name + " holds a "                        + t.getClass() + " at run time.";    }}

Now the output is:

t.z()=1 when t holds a class T at run time.s.z()=0 when s holds a class S at run time.s.z()=1 when s holds a class T at run time.

The last line shows that, indeed, the method that is accesseddoes depend on the run-time class of the referenced object; whens holds a reference to an object of classT, the expressions.z() refers to thez method of classT, despite the fact that the type of the expressions isS. Methodz of classT overrides methodz of classS.


Example 15.11.1-2. Receiver Variable Is Irrelevant Forstatic Field Access

The following program demonstrates that a null reference may be used to access a class (static) variable without causing an exception:

class Test3 {    static String mountain = "Chocorua";    static Test3 favorite(){        System.out.print("Mount ");        return null;    }    public static void main(String[] args) {        System.out.println(favorite().mountain);    }}

It compiles, executes, and prints:

Mount Chocorua

Even though the result offavorite() isnull, aNullPointerException is not thrown. That "Mount" is printed demonstrates that thePrimary expression is indeed fully evaluated at run time, despite the fact that only its type, not its value, is used to determine which field to access (because the fieldmountain isstatic).


15.11.2. Accessing Superclass Members usingsuper

The formsuper.Identifier refers to the field namedIdentifier of the current object, but with the current object viewed as an instance of the superclass of the current class.

The formT.super.Identifier refers to the field namedIdentifier of the lexically enclosing instance corresponding toT, but with that instance viewed as an instance of the superclass ofT.

The forms using the keywordsuper are valid only in an instance method, instance initializer, or constructor of a class, or in the initializer of an instance variable of a class. If they appear anywhere else, a compile-time error occurs.

These are exactly the same situations in which the keywordthis may be used in a class declaration (§15.8.3).

It is a compile-time error if the forms using the keywordsuper appear in the declaration of classObject, sinceObject has no superclass.

Suppose that a field access expressionsuper.f appears within classC, and the immediate superclass ofC is classS. Iff inS is accessible from classC (§6.6), thensuper.f is treated as if it had been the expressionthis.f in the body of classS. Otherwise, a compile-time error occurs.

Thus,super.f can access the fieldf that is accessible in classS, even if that field is hidden by a declaration of a fieldf in classC.

Suppose that a field access expressionT.super.f appears within classC, and the immediate superclass of the class denoted byT is a class whose fully qualified name isS. Iff inS is accessible fromC, thenT.super.f is treated as if it had been the expressionthis.f in the body of classS. Otherwise, a compile-time error occurs.

Thus,T.super.f can access the fieldf that is accessible in classS, even if that field is hidden by a declaration of a fieldf in classT.

It is a compile-time error if the current class is not an inner class of classT orT itself.

Example 15.11.2-1. Thesuper Expression

interface I           { int x = 0; }class T1 implements I { int x = 1; }class T2 extends T1   { int x = 2; }class T3 extends T2 {    int x = 3;    void test() {        System.out.println("x=\t\t"          + x);        System.out.println("super.x=\t\t"    + super.x);        System.out.println("((T2)this).x=\t" + ((T2)this).x);        System.out.println("((T1)this).x=\t" + ((T1)this).x);        System.out.println("((I)this).x=\t"  + ((I)this).x);    }}class Test {    public static void main(String[] args) {        new T3().test();    }}

This program produces the output:

x=              3super.x=        2((T2)this).x=   2((T1)this).x=   1((I)this).x=    0

Within classT3, the expressionsuper.x has the same effect as((T2)this).x whenx has package access. Note thatsuper.x is not specified in terms of a cast, due to difficulties around access toprotected members of the superclass.


15.12. Method Invocation Expressions

A method invocation expression is used to invoke a class or instance method.

MethodInvocation:
MethodName( [ArgumentList])
TypeName. [TypeArguments]Identifier( [ArgumentList])
ExpressionName. [TypeArguments]Identifier( [ArgumentList])
Primary. [TypeArguments]Identifier( [ArgumentList])
super. [TypeArguments]Identifier( [ArgumentList])
TypeName.super. [TypeArguments]Identifier( [ArgumentList])
ArgumentList:
Expression {,Expression}

Resolving a method name at compile time is more complicated than resolving a field name because of the possibility of method overloading. Invoking a method at run time is also more complicated than accessing a field because of the possibility of instance method overriding.

Determining the method that will be invoked by a method invocation expression involves several steps. The following three sections describe the compile-time processing of a method invocation. The determination of the type of the method invocation expression is specified in§15.12.3.

The exception types that a method invocation expression can throw are specified in§11.2.1.

It is a compile-time error if the name to the left of the rightmost "." that occurs before the( in aMethodInvocation cannot be classified as aTypeName or anExpressionName (§6.5.2).

IfTypeArguments is present to the left ofIdentifier, then it is a compile-time error if any of the type arguments are wildcards (§4.5.1).

A method invocation expression is a poly expression if all of the following are true:

  • The invocation appears in an assignment context or an invocation context (§5.2,§5.3).

  • If the invocation is qualified (that is, any form ofMethodInvocation except for the first), then the invocation elidesTypeArguments to the left of theIdentifier.

  • The method to be invoked, as determined by the following subsections, is generic (§8.4.4) and has a return type that mentions at least one of the method's type parameters.

Otherwise, the method invocation expression is a standalone expression.

15.12.1. Compile-Time Step 1: Determine Class or Interface to Search

The first step in processing a method invocation at compile time is to figure out the name of the method to be invoked and which class or interface to search for definitions of methods of that name.

The name of the method is specified by theMethodName orIdentifier which immediately precedes the left parenthesis of theMethodInvocation.

For the class or interface to search, there are six cases to consider, depending on the form that precedes the left parenthesis of theMethodInvocation:

  • If the form isMethodName, that is, just anIdentifier, then:

    If theIdentifier appears in the scope of a visible method declaration with that name (§6.3,§6.4.1), then:

    • If there is an enclosing type declaration of which that method is a member, letT be the innermost such type declaration. The class or interface to search isT.

      This search policy is called the "comb rule". It effectively looks for methods in a nested class's superclass hierarchy before looking for methods in an enclosing class and its superclass hierarchy. See§6.5.7.1 for an example.

    • Otherwise, the visible method declaration may be in scope due to one or more single-static-import or static-import-on-demand declarations. There is no class or interface to search, as the method to be invoked is determined later (§15.12.2.1).

  • If the form isTypeName.[TypeArguments]Identifier, then the type to search is the type denoted byTypeName.

  • If the form isExpressionName.[TypeArguments]Identifier, then the class or interface to search is the declared typeT of the variable denoted byExpressionName ifT is a class or interface type, or the upper bound ofT ifT is a type variable.

  • If the form isPrimary.[TypeArguments]Identifier, then letT be the type of thePrimary expression. The class or interface to search isT ifT is a class or interface type, or the upper bound ofT ifT is a type variable.

    It is a compile-time error ifT is not a reference type.

  • If the form issuper.[TypeArguments]Identifier, then the class to search is the superclass of the class whose declaration contains the method invocation.

    LetT be the type declaration immediately enclosing the method invocation. It is a compile-time error ifT is the classObject orT is an interface.

  • If the form isTypeName.super.[TypeArguments]Identifier, then:

    • It is a compile-time error ifTypeName denotes neither a class nor an interface.

    • IfTypeName denote a class,C, then the class to search is the superclass ofC.

      It is a compile-time error ifC is not a lexically enclosing type declaration of the current class, or ifC is the classObject.

      LetT be the type declaration immediately enclosing the method invocation. It is a compile-time error ifT is the classObject.

    • Otherwise,TypeName denotes the interface to be searched,I.

      LetT be the type declaration immediately enclosing the method invocation. It is a compile-time error ifI is not a direct superinterface ofT, or if there exists some other direct superclass or direct superinterface ofT,J, such thatJ is a subtype ofI.

TheTypeName.super syntax is overloaded: traditionally, theTypeName refers to a lexically enclosing type declaration which is a class, and the target is the superclass of this class, as if the invocation were an unqualifiedsuper in the lexically enclosing type declaration.

class Superclass {    void foo() { System.out.println("Hi"); }}class Subclass1 extends Superclass {    void foo() { throw new UnsupportedOperationException(); }    Runnable tweak = new Runnable() {        void run() {            Subclass1.super.foo();  // Gets the 'println' behavior        }    };}

To support invocation of default methods in superinterfaces, theTypeName may also refer to a direct superinterface of the current class or interface, and the target is that superinterface.

interface Superinterface {    default void foo() { System.out.println("Hi"); }}class Subclass2 implements Superinterface {    void foo() { throw new UnsupportedOperationException(); }    void tweak() {        Superinterface.super.foo();  // Gets the 'println' behavior    }}

No syntax supports a combination of these forms, that is, invoking a superinterface method of a lexically enclosing type declaration which is a class, as if the invocation were of the formInterfaceName.super in the lexically enclosing type declaration.

class Subclass3 implements Superinterface {    void foo() { throw new UnsupportedOperationException(); }    Runnable tweak = new Runnable() {        void run() {            Subclass3.Superinterface.super.foo();  // Illegal        }    };}

A workaround is to introduce aprivate method in the lexically enclosing type declaration, that performs the interfacesuper call.

15.12.2. Compile-Time Step 2: Determine Method Signature

The second step searches the type determined in the previous step for member methods. This step uses the name of the method and the argument expressions to locate methods that are bothaccessible andapplicable, that is, declarations that can be correctly invoked on the given arguments.

There may be more than one such method, in which case themost specific one is chosen. The descriptor (signature plus return type) of the most specific method is the one used at run time to perform the method dispatch.

A method isapplicable if it is applicable by one of strict invocation (§15.12.2.2), loose invocation (§15.12.2.3), or variable arity invocation (§15.12.2.4).

Certain argument expressions that contain implicitly typed lambda expressions (§15.27.1) or inexact method references (§15.13.1) are ignored by the applicability tests, because their meaning cannot be determined until a target type is selected.

Although the method invocation may be a poly expression, only its argument expressions -not the invocation's target type - influence the selection of applicable methods.

The process of determining applicability begins by determining the potentially applicable methods (§15.12.2.1).

The remainder of the process is split into three phases, to ensure compatibility with versions of the Java programming language prior to Java SE 5.0. The phases are:

  1. The first phase (§15.12.2.2) performs overload resolution without permitting boxing or unboxing conversion, or the use of variable arity method invocation. If no applicable method is found during this phase then processing continues to the second phase.

    This guarantees that any calls that were valid in the Java programming language before Java SE 5.0 are not considered ambiguous as the result of the introduction of variable arity methods, implicit boxing and/or unboxing. However, the declaration of a variable arity method (§8.4.1) can change the method chosen for a given method method invocation expression, because a variable arity method is treated as a fixed arity method in the first phase. For example, declaringm(Object...) in a class which already declaresm(Object) causesm(Object) to no longer be chosen for some invocation expressions (such asm(null)), asm(Object[]) is more specific.

  2. The second phase (§15.12.2.3) performs overload resolution while allowing boxing and unboxing, but still precludes the use of variable arity method invocation. If no applicable method is found during this phase then processing continues to the third phase.

    This ensures that a method is never chosen through variable arity method invocation if it is applicable through fixed arity method invocation.

  3. The third phase (§15.12.2.4) allows overloading to be combined with variable arity methods, boxing, and unboxing.

Deciding whether a method is applicable will, in the case of generic methods (§8.4.4), require an analysis of the type arguments. Type arguments may be passed explicitly or implicitly. If they are passed implicitly, bounds of the type arguments must be inferred (§18 (Type Inference)) from the argument expressions.

If several applicable methods have been identified during one of the three phases of applicability testing, then the most specific one is chosen, as specified in section§15.12.2.5.

To check for applicability, the types of an invocation's arguments cannot, in general, be inputs to the analysis. This is because:

  • The arguments to a method invocation may be poly expressions

  • Poly expressions cannot be typed in the absence of a target type

  • Overload resolution has to be completed before the arguments' target types will be known

Instead, the input to the applicability check is a list of argument expressions, whichcan be checked for compatibility with potential target types, even if the ultimate types of the expressions are unknown.

Note that overload resolution is independent of a target type. This is for two reasons:

  • First, it makes the user model more accessible and less error-prone. The meaning of a method name (i.e., the declaration corresponding to the name) is too fundamental to the meaning of a program to depend on subtle contextual hints. (In contrast, other poly expressions may have different behavior depending on a target type; but the variation in behavior is always limited and essentially equivalent, while no such guarantees can be made about the behavior of an arbitrary set of methods that share a name and arity.)

  • Second, it allows other properties - such as whether or not the method is a poly expression (§15.12) or how to categorize a conditional expression (§15.25) - to depend on the meaning of the method name, even before a target type is known.

Example 15.12.2-1. Method Applicability

class Doubler {            static int two()      { return two(1); }    private static int two(int i) { return 2*i;    }}class Test extends Doubler {    static long two(long j) { return j+j; }    public static void main(String[] args) {        System.out.println(two(3));        System.out.println(Doubler.two(3)); // compile-time error    }}

For the method invocationtwo(1) within classDoubler, there are two accessible methods namedtwo, but only the second one is applicable, and so that is the one invoked at run time.

For the method invocationtwo(3) within classTest, there are two applicable methods, but only the one in classTest is accessible, and so that is the one to be invoked at run time (the argument3 is converted to typelong).

For the method invocationDoubler.two(3), the classDoubler, not classTest, is searched for methods namedtwo; the only applicable method is not accessible, and so this method invocation causes a compile-time error.

Another example is:

class ColoredPoint {    int x, y;    byte color;    void setColor(byte color) { this.color = color; }}class Test {    public static void main(String[] args) {        ColoredPoint cp = new ColoredPoint();        byte color = 37;        cp.setColor(color);        cp.setColor(37);  // compile-time error    }}

Here, a compile-time error occurs for the second invocation ofsetColor, because no applicable method can be found at compile time. The type of the literal37 isint, andint cannot be converted tobyte by invocation conversion. Assignment conversion, which is used in the initialization of the variablecolor, performs an implicit conversion of the constant from typeint tobyte, which is permitted because the value37 is small enough to be represented in typebyte; but such a conversion is not allowed for invocation conversion.

If the methodsetColor had, however, been declared to take anint instead of abyte, then both method invocations would be correct; the first invocation would be allowed because invocation conversion does permit a widening conversion frombyte toint. However, a narrowing cast would then be required in the body ofsetColor:

void setColor(int color) { this.color = (byte)color; }

Here is an example of overloading ambiguity. Consider the program:

class Point { int x, y; }class ColoredPoint extends Point { int color; }class Test {    static void test(ColoredPoint p, Point q) {        System.out.println("(ColoredPoint, Point)");    }    static void test(Point p, ColoredPoint q) {        System.out.println("(Point, ColoredPoint)");    }    public static void main(String[] args) {        ColoredPoint cp = new ColoredPoint();        test(cp, cp);  // compile-time error    }}

This example produces an error at compile time. The problem is that there are two declarations oftest that are applicable and accessible, and neither is more specific than the other. Therefore, the method invocation is ambiguous.

If a third definition oftest were added:

static void test(ColoredPoint p, ColoredPoint q) {    System.out.println("(ColoredPoint, ColoredPoint)");}

then it would be more specific than the other two, and the method invocation would no longer be ambiguous.


Example 15.12.2-2. Return Type Not Considered During Method Selection

class Point { int x, y; }class ColoredPoint extends Point { int color; }class Test {    static int test(ColoredPoint p) {        return p.color;    }    static String test(Point p) {        return "Point";    }    public static void main(String[] args) {        ColoredPoint cp = new ColoredPoint();        String s = test(cp);  // compile-time error    }}

Here, the most specific declaration of methodtest is the one taking a parameter of typeColoredPoint. Because the result type of the method isint, a compile-time error occurs because anint cannot be converted to aString by assignment conversion. This example shows that the result types of methods do not participate in resolving overloaded methods, so that the secondtest method, which returns aString, is not chosen, even though it has a result type that would allow the example program to compile without error.


Example 15.12.2-3. Choosing The Most Specific Method

The most specific method is chosen at compile time; its descriptor determines what method is actually executed at run time. If a new method is added to a class, then source code that was compiled with the old definition of the class might not use the new method, even if a recompilation would cause this method to be chosen.

So, for example, consider two compilation units, one for classPoint:

package points;public class Point {    public int x, y;    public Point(int x, int y) { this.x = x; this.y = y; }    public String toString() { return toString(""); }    public String toString(String s) {        return "(" + x + "," + y + s + ")";    }}

and one for classColoredPoint:

package points;public class ColoredPoint extends Point {    public static final int        RED = 0, GREEN = 1, BLUE = 2;    public static String[] COLORS =        { "red", "green", "blue" };    public byte color;    public ColoredPoint(int x, int y, int color) {        super(x, y);        this.color = (byte)color;    }    /** Copy all relevant fields of the argument into        this ColoredPoint object. */    public void adopt(Point p) { x = p.x; y = p.y; }    public String toString() {        String s = "," + COLORS[color];        return super.toString(s);    }}

Now consider a third compilation unit that usesColoredPoint:

import points.*;class Test {    public static void main(String[] args) {        ColoredPoint cp =            new ColoredPoint(6, 6, ColoredPoint.RED);        ColoredPoint cp2 =            new ColoredPoint(3, 3, ColoredPoint.GREEN);        cp.adopt(cp2);        System.out.println("cp: " + cp);    }}

The output is:

cp: (3,3,red)

The programmer who coded classTest has expected to see the wordgreen, because the actual argument, aColoredPoint, has acolor field, andcolor would seem to be a "relevant field". (Of course, the documentation for the packagepoints ought to have been much more precise!)

Notice, by the way, that the most specific method (indeed, the only applicable method) for the method invocation ofadopt has a signature that indicates a method of one parameter, and the parameter is of typePoint. This signature becomes part of the binary representation of classTest produced by the Java compiler and is used by the method invocation at run time.

Suppose the programmer reported this software error and the maintainer of thepoints package decided, after due deliberation, to correct it by adding a method to classColoredPoint:

public void adopt(ColoredPoint p) {    adopt((Point)p);    color = p.color;}

If the programmer then runs the old binary file forTest with the new binary file forColoredPoint, the output is still:

cp: (3,3,red)

because the old binary file forTest still has the descriptor "one parameter, whose type isPoint;void" associated with the method callcp.adopt(cp2). If the source code forTest is recompiled, the Java compiler will then discover that there are now two applicableadopt methods, and that the signature for the more specific one is "one parameter, whose type isColoredPoint;void"; running the program will then produce the desired output:

cp: (3,3,green)

With forethought about such problems, the maintainer of thepoints package could fix theColoredPoint class to work with both newly compiled and old code, by adding defensive code to the oldadopt method for the sake of old code that still invokes it onColoredPoint arguments:

public void adopt(Point p) {    if (p instanceof ColoredPoint)        color = ((ColoredPoint)p).color;    x = p.x; y = p.y;}

Ideally, source code should be recompiled whenever code that it depends on is changed. However, in an environment where different classes are maintained by different organizations, this is not always feasible. Defensive programming with careful attention to the problems of class evolution can make upgraded code much more robust. See§13 (Binary Compatibility) for a detailed discussion of binary compatibility and type evolution.


15.12.2.1. Identify Potentially Applicable Methods

The class or interface determined by compile-time step 1 (§15.12.1) is searched for all member methods that are potentially applicable to this method invocation; members inherited from superclasses and superinterfaces are included in this search.

In addition, if the form of the method invocation expression isMethodName - that is, a singleIdentifier - then the search for potentially applicable methods also examines all member methods that are imported by single-static-import declarations and static-import-on-demand declarations of the compilation unit where the method invocation occurs (§7.5.3,§7.5.4) and that are not shadowed at the point where the method invocation appears.

A member method ispotentially applicable to a method invocation if and only if all of the following are true:

  • The name of the member is identical to the name of the method in the method invocation.

  • The member is accessible (§6.6) to the class or interface in which the method invocation appears.

    Whether a member method is accessible at a method invocation depends on the access modifier (public,protected, no modifier (package access), orprivate) in the member's declaration and on where the method invocation appears.

  • If the member is a fixed arity method with arityn, the arity of the method invocation is equal ton, and for alli (1in), thei'th argument of the method invocation ispotentially compatible, as defined below, with the type of thei'th parameter of the method.

  • If the member is a variable arity method with arityn, then for alli (1in-1), thei'th argument of the method invocation ispotentially compatible with the type of thei'th parameter of the method; and, where thenth parameter of the method has typeT[], one of the following is true:

    • The arity of the method invocation is equal ton-1.

    • The arity of the method invocation is equal ton, and thenth argument of the method invocation is potentially compatible with eitherT orT[].

    • The arity of the method invocation ism, wherem >n, and for alli (nim), thei'th argument of the method invocation is potentially compatible withT.

  • If the method invocation includes explicit type arguments, and the member is a generic method, then the number of type arguments is equal to the number of type parameters of the method.

    This clause implies that a non-generic method may be potentially applicable to an invocation that supplies explicit type arguments. Indeed, it may turn out to be applicable. In such a case, the type arguments will simply be ignored.

    This rule stems from issues of compatibility and principles of substitutability. Since interfaces or superclasses may be generified independently of their subtypes, we may override a generic method with a non-generic one. However, the overriding (non-generic) method must be applicable to calls to the generic method, including calls that explicitly pass type arguments. Otherwise the subtype would not be substitutable for its generified supertype.

If the search does not yield at least one method that is potentially applicable, then a compile-time error occurs.

An expression ispotentially compatible with a target type according to the following rules:

  • A lambda expression (§15.27) is potentially compatible with a functional interface type (§9.8) if all of the following are true:

    • The arity of the target type's function type is the same as the arity of the lambda expression.

    • If the target type's function type has avoid return, then the lambda body is either a statement expression (§14.8) or a void-compatible block (§15.27.2).

    • If the target type's function type has a (non-void) return type, then the lambda body is either an expression or a value-compatible block (§15.27.2).

  • A method reference expression (§15.13) is potentially compatible with a functional interface type if, where the type's function type arity isn, there exists at least one potentially applicable method for the method reference expression with arityn (§15.13.1), and one of the following is true:

    • The method reference expression has the formReferenceType::[TypeArguments]Identifier and at least one potentially applicable method is i)static and supports arityn, or ii) notstatic and supports arityn-1.

    • The method reference expression has some other form and at least one potentially applicable method is notstatic.

  • A lambda expression or a method reference expression is potentially compatible with a type variable if the type variable is a type parameter of the candidate method.

  • A parenthesized expression (§15.8.5) is potentially compatible with a type if its contained expression is potentially compatible with that type.

  • A conditional expression (§15.25) is potentially compatible with a type if each of its second and third operand expressions are potentially compatible with that type.

  • A class instance creation expression, a method invocation expression, or an expression of a standalone form (§15.2) is potentially compatible with any type.

The definition of potential applicability goes beyond a basic arity check to also take into account the presence and "shape" of functional interface target types. In some cases involving type argument inference, a lambda expression appearing as a method invocation argument cannot be properly typed until after overload resolution. These rules allow the form of the lambda expression to still be taken into account, discarding obviously incorrect target types that might otherwise cause ambiguity errors.

15.12.2.2. Phase 1: Identify Matching Arity Methods Applicable by Strict Invocation

An argument expression is consideredpertinent to applicability for a potentially applicable methodm unless it has one of the following forms:

  • An implicitly typed lambda expression (§15.27.1).

  • An inexact method reference expression (§15.13.1).

  • Ifm is a generic method and the method invocation does not provide explicit type arguments, an explicitly typed lambda expression or an exact method reference expression for which the corresponding target type (as derived from the signature ofm) is a type parameter ofm.

  • An explicitly typed lambda expression whose body is an expression that is not pertinent to applicability.

  • An explicitly typed lambda expression whose body is a block, where at least one result expression is not pertinent to applicability.

  • A parenthesized expression (§15.8.5) whose contained expression is not pertinent to applicability.

  • A conditional expression (§15.25) whose second or third operand is not pertinent to applicability.

Letm be a potentially applicable method (§15.12.2.1) with arityn and formal parameter typesF1 ...Fn, and lete1, ...,en be the actual argument expressions of the method invocation. Then:

  • Ifm is a generic method and the method invocation does not provide explicit type arguments, then the applicability of the method is inferred as specified in§18.5.1.

  • Ifm is a generic method and the method invocation provides explicit type arguments, then letR1 ...Rp (p 1) be the type parameters ofm, letBl be the declared bound ofRl (1lp), and letU1, ...,Up be the explicit type arguments given in the method invocation. Thenm isapplicable by strict invocation if both of the following are true:

    • For 1in, ifei is pertinent to applicability thenei is compatible in a strict invocation context withFi[R1:=U1, ...,Rp:=Up].

    • For 1lp,Ul<:Bl[R1:=U1, ...,Rp:=Up].

  • Ifm is not a generic method, thenm isapplicable by strict invocation if, for 1in, eitherei is compatible in a strict invocation context withFi orei is not pertinent to applicability.

If no method applicable by strict invocation is found, the search for applicable methods continues with phase 2 (§15.12.2.3).

Otherwise, the most specific method (§15.12.2.5) is chosen among the methods that are applicable by strict invocation.

The meaning of an implicitly typed lambda expression or an inexact method reference expression is sufficiently vague prior to resolving a target type that arguments containing these expressions are not consideredpertinent to applicability; they are simply ignored (except for their expected arity) until overload resolution is finished.

15.12.2.3. Phase 2: Identify Matching Arity Methods Applicable by Loose Invocation

Letm be a potentially applicable method (§15.12.2.1) with arityn and formal parameter typesF1, ...,Fn, and lete1, ...,en be the actual argument expressions of the method invocation. Then:

  • Ifm is a generic method and the method invocation does not provide explicit type arguments, then the applicability of the method is inferred as specified in§18.5.1.

  • Ifm is a generic method and the method invocation provides explicit type arguments, then letR1 ...Rp (p 1) be the type parameters ofm, letBl be the declared bound ofRl (1lp), and letU1 ...Up be the explicit type arguments given in the method invocation. Thenm isapplicable by loose invocation if both of the following are true:

    • For 1in, ifei is pertinent to applicability (§15.12.2.2) thenei is compatible in a loose invocation context withFi[R1:=U1, ...,Rp:=Up].

    • For 1lp,Ul<:Bl[R1:=U1, ...,Rp:=Up].

  • Ifm is not a generic method, thenm isapplicable by loose invocation if, for 1in, eitherei is compatible in a loose invocation context withFi orei is not pertinent to applicability.

If no method applicable by loose invocation is found, the search for applicable methods continues with phase 3 (§15.12.2.4).

Otherwise, the most specific method (§15.12.2.5) is chosen among the methods that are applicable by loose invocation.

15.12.2.4. Phase 3: Identify Methods Applicable by Variable Arity Invocation

Where a variable arity method has formal parameter typesF1, ...,Fn-1,Fn[], let thei'thvariable arity parameter type of the method be defined as follows:

  • Forin-1, thei'th variable arity parameter type isFi.

  • Forin, thei'th variable arity parameter type isFn.

Letm be a potentially applicable method (§15.12.2.1) with variable arity, letT1, ...,Tk be the firstk variable arity parameter types ofm, and lete1, ...,ek be the actual argument expressions of the method invocation. Then:

  • Ifm is a generic method and the method invocation does not provide explicit type arguments, then the applicability of the method is inferred as specified in§18.5.1.

  • Ifm is a generic method and the method invocation provides explicit type arguments, then letR1 ...Rp (p 1) be the type parameters ofm, letBl be the declared bound ofRl (1lp), and letU1 ...Up be the explicit type arguments given in the method invocation. Thenm isapplicable by variable arity invocation if:

    • For 1ik, ifei is pertinent to applicability (§15.12.2.2) thenei is compatible in a loose invocation context withTi[R1:=U1, ...,Rp:=Up].

    • For 1lp,Ul<:Bl[R1:=U1, ...,Rp:=Up].

  • Ifm is not a generic method, thenm isapplicable by variable arity invocation if, for 1ik, eitherei is compatible in a loose invocation context withTi orei is not pertinent to applicability.

If no method applicable by variable arity invocation is found, then a compile-time error occurs.

Otherwise, the most specific method (§15.12.2.5) is chosen among the methods applicable by variable arity invocation.

15.12.2.5. Choosing the Most Specific Method

If more than one member method is both accessible and applicable to a method invocation, it is necessary to choose one to provide the descriptor for the run-time method dispatch. The Java programming language uses the rule that themost specific method is chosen.

The informal intuition is that one method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time error. In cases such as an explicitly typed lambda expression argument (§15.27.1) or a variable arity invocation (§15.12.2.4), some flexibility is allowed to adapt one signature to the other.

One applicable methodm1 ismore specific than another applicable methodm2, for an invocation with argument expressionse1, ...,ek, if any of the following are true:

  • m2 is generic, andm1 is inferred to be more specific thanm2 for argument expressionse1, ...,ek by§18.5.4.

  • m2 is not generic, andm1 andm2 are applicable by strict or loose invocation, and wherem1 has formal parameter typesS1, ...,Sn andm2 has formal parameter typesT1, ...,Tn, the typeSi ismore specific thanTi for argumentei for alli (1in,n =k).

  • m2 is not generic, andm1 andm2 are applicable by variable arity invocation, and where the firstk variable arity parameter types ofm1 areS1, ...,Sk and the firstk variable arity parameter types ofm2 areT1, ...,Tk, the typeSi ismore specific thanTi for argumentei for alli (1ik). Additionally, ifm2 hask+1 parameters, then thek+1'th variable arity parameter type ofm1 is a subtype of thek+1'th variable arity parameter type ofm2.

The above conditions are the only circumstances under which one method may be more specific than another.

A typeS ismore specific than a typeT forany expression ifS<:T (§4.10).

A functional interface typeS ismore specific than a functional interface typeT for an expressione ifT is not a subtype ofS and one of the following is true (whereU1 ...Uk andR1 are the parameter types and return type of the function type of the capture ofS, andV1 ...Vk andR2 are the parameter types and return type of the function type ofT):

  • Ife is an explicitly typed lambda expression (§15.27.1), then one of the following is true:

    • R2 isvoid.

    • R1<:R2.

    • R1 andR2 are functional interface types, and there is at least one result expression, andR1 is more specific thanR2 for each result expression ofe.

      (The result expression of a lambda expression with a block body is defined in§15.27.2; the result expression of a lambda expression with an expression body is simply the body itself.)

    • R1 is a primitive type, andR2 is a reference type, and there is at least one result expression, and each result expression ofe is a standalone expression (§15.2) of a primitive type.

    • R1 is a reference type, andR2 is a primitive type, and there is at least one result expression, and each result expression ofe is either a standalone expression of a reference type or a poly expression.

  • Ife is an exact method reference expression (§15.13.1), then i) for alli (1ik),Ui is the same asVi, and ii) one of the following is true:

    • R2 isvoid.

    • R1<:R2.

    • R1 is a primitive type,R2 is a reference type, and the compile-time declaration for the method reference has a return type which is a primitive type.

    • R1 is a reference type,R2 is a primitive type, and the compile-time declaration for the method reference has a return type which is a reference type.

  • Ife is a parenthesized expression, then one of these conditions applies recursively to the contained expression.

  • Ife is a conditional expression, then for each of the second and third operands, one of these conditions applies recursively.

A methodm1 isstrictly more specific than another methodm2 if and only ifm1 is more specific thanm2 andm2 is not more specific thanm1.

A method is said to bemaximally specific for a method invocation if it is accessible and applicable and there is no other method that is applicable and accessible that is strictly more specific.

If there is exactly one maximally specific method, then that method is in fact themost specific method; it is necessarily more specific than any other accessible method that is applicable. It is then subjected to some further compile-time checks as specified in§15.12.3.

It is possible that no method is the most specific, because there are two or more methods that are maximally specific. In this case:

  • If all the maximally specific methods have override-equivalent signatures (§8.4.2), then:

    • If exactly one of the maximally specific methods is concrete (that is, non-abstract or default), it is the most specific method.

    • Otherwise, if all the maximally specific methods areabstract or default, and the signatures of all of the maximally specific methods have the same erasure (§4.6), then the most specific method is chosen arbitrarily among the subset of the maximally specific methods that have the most specific return type.

      In this case, the most specific method is considered to beabstract. Also, the most specific method is considered to throw a checked exception if and only if that exception or its erasure is declared in thethrows clauses of each of the maximally specific methods.

  • Otherwise, the method invocation isambiguous, and a compile-time error occurs.

15.12.2.6. Method Invocation Type

Theinvocation type of a most specific accessible and applicable method is a method type (§8.2) expressing the target types of the invocation arguments, the result (return type orvoid) of the invocation, and the exception types of the invocation. It is determined as follows:

  • If the chosen method is generic and the method invocation does not provide explicit type arguments, the invocation type is inferred as specified in§18.5.2.

  • If the chosen method is generic and the method invocation provides explicit type arguments, letPi be the type parameters of the method and letTi be the explicit type arguments provided for the method invocation (1ip). Then:

    • If unchecked conversion was necessary for the method to be applicable, then the invocation type's parameter types are obtained by applying the substitution[P1:=T1, ...,Pp:=Tp] to the parameter types of the method's type, and the invocation type's return type and thrown types are given by the erasure of the return type and thrown types of the method's type.

    • If unchecked conversion was not necessary for the method to be applicable, then the invocation type is obtained by applying the substitution[P1:=T1, ...,Pp:=Tp] to the method's type.

  • If the chosen method is not generic, then:

    • If unchecked conversion was necessary for the method to be applicable, the parameter types of the invocation type are the parameter types of the method's type, and the return type and thrown types are given by the erasures of the return type and thrown types of the method's type.

    • Otherwise, if the chosen method is thegetClass method of the classObject (§4.3.2), the invocation type is the same as the method's type, except that the return type isClass<?extends |T|>, whereT is the type that was searched, as determined by§15.12.1, and |T| denotes the erasure ofT (§4.6).

    • Otherwise, the invocation type is the same as the method's type.

15.12.3. Compile-Time Step 3: Is the Chosen Method Appropriate?

If there is a most specific method declaration for a method invocation, it is called thecompile-time declaration for the method invocation.

It is a compile-time error if an argument to a method invocation is not compatible with its target type, as derived from the invocation type of the compile-time declaration.

If the compile-time declaration is applicable by variable arity invocation, then where the last formal parameter type of the invocation type of the method isFn[], it is a compile-time error if the type which is the erasure ofFn is not accessible at the point of invocation.

If the compile-time declaration isvoid, then the method invocation must be a top level expression (that is, theExpression in an expression statement or in theForInit orForUpdate part of afor statement), or a compile-time error occurs. Such a method invocation produces no value and so must be used only in a situation where a value is not needed.

In addition, whether the compile-time declaration is appropriate may depend on the form of the method invocation expression before the left parenthesis, as follows:

  • If the form isMethodName - that is, just anIdentifier - and the compile-time declaration is an instance method, then:

    • It is a compile-time error if the method invocation occurs in a static context (§8.1.3).

    • Otherwise, letC be the immediately enclosing class of which the compile-time declaration is a member. If the method invocation is not directly enclosed byC or an inner class ofC, then a compile-time error occurs.

  • If the form isTypeName.[TypeArguments]Identifier, then the compile-time declaration must bestatic, or a compile-time error occurs.

  • If the form isExpressionName.[TypeArguments]Identifier orPrimary.[TypeArguments]Identifier, then the compile-time declaration must not be astatic method declared in an interface, or a compile-time error occurs.

  • If the form issuper.[TypeArguments]Identifier, then:

    • It is a compile-time error if the compile-time declaration isabstract.

    • It is a compile-time error if the method invocation occurs in a static context.

  • If the form isTypeName.super.[TypeArguments]Identifier, then:

    • It is a compile-time error if the compile-time declaration isabstract.

    • It is a compile-time error if the method invocation occurs in a static context.

    • IfTypeName denotes a classC, then if the method invocation is not directly enclosed byC or an inner class ofC, a compile-time error occurs.

    • IfTypeName denotes an interface, letT be the type declaration immediately enclosing the method invocation. A compile-time error occurs if there exists a method, distinct from the compile-time declaration, that overrides (§9.4.1) the compile-time declaration from a direct superclass or direct superinterface ofT.

      In the case that a superinterface overrides a method declared in a grandparent interface, this rule prevents the child interface from "skipping" the override by simply adding the grandparent to its list of direct superinterfaces. The appropriate way to access functionality of a grandparent is through the direct superinterface, and only if that interface chooses to expose the desired behavior. (Alternately, the developer is free to define his own additional superinterface that exposes the desired behavior with asuper method invocation.)

Thecompile-time parameter types andcompile-time result are determined as follows:

  • If the compile-time declaration for the method invocation isnot a signature polymorphic method, then the compile-time parameter types are the types of the formal parameters of the compile-time declaration, and the compile-time result is the result chosen for the compile-time declaration (§15.12.2.6).

  • If the compile-time declaration for the method invocation is a signature polymorphic method, then:

    • The compile-time parameter types are the static types of the actual argument expressions. An argument expression which is the null literalnull (§3.10.7) is treated as having the static typeVoid.

    • The compile-time result is determined as follows:

      • If the method invocation expression is an expression statement, the compile-time result isvoid.

      • Otherwise, if the method invocation expression is the operand of a cast expression (§15.16), the compile-time result is the erasure of the type of the cast expression (§4.6).

      • Otherwise, the compile-time result is the signature polymorphic method's declared return type,Object.

A method issignature polymorphic if all of the following are true:

  • It is declared in thejava.lang.invoke.MethodHandle class.

  • It takes a single variable arity parameter (§8.4.1) whose declared type isObject[].

  • It has a return type ofObject.

  • It isnative.

In Java SE 8, the only signature polymorphic methods are theinvoke andinvokeExact methods of the classjava.lang.invoke.MethodHandle.

The following compile-time information is then associated with the method invocation for use at run time:

  • The name of the method.

  • The qualifying type of the method invocation (§13.1).

  • The number of parameters and the compile-time parameter types, in order.

  • The compile-time result, orvoid.

  • The invocation mode, computed as follows:

    • If the qualifying type of the method declaration is a class, then:

      • If the compile-time declaration has thestatic modifier, then the invocation mode isstatic.

      • Otherwise, if the compile-time declaration has theprivate modifier, then the invocation mode isnonvirtual.

      • Otherwise, if the part of the method invocation before the left parenthesis is of the formsuper.Identifier or of the formTypeName.super.Identifier, then the invocation mode issuper.

      • Otherwise, the invocation mode isvirtual.

    • If the qualifying type of the method invocation is an interface, then the invocation mode isinterface.

If the result of the invocation type of the compile-time declaration is notvoid, then the type of the method invocation expression is obtained by applying capture conversion (§5.1.10) to the return type of the invocation type of the compile-time declaration.

15.12.4. Run-Time Evaluation of Method Invocation

At run time, method invocation requires five steps. First, atarget reference may be computed. Second, the argument expressions are evaluated. Third, the accessibility of the method to be invoked is checked. Fourth, the actual code for the method to be executed is located. Fifth, a new activation frame is created, synchronization is performed if necessary, and control is transferred to the method code.

15.12.4.1. Compute Target Reference (If Necessary)

There are six cases to consider, depending on the form of the method invocation:

  • If the form isMethodName - that is, just anIdentifier - then:

    • If the invocation mode isstatic, then there is no target reference.

    • Otherwise, letT be the enclosing type declaration of which the method is a member, and letn be an integer such thatT is then'th lexically enclosing type declaration of the class whose declaration immediately contains the method invocation. The target reference is then'th lexically enclosing instance ofthis.

      It is a compile-time error if then'th lexically enclosing instance ofthis does not exist.

  • If the form isTypeName.[TypeArguments]Identifier, then there is no target reference.

  • If form isExpressionName.[TypeArguments]Identifier, then:

    • If the invocation mode isstatic, then there is no target reference. TheExpressionName is evaluated, but the result is then discarded.

    • Otherwise, the target reference is the value denoted byExpressionName.

  • If the form isPrimary.[TypeArguments]Identifier involved, then:

    • If the invocation mode isstatic, then there is no target reference. ThePrimary expression is evaluated, but the result is then discarded.

    • Otherwise, thePrimary expression is evaluated and the result is used as the target reference.

    In either case, if the evaluation of thePrimary expression completes abruptly, then no part of any argument expression appears to have been evaluated, and the method invocation completes abruptly for the same reason.

  • If the form issuper.[TypeArguments]Identifier, then the target reference is the value ofthis.

  • If the form isTypeName.super.[TypeArguments]Identifier, then ifTypeName denotes a class, the target reference is the value ofTypeName.this; otherwise, the target reference is the value ofthis.

Example 15.12.4.1-1. Target References andstatic Methods

When a target reference is computed and then discarded because the invocation mode isstatic, the reference is not examined to see whether it isnull:

class Test1 {    static void mountain() {        System.out.println("Monadnock");    }    static Test1 favorite(){        System.out.print("Mount ");        return null;    }    public static void main(String[] args) {        favorite().mountain();    }}

which prints:

Mount Monadnock

Herefavorite() returnsnull, yet noNullPointerException is thrown.


Example 15.12.4.1-2. Evaluation Order During Method Invocation

As part of an instance method invocation (§15.12), there is an expression that denotes the object to be invoked. This expression appears to be fully evaluated before any part of any argument expression to the method invocation is evaluated.

So, for example, in:

class Test2 {    public static void main(String[] args) {        String s = "one";        if (s.startsWith(s = "two"))            System.out.println("oops");    }}

the occurrence ofs before ".startsWith" is evaluated first, before the argument expressions = "two". Therefore, a reference to the string"one" is remembered as the target reference before the local variables is changed to refer to the string"two". As a result, thestartsWith method is invoked for target object"one" with argument"two", so the result of the invocation isfalse, as the string"one" does not start with"two". It follows that the test program does not print "oops".


15.12.4.2. Evaluate Arguments

The process of evaluating the argument list differs, depending on whether the method being invoked is a fixed arity method or a variable arity method (§8.4.1).

If the method being invoked is a variable arity methodm, it necessarily hasn > 0 formal parameters. The final formal parameter ofm necessarily has typeT[] for someT, andm is necessarily being invoked withk 0 actual argument expressions.

Ifm is being invoked withkn actual argument expressions, or, ifm is being invoked withk =n actual argument expressions and the type of thek'th argument expression is not assignment compatible withT[], then the argument list (e1, ...,en-1,en, ...,ek) is evaluated as if it were written as (e1, ...,en-1,new |T[]|{en, ...,ek}), where |T[]| denotes the erasure (§4.6) ofT[].

The preceding paragraph is crafted to handle the interaction of parameterized types and array types that occurs in a Java Virtual Machine with erased generics. Namely, if the element typeT of the variable array parameter is non-reifiable, e.g.List<String>, then special care must be taken with the array creation expression (§15.10) because the created array's element type must be reifiable. By erasing the array type of the final expression in the argument list, we are guaranteed to obtain a reifiable element type. Then, since the array creation expression appears in an invocation context (§5.3), an unchecked conversion is possible from the array type with reifiable element type to an array type with non-reifiable element type, specifically that of the variable arity parameter. A Java compiler is required to give a compile-time unchecked warning at this conversion. Oracle's reference implementation of a Java compiler identifies the unchecked warning here as a more informativeunchecked generic array creation.

The argument expressions (possibly rewritten as described above) are now evaluated to yieldargument values. Each argument value corresponds to exactly one of the method'sn formal parameters.

The argument expressions, if any, are evaluated in order, from left to right. If the evaluation of any argument expression completes abruptly, then no part of any argument expression to its right appears to have been evaluated, and the method invocation completes abruptly for the same reason. The result of evaluating thej'th argument expression is thej'th argument value, for 1jn. Evaluation then continues, using the argument values, as described below.

15.12.4.3. Check Accessibility of Type and Method

LetC be the class containing the method invocation, and letT be the qualifying type of the method invocation (§13.1), and letm be the name of the method as determined at compile time (§15.12.3).

An implementation of the Java programming language must ensure, as part of linkage, that the methodm still exists in the typeT. If this is not true, then aNoSuchMethodError (which is a subclass ofIncompatibleClassChangeError) occurs.

If the invocation mode isinterface, then the implementation must also check that the target reference type still implements the specified interface. If the target reference type does not still implement the interface, then anIncompatibleClassChangeError occurs.

The implementation must also ensure, during linkage, that the typeT and the methodm are accessible:

  • For the typeT:

    • IfT is in the same package asC, thenT is accessible.

    • IfT is in a different package thanC, andT ispublic, thenT is accessible.

    • IfT is in a different package thanC, andT isprotected, thenT is accessible if and only ifC is a subclass ofT.

  • For the methodm:

    • Ifm ispublic, thenm is accessible. (All members of interfaces arepublic (§9.2).)

    • Ifm isprotected, thenm is accessible if and only if eitherT is in the same package asC, orC isT or a subclass ofT.

    • Ifm has package access, thenm is accessible if and only ifT is in the same package asC.

    • Ifm isprivate, thenm is accessible if and only ifC isT, orC enclosesT, orT enclosesC, orT andC are both enclosed by a third class.

If eitherT orm is not accessible, then anIllegalAccessError occurs (§12.3).

15.12.4.4. Locate Method to Invoke

The strategy for method lookup depends on the invocation mode.

If the invocation mode isstatic, no target reference is needed and overriding is not allowed. Methodm of classT is the one to be invoked.

Otherwise, an instance method is to be invoked and there is a target reference. If the target reference isnull, aNullPointerException is thrown at this point. Otherwise, the target reference is said to refer to atarget object and will be used as the value of the keywordthis in the invoked method. The other four possibilities for the invocation mode are then considered.

If the invocation mode isnonvirtual, overriding is not allowed. Methodm of classT is the one to be invoked.

Otherwise, if the invocation mode isvirtual, andT andm jointly indicate a signature polymorphic method (§15.12.3), then the target object is an instance ofjava.lang.invoke.MethodHandle. The method handle encapsulates atype which is matched against the information associated with the method invocation at compile time (§15.12.3). Details of this matching are given inThe Java Virtual Machine Specification, Java SE 8 Edition and the Java SE platform API. If matching succeeds, thetarget method encapsulated by the method handle is directly and immediately invoked,and the procedure in§15.12.4.5 is not executed.

Otherwise, the invocation mode isinterface,virtual, orsuper, and overriding may occur. Adynamic method lookup is used. The dynamic lookup process starts from a classS, determined as follows:

  • If the invocation mode isinterface orvirtual, thenS is initially the actual run-time classR of the target object.

    This is true even if the target object is an array instance. (Note that for invocation modeinterface,R necessarily implementsT; for invocation modevirtual,R is necessarily eitherT or a subclass ofT.)

  • If the invocation mode issuper, thenS is initially the qualifying type (§13.1) of the method invocation.

The dynamic method lookup uses the following procedure to search classS, and then the superclasses and superinterfaces of classS, as necessary, for methodm.

LetX be the compile-time type of the target reference of the method invocation. Then:

  1. If classS contains a declaration for a method namedm with the same descriptor (same number of parameters, the same parameter types, and the same return type) required by the method invocation as determined at compile time (§15.12.3), then:

    • If the invocation mode issuper orinterface, then this is the method to be invoked, and the procedure terminates.

    • If the invocation mode isvirtual, and the declaration inS overridesX.m (§8.4.8.1), then the method declared inS is the method to be invoked, and the procedure terminates.

  2. Otherwise, ifS has a superclass, the lookup procedure of steps 1 and 2 is performed recursively using the direct superclass ofS in place ofS; the method to be invoked, if any, is the result of the recursive invocation of this lookup procedure.

  3. If no method is found by the previous two steps, the superinterfaces ofS are searched for a suitable method.

    A set of candidate methods is considered with the following properties: i) each method is declared in a (direct or indirect) superinterface ofS; ii) each method has the name and descriptor required by the method invocation; iii) each method is non-static; iv) for each method, where the method's declaring interface isI, there is no other method satisfying (i) through (iii) that is declared in a subinterface ofI.

    If this set contains a default method, one such method is the method to be invoked. Otherwise, anabstract method in the set is selected as the method to be invoked.

Dynamic method lookup may cause the following errors to occur:

  • If the method to be invoked isabstract, anAbstractMethodError is thrown.

  • If the method to be invoked is default, and more than one default method appears in the set of candidates in step 3 above, anIncompatibleClassChangeError is thrown.

  • If the invocation mode isinterface and the selected method is notpublic, anIllegalAccessError is thrown.

The above procedure (if it terminates without error) will find a non-abstract, accessible method to invoke, provided that all classes and interfaces in the program have been consistently compiled. However, if this is not the case, then various errors may occur, as specified above; additional details about the behavior of the Java Virtual Machine under these circumstances are given byThe Java Virtual Machine Specification, Java SE 8 Edition.

The dynamic lookup process, while described here explicitly, will often be implemented implicitly, for example as a side-effect of the construction and use of per-class method dispatch tables, or the construction of other per-class structures used for efficient dispatch.

Example 15.12.4.4-1. Overriding and Method Invocation

class Point {    final int EDGE = 20;    int x, y;    void move(int dx, int dy) {        x += dx; y += dy;        if (Math.abs(x) >= EDGE || Math.abs(y) >= EDGE)            clear();    }    void clear() {        System.out.println("\tPoint clear");        x = 0; y = 0;    }}class ColoredPoint extends Point {    int color;    void clear() {        System.out.println("\tColoredPoint clear");        super.clear();        color = 0;    }}

Here, the subclassColoredPoint extends theclear abstraction defined by its superclassPoint. It does so by overriding theclear method with its own method, which invokes theclear method of its superclass, using the formsuper.clear().

This method is then invoked whenever the target object for an invocation ofclear is aColoredPoint. Even the methodmove inPoint invokes theclear method of classColoredPoint when the class ofthis isColoredPoint, as shown by the output of this test program:

class Test1 {    public static void main(String[] args) {        Point p = new Point();        System.out.println("p.move(20,20):");        p.move(20, 20);        ColoredPoint cp = new ColoredPoint();        System.out.println("cp.move(20,20):");        cp.move(20, 20);        p = new ColoredPoint();        System.out.println("p.move(20,20), p colored:");        p.move(20, 20);    }}

which is:

p.move(20,20):        Point clearcp.move(20,20):        ColoredPoint clear        Point clearp.move(20,20), p colored:        ColoredPoint clear        Point clear

Overriding is sometimes called "late-bound self-reference"; in this example it means that the reference toclear in the body ofPoint.move (which is really syntactic shorthand forthis.clear) invokes a method chosen "late" (at run time, based on the run-time class of the object referenced bythis) rather than a method chosen "early" (at compile time, based only on the type ofthis). This provides the programmer a powerful way of extending abstractions and is a key idea in object-oriented programming.


Example 15.12.4.4-2. Method Invocation Usingsuper

An overridden instance method of a superclass may be accessed by using the keywordsuper to access the members of the immediate superclass, bypassing any overriding declaration in the class that contains the method invocation.

When accessing an instance variable,super means the same as a cast ofthis (§15.11.2), but this equivalence does not hold true for method invocation. This is demonstrated by the example:

class T1 {    String s() { return "1"; }}class T2 extends T1 {    String s() { return "2"; }}class T3 extends T2 {    String s() { return "3"; }    void test() {        System.out.println("s()=\t\t"          + s());        System.out.println("super.s()=\t"      + super.s());        System.out.println("((T2)this).s()=\t" + ((T2)this).s());        System.out.println("((T1)this).s()=\t" + ((T1)this).s());    }}class Test2 {    public static void main(String[] args) {        T3 t3 = new T3();        t3.test();    }}

which produces the output:

s()=            3super.s()=      2((T2)this).s()= 3((T1)this).s()= 3

The casts to typesT1 andT2 do not change the method that is invoked, because the instance method to be invoked is chosen according to the run-time class of the object referred to bythis. A cast does not change the class of an object; it only checks that the class is compatible with the specified type.


15.12.4.5. Create Frame, Synchronize, Transfer Control

A methodm in some classS has been identified as the one to be invoked.

Now a newactivation frame is created, containing the target reference (if any) and the argument values (if any), as well as enough space for the local variables and stack for the method to be invoked and any other bookkeeping information that may be required by the implementation (stack pointer, program counter, reference to previous activation frame, and the like). If there is not sufficient memory available to create such an activation frame, aStackOverflowError is thrown.

The newly created activation frame becomes the current activation frame. The effect of this is to assign the argument values to corresponding freshly created parameter variables of the method, and to make the target reference available asthis, if there is a target reference. Before each argument value is assigned to its corresponding parameter variable, it is subjected to invocation conversion (§5.3), which includes any required value set conversion (§5.1.13).

If the erasure (§4.6) of the type of the method being invoked differs in its signature from the erasure of the type of the compile-time declaration for the method invocation (§15.12.3), then if any of the argument values is an object which is not an instance of a subclass or subinterface of the erasure of the corresponding formal parameter type in the compile-time declaration for the method invocation, then aClassCastException is thrown.

If the methodm is anative method but the necessary native, implementation-dependent binary code has not been loaded or otherwise cannot be dynamically linked, then anUnsatisfiedLinkError is thrown.

If the methodm is notsynchronized, control is transferred to the body of the methodm to be invoked.

If the methodm issynchronized, then an object must be locked before the transfer of control. No further progress can be made until the current thread can obtain the lock. If there is a target reference, then the target object must be locked; otherwise theClass object for classS, the class of the methodm, must be locked. Control is then transferred to the body of the methodm to be invoked. The object is automatically unlocked when execution of the body of the method has completed, whether normally or abruptly. The locking and unlocking behavior is exactly as if the body of the method were embedded in asynchronized statement (§14.19).

Example 15.12.4.5-1. Invoked Method Signature Has Different Erasure Than Compile-Time Method Signature

Consider the declarations:

abstract class C<T> {    abstract T id(T x);}class D extends C<String> {    String id(String x) { return x; }}

Now, given an invocation:

C c = new D();c.id(new Object());  // fails with a ClassCastException

The erasure of the actual method being invoked,D.id(), differs in its signature from that of the compile-time method declaration,C.id(). The former takes an argument of typeString while the latter takes an argument of typeObject. The invocation fails with aClassCastException before the body of the method is executed.

Such situations can only arise if the program gives rise to a compile-time unchecked warning (§4.8,§5.1.9,§5.5.2,§8.4.1,§8.4.8.3,§8.4.8.4,§9.4.1.2,§15.12.4.2).

Implementations can enforce these semantics by creatingbridge methods. In the above example, the following bridge method would be created in classD:

Object id(Object x) { return id((String) x); }

This is the method that would actually be invoked by the Java Virtual Machine in response to the callc.id(new Object()) shown above, and it will execute the cast and fail, as required.


15.13. Method Reference Expressions

A method reference expression is used to refer to the invocation of a method without actually performing the invocation. Certain forms of method reference expression also allow class instance creation (§15.9) or array creation (§15.10) to be treated as if it were a method invocation.

MethodReference:
ExpressionName:: [TypeArguments]Identifier
ReferenceType:: [TypeArguments]Identifier
Primary:: [TypeArguments]Identifier
super:: [TypeArguments]Identifier
TypeName.super:: [TypeArguments]Identifier
ClassType:: [TypeArguments]new
ArrayType::new

IfTypeArguments is present to the right of::, then it is a compile-time error if any of the type arguments are wildcards (§4.5.1).

If a method reference expression has the formExpressionName::[TypeArguments]Identifier orPrimary::[TypeArguments]Identifier, it is a compile-time error if the type of theExpressionName orPrimary is not a reference type.

If a method reference expression has the formsuper::[TypeArguments]Identifier, letT be the type declaration immediately enclosing the method reference expression. It is a compile-time error ifT is the classObject orT is an interface.

If a method reference expression has the formTypeName.super::[TypeArguments]Identifier, then:

  • IfTypeName denotes a class,C, then it is a compile-time error ifC is not a lexically enclosing class of the current class, or ifC is the classObject.

  • IfTypeName denotes an interface,I, then letT be the type declaration immediately enclosing the method reference expression. It is a compile-time error ifI is not a direct superinterface ofT, or if there exists some other direct superclass or direct superinterface ofT,J, such thatJ is a subtype ofI.

  • IfTypeName denotes a type variable, then a compile-time error occurs.

If a method reference expression has the formsuper::[TypeArguments]Identifier orTypeName.super::[TypeArguments]Identifier, it is a compile-time error if the expression occurs in a static context.

If a method reference expression has the formClassType::[TypeArguments]new, then:

  • ClassType must denote a class that is accessible, non-abstract, and not an enum type, or a compile-time error occurs.

  • IfClassType denotes a parameterized type (§4.5), then it is a compile-time error if any of its type arguments are wildcards.

  • IfClassType denotes a raw type (§4.8), then it is a compile-time error ifTypeArguments is present after the::.

If a method reference expression has the formArrayType::new, thenArrayType must denote a type that is reifiable (§4.7), or a compile-time error occurs.

The target reference of an instance method (§15.12.4.1) may be provided by the method reference expression using anExpressionName, aPrimary, orsuper, or it may be provided later when the method is invoked. The immediately enclosing instance of a new inner class instance (§15.9.2) is provided by a lexically enclosing instance ofthis (§8.1.3).

When more than one member method of a type has the same name, or when a class has more than one constructor, the appropriate method or constructor is selected based on the functional interface type targeted by the expression, as specified in§15.13.1.

If a method or constructor is generic, the appropriate type arguments may either be inferred or provided explicitly. Similarly, the type arguments of a generic type mentioned by the method reference expression may be provided explicitly or inferred.

Method reference expressions are always poly expressions (§15.2).

It is a compile-time error if a method reference expression occurs in a program in someplace other than an assignment context (§5.2), an invocation context (§5.3), or a casting context (§5.5).

Evaluation of a method reference expression produces an instance of a functional interface type (§9.8). Method reference evaluation doesnot cause the execution of the corresponding method; instead, this may occur at a later time when an appropriate method of the functional interface is invoked.

Here are some method reference expressions, first with no target reference and then with a target reference:

String::length             // instance methodSystem::currentTimeMillis  // static methodList<String>::size  // explicit type arguments for generic typeList::size          // inferred type arguments for generic typeint[]::cloneT::tvarMemberSystem.out::println"abc"::lengthfoo[x]::bar(test ? list.replaceAll(String::trim) : list) :: iteratorsuper::toString

Here are some more method reference expressions:

String::valueOf       // overload resolution needed     Arrays::sort          // type arguments inferred from contextArrays::<String>sort  // explicit type arguments

Here are some method reference expressions that represent a deferred creation of an object or an array:

ArrayList<String>::new     // constructor for parameterized typeArrayList::new             // inferred type arguments                           // for generic classFoo::<Integer>new          // explicit type arguments                           // for generic constructorBar<String>::<Integer>new  // generic class, generic constructorOuter.Inner::new           // inner class constructorint[]::new                 // array creation

It is not possible to specify a particular signature to be matched, for example,Arrays::sort(int[]). Instead, the functional interface provides argument types that are used as input to the overload resolution algorithm (§15.12.2). This should satisfy the vast majority of use cases; when the rare need arises for more precise control, a lambda expression can be used.

The use of type argument syntax in the class name before a delimiter (List<String>::size) raises the parsing problem of distinguishing between< as a type argument bracket and< as a less-than operator. In theory, this is no worse than allowing type arguments in cast expressions; however, the difference is that the cast case only comes up when a( token is encountered; with the addition of method reference expressions, the start ofevery expression is potentially a parameterized type.

15.13.1. Compile-Time Declaration of a Method Reference

Thecompile-time declaration of a method reference is the method to which the expression refers. In special cases, the compile-time declaration does not actually exist, but is a notional method that represents a class instance creation or an array creation. The choice of compile-time declaration depends on a function type targeted by the expression, just as the compile-time declaration of a method invocation depends on the invocation's arguments (§15.12).

The search for a compile-time declaration mirrors the process for method invocations in§15.12.1 and§15.12.2, as follows:

  • First, a type to search is determined:

    • If the method reference expression has the formExpressionName::[TypeArguments]Identifier orPrimary::[TypeArguments]Identifier, the type to search is the type of the expression preceding the:: token.

    • If the method reference expression has the formReferenceType::[TypeArguments]Identifier, the type to search is the result of capture conversion (§5.1.10) applied toReferenceType.

    • If the method reference expression has the formsuper::[TypeArguments]Identifier, the type to search is the superclass type of the class whose declaration contains the method reference.

    • If the method reference expression has the formTypeName.super::[TypeArguments]Identifier, then ifTypeName denotes a class, the type to search is the superclass type of the named class; otherwise,TypeName denotes an interface, and the corresponding superinterface type of the class or interface whose declaration contains the method reference is the type to search.

    • For the two other forms (involving::new), the referenced method is notional and there is no type to search.

  • Second, given a targeted function type withn parameters, a set of potentially applicable methods is identified:

    • If the method reference expression has the formReferenceType::[TypeArguments]Identifier, the potentially applicable methods are the member methods of the type to search that have an appropriate name (given byIdentifier), accessibility, arity (n orn-1), and type argument arity (derived from[TypeArguments]), as specified in§15.12.2.1.

      Two different arities,n andn-1, are considered, to account for the possibility that this form refers to either astatic method or an instance method.

    • If the method reference expression has the formClassType::[TypeArguments]new, the potentially applicable methods are a set of notional methods corresponding to the constructors ofClassType.

      IfClassType is a raw type, but is not a non-static member type of a raw type, the candidate notional member methods are those specified in§15.9.3 for a class instance creation expression that uses<> to elide the type arguments to a class.

      Otherwise, the candidate notional member methods are the constructors ofClassType, treated as if they were methods with return typeClassType. Among these candidates, the methods with appropriate accessibility, arity (n), and type argument arity (derived from[TypeArguments]) are selected, as specified in§15.12.2.1.

    • If the method reference expression has the formArrayType::new, a single notional method is considered. The method has a single parameter of typeint, returns theArrayType, and has nothrows clause. Ifn = 1, this is the only potentially applicable method; otherwise, there are no potentially applicable methods.

    • For all other forms, the potentially applicable methods are the member methods of the type to search that have an appropriate name (given byIdentifier), accessibility, arity (n), and type argument arity (derived from[TypeArguments]), as specified in§15.12.2.1.

  • Finally, if there are no potentially applicable methods, then there is no compile-time declaration.

    Otherwise, given a targeted function type with parameter typesP1, ...,Pn and a set of potentially applicable methods, the compile-time declaration is selected as follows:

    • If the method reference expression has the formReferenceType::[TypeArguments]Identifier, then two searches for a most specific applicable method are performed. Each search is as specified in§15.12.2.2 through§15.12.2.5, with the clarifications below. Each search may produce a method or, in the case of an error as specified in§15.12.2.2 through§15.12.2.5, no result.

      In the first search, the method reference is treated as if it were an invocation with argument expressions of typesP1, ...,Pn; the type arguments, if any, are given by the method reference expression.

      In the second search, ifP1, ...,Pn is not empty andP1 is a subtype ofReferenceType, then the method reference expression is treated as if it were a method invocation expression with argument expressions of typesP2, ...,Pn. IfReferenceType is a raw type, and there exists a parameterization of this type,G<...>, that is a supertype ofP1, the type to search is the result of capture conversion (§5.1.10) applied toG<...>; otherwise, the type to search is the same as the type of the first search. Again, the type arguments, if any, are given by the method reference expression.

      If the first search produces astatic method, and no non-static method is applicable by§15.12.2.2,§15.12.2.3, or§15.12.2.4 during the second search, then the compile-time declaration is the result of the first search.

      Otherwise, if nostatic method is applicable by§15.12.2.2,§15.12.2.3, or§15.12.2.4 during the first search, and the second search produces a non-static method, then the compile-time declaration is the result of the second search.

      Otherwise, there is no compile-time declaration.

    • For all other forms of method reference expression, one search for a most specific applicable method is performed. The search is as specified in§15.12.2.2 through§15.12.2.5, with the clarifications below.

      The method reference is treated as if it were an invocation with argument expressions of typesP1, ...,Pn; the type arguments, if any, are given by the method reference expression.

      If the search results in an error as specified in§15.12.2.2 through§15.12.2.5, or if the most specific applicable method isstatic, there is no compile-time declaration.

      Otherwise, the compile-time declaration is the most specific applicable method.

It is a compile-time error if a method reference expression has the formReferenceType::[TypeArguments]Identifier, and the compile-time declaration isstatic, andReferenceType is not a simple or qualified name (§6.2).

It is a compile-time error if the method reference expression has the formsuper::[TypeArguments]Identifier orTypeName.super::[TypeArguments]Identifier, and the compile-time declaration isabstract.

It is a compile-time error if the method reference expression has the formTypeName.super::[TypeArguments]Identifier, andTypeName denotes an interface, and there exists a method, distinct from the compile-time declaration, that overrides (§8.4.8,§9.4.1) the compile-time declaration from a direct superclass or direct superinterface of the type whose declaration immediately encloses the method reference expression.

It is a compile-time error if the method reference expression is of the formClassType::[TypeArguments]new and a compile-time error would occur when determining an enclosing instance forClassType as specified in§15.9.2 (treating the method reference expression as if it were an unqualified class instance creation expression).

A method reference expression of the formReferenceType::[TypeArguments]Identifier can be interpreted in different ways. IfIdentifier refers to an instance method, then the implicit lambda expression has an extra parameter compared to ifIdentifier refers to astatic method. It is possible forReferenceType to have both kinds of applicable methods, so the search algorithm described above identifies them separately, since there are different parameter types for each case.

An example of ambiguity is:

interface Fun<T,R> { R apply(T arg); }class C {    int size() { return 0; }    static int size(Object arg) { return 0; }    void test() {        Fun<C, Integer> f1 = C::size;          // Error: instance method size()          // or static method size(Object)?    }}

This ambiguity cannot be resolved by providing an applicable instance method which is more specific than an applicablestatic method:

interface Fun<T,R> { R apply(T arg); }class C {    int size() { return 0; }    static int size(Object arg) { return 0; }    int size(C arg) { return 0; }    void test() {        Fun<C, Integer> f1 = C::size;          // Error: instance method size()          // or static method size(Object)?    }}

The search is smart enough to ignore ambiguities in which all the applicable methods (from both searches) are instance methods:

interface Fun<T,R> { R apply(T arg); }class C {    int size() { return 0; }    int size(Object arg) { return 0; }    int size(C arg) { return 0; }    void test() {        Fun<C, Integer> f1 = C::size;          // OK: reference is to instance method size()    }}

For convenience, when the name of a generic type is used to refer to an instance method (where the receiver becomes the first parameter), the target type is used to determine the type arguments. This facilitates usage likePair::first in place ofPair<String,Integer>::first. Similarly, a method reference likePair::new is treated like a "diamond" instance creation (new Pair<>()). Because the "diamond" is implicit, this form doesnot instantiate a raw type; in fact, there is no way to express a reference to the constructor of a raw type.

For some method reference expressions, there is only one possible compile-time declaration with only one possible invocation type (§15.12.2.6), regardless of the targeted function type. Such method reference expressions are said to beexact. A method reference expression that is not exact is said to beinexact.

A method reference expression ending withIdentifier is exact if it satisfies all of the following:

  • If the method reference expression has the formReferenceType::[TypeArguments]Identifier, thenReferenceType does not denote a raw type.

  • The type to search has exactly one member method with the nameIdentifier that is accessible to the class or interface in which the method reference expression appears.

  • This method is not variable arity (§8.4.1).

  • If this method is generic (§8.4.4), then the method reference expression providesTypeArguments.

A method reference expression of the formClassType::[TypeArguments]new is exact if it satisfies all of the following:

  • The type denoted byClassType is not raw, or is a non-static member type of a raw type.

  • The type denoted byClassType has exactly one constructor that is accessible to the class or interface in which the method reference expression appears.

  • This constructor is not variable arity.

  • If this constructor is generic, then the method reference expression providesTypeArguments.

A method reference expression of the formArrayType::new is always exact.

15.13.2. Type of a Method Reference

A method reference expression is compatible in an assignment context, invocation context, or casting context with a target typeT ifT is a functional interface type (§9.8) and the expression iscongruent with the function type of theground target type derived fromT.

Theground target type is derived fromT as follows:

  • IfT is a wildcard-parameterized functional interface type, then the ground target type is the non-wildcard parameterization (§9.9) ofT.

  • Otherwise, the ground target type isT.

A method reference expression iscongruent with a function type if both of the following are true:

  • The function type identifies a single compile-time declaration corresponding to the reference.

  • One of the following is true:

    • The result of the function type isvoid.

    • The result of the function type isR, and the result of applying capture conversion (§5.1.10) to the return type of the invocation type (§15.12.2.6) of the chosen compile-time declaration isR' (whereR is the target type that may be used to inferR'), and neitherR norR' isvoid, andR' is compatible withR in an assignment context.

A compile-time unchecked warning occurs if unchecked conversion was necessary for the compile-time declaration to be applicable, and this conversion would cause an unchecked warning in an invocation context.

A compile-time unchecked warning occurs if unchecked conversion was necessary for the return typeR', described above, to be compatible with the function type's return type,R, and this conversion would cause an unchecked warning in an assignment context.

If a method reference expression is compatible with a target typeT, then the type of the expression,U, is the ground target type derived fromT.

It is a compile-time error if any class or interface mentioned by eitherU or the function type ofU is not accessible from the class or interface in which the method reference expression appears.

For each non-static member methodm ofU, if the function type ofU has a subsignature of the signature ofm, then a notional method whose method type is the function type ofU is said to overridem, and any compile-time error or unchecked warning specified in§8.4.8.3 may occur.

For each checked exception typeX listed in thethrows clause of the invocation type of the compile-time declaration,X or a superclass ofX must be mentioned in thethrows clause of the function type ofU, or a compile-time error occurs.

The key idea driving the compatibility definition is that a method reference is compatible if and only if the equivalent lambda expression(x, y, z)-> exp.<T1, T2>method(x, y, z) is compatible. (This is informal, and there are issues that make it difficult or impossible to formally define the semantics in terms of such a rewrite.)

These compatibility rules provide a convenient facility for converting from one functional interface to another:

Task t = ()-> System.out.println("hi");Runnable r = t::invoke;

The implementation may be optimized so that when a lambda-derived object is passed around and converted to various types, this does not result in many levels of adaptation logic around the core lambda body.

Unlike a lambda expression, a method reference can be congruent with a generic function type (that is, a function type that has type parameters). This is because the lambda expression would need to be able to declare type parameters, and no syntax supports this; while for a method reference, no such declaration is necessary. For example, the following program is legal:

interface ListFactory {    <T> List<T> make();}ListFactory lf  = ArrayList::new;List<String> ls = lf.make();List<Number> ln = lf.make();

15.13.3. Run-Time Evaluation of Method References

At run time, evaluation of a method reference expression is similar to evaluation of a class instance creation expression, insofar as normal completion produces a reference to an object. Evaluation of a method reference expression is distinct from invocation of the method itself.

First, if the method reference expression begins with anExpressionName or aPrimary, this subexpression is evaluated. If the subexpression evaluates tonull, aNullPointerException is raised, and the method reference expression completes abruptly. If the subexpression completes abruptly, the method reference expression completes abruptly for the same reason.

Next, either a new instance of a class with the properties below is allocated and initialized, or an existing instance of a class with the properties below is referenced. If a new instance is to be created, but there is insufficient space to allocate the object, evaluation of the method reference expression completes abruptly by throwing anOutOfMemoryError.

The value of a method reference expression is a reference to an instance of a class with the following properties:

  • The class implements the targeted functional interface type and, if the target type is an intersection type, every other interface type mentioned in the intersection.

  • Where the method reference expression has typeU, for each non-static member methodm ofU:

    If the function type ofU has a subsignature of the signature ofm, then the class declares aninvocation method that overridesm. The invocation method's body invokes the referenced method, creates a class instance, or creates an array, as described below. If the invocation method's result is notvoid, then the body returns the result of the method invocation or object creation, after any necessary assignment conversions (§5.2).

    If the erasure of the type of a method being overridden differs in its signature from the erasure of the function type ofU, then before the method invocation or object creation, an invocation method's body checks that each argument value is an instance of a subclass or subinterface of the erasure of the corresponding parameter type in the function type ofU; if not, aClassCastException is thrown.

  • The class overrides no other methods of the functional interface type or other interface types mentioned above, although it may override methods of theObject class.

The body of an invocation method depends on the form of the method reference expression, as follows:

  • If the form isExpressionName::[TypeArguments]Identifier orPrimary::[TypeArguments]Identifier, then the body of the invocation method has the effect of a method invocation expression for a compile-time declaration which is the compile-time declaration of the method reference expression. Run-time evaluation of the method invocation expression is as specified in§15.12.4.3,§15.12.4.4, and§15.12.4.5, where:

    • The invocation mode is derived from the compile-time declaration as specified in§15.12.3.

    • The target reference is the value ofExpressionName orPrimary, as determined when the method reference expression was evaluated.

    • The arguments to the method invocation expression are the formal parameters of the invocation method.

  • If the form isReferenceType::[TypeArguments]Identifier, the body of the invocation method similarly has the effect of a method invocation expression for a compile-time declaration which is the compile-time declaration of the method reference expression. Run-time evaluation of the method invocation expression is as specified in§15.12.4.3,§15.12.4.4, and§15.12.4.5, where:

    • The invocation mode is derived from the compile-time declaration as specified in§15.12.3.

    • If the compile-time declaration is an instance method, then the target reference is the first formal parameter of the invocation method. Otherwise, there is no target reference.

    • If the compile-time declaration is an instance method, then the arguments to the method invocation expression (if any) are the second and subsequent formal parameters of the invocation method. Otherwise, the arguments to the method invocation expression are the formal parameters of the invocation method.

  • If the form issuper::[TypeArguments]Identifier orTypeName.super::[TypeArguments]Identifier, the body of the invocation method has the effect of a method invocation expression for a compile-time declaration which is the compile-time declaration of the method reference expression. Run-time evaluation of the method invocation expression is as specified in§15.12.4.3,§15.12.4.4, and§15.12.4.5, where:

    • The invocation mode issuper.

    • If the method reference expression begins with aTypeName that names a class, the target reference is the value ofTypeName.this at the point at which the method reference is evaluated. Otherwise, the target reference is the value ofthis at the point at which the method reference is evaluated.

    • The arguments to the method invocation expression are the formal parameters of the invocation method.

  • If the form isClassType::[TypeArguments]new, the body of the invocation method has the effect of a class instance creation expression of the formnew[TypeArguments]ClassType(A1, ...,An), where the argumentsA1, ...,An are the formal parameters of the invocation method, and where:

    • The enclosing instance for the new object, if any, is derived from the site of the method reference expression, as specified in§15.9.2.

    • The constructor to invoke is the constructor that corresponds to the compile-time declaration of the method reference (§15.13.1).

  • If the form isType[]k::new (k 1), then the body of the invocation method has the same effect as an array creation expression of the formnewType[ size][]k-1, wheresize is the invocation method's single parameter. (The notation[]k indicates a sequence ofk bracket pairs.)

If the body of the invocation method has the effect of a method invocation expression, then the compile-time parameter types and the compile-time result of the method invocation are determined as specified in§15.12.3. For the purpose of determining the compile-time result, the method invocation expression is an expression statement if the invocation method's result isvoid, and theExpression of areturn statement if the invocation method's result is non-void.

The effect of this determination when the compile-time declaration of the method reference is signature polymorphic is that:

  • The types of the parameters for the method invocation are the types of the corresponding arguments.

  • The method invocation is eithervoid or has a return type ofObject, depending on whether the invocation method which encloses the method invocation isvoid or has a return type.

The timing of method reference expression evaluation is more complex than that of lambda expressions (§15.27.4). When a method reference expression has an expression (rather than a type) preceding the:: separator, that subexpression is evaluated immediately. The result of evaluation is stored until the method of the corresponding functional interface type is invoked; at that point, the result is used as the target reference for the invocation. This means the expression preceding the:: separator is evaluated only when the program encounters the method reference expression, and is not re-evaluated on subsequent invocations on the functional interface type.

It is interesting to contrast the treatment ofnull here with its treatment during method invocation. When a method invocation expression is evaluated, it is possible for thePrimary that qualifies the invocation to evaluate tonull but for noNullPointerException to be raised. This occurs when the invoked method isstatic (despite the syntax of the invocation suggesting an instance method). Since the applicable method for a method reference expression qualified by aPrimary is prohibited from beingstatic (§15.13.1), the evaluation of the method reference expression is simpler - anullPrimary always raises aNullPointerException.

15.14. Postfix Expressions

Postfix expressions include uses of the postfix++ and-- operators. Names are not considered to be primary expressions (§15.8), but are handled separately in the grammar to avoid certain ambiguities. They become interchangeable only here, at the level of precedence of postfix expressions.

PostfixExpression:
Primary
ExpressionName
PostIncrementExpression
PostDecrementExpression

15.14.1. Expression Names

The rules for evaluating expression names are given in§6.5.6.

15.14.2. Postfix Increment Operator++

A postfix expression followed by a++ operator is a postfix increment expression.

PostIncrementExpression:

The result of the postfix expression must be a variable of a type that is convertible (§5.1.8) to a numeric type, or a compile-time error occurs.

The type of the postfix increment expression is the type of the variable. The result of the postfix increment expression is not a variable, but a value.

At run time, if evaluation of the operand expression completes abruptly, then the postfix increment expression completes abruptly for the same reason and no incrementation occurs. Otherwise, the value1 is added to the value of the variable and the sum is stored back into the variable. Before the addition, binary numeric promotion (§5.6.2) is performed on the value1 and the value of the variable. If necessary, the sum is narrowed by a narrowing primitive conversion (§5.1.3) and/or subjected to boxing conversion (§5.1.7) to the type of the variable before it is stored. The value of the postfix increment expression is the value of the variablebefore the new value is stored.

Note that the binary numeric promotion mentioned above may include unboxing conversion (§5.1.8) and value set conversion (§5.1.13). If necessary, value set conversion is applied to the sum prior to its being stored in the variable.

A variable that is declaredfinal cannot be incremented because when an access of such afinal variable is used as an expression, the result is a value, not a variable. Thus, it cannot be used as the operand of a postfix increment operator.

15.14.3. Postfix Decrement Operator--

A postfix expression followed by a-- operator is a postfix decrement expression.

PostDecrementExpression:

The result of the postfix expression must be a variable of a type that is convertible (§5.1.8) to a numeric type, or a compile-time error occurs.

The type of the postfix decrement expression is the type of the variable. The result of the postfix decrement expression is not a variable, but a value.

At run time, if evaluation of the operand expression completes abruptly, then the postfix decrement expression completes abruptly for the same reason and no decrementation occurs. Otherwise, the value1 is subtracted from the value of the variable and the difference is stored back into the variable. Before the subtraction, binary numeric promotion (§5.6.2) is performed on the value1 and the value of the variable. If necessary, the difference is narrowed by a narrowing primitive conversion (§5.1.3) and/or subjected to boxing conversion (§5.1.7) to the type of the variable before it is stored. The value of the postfix decrement expression is the value of the variablebefore the new value is stored.

Note that the binary numeric promotion mentioned above may include unboxing conversion (§5.1.8) and value set conversion (§5.1.13). If necessary, value set conversion is applied to the difference prior to its being stored in the variable.

A variable that is declaredfinal cannot be decremented because when an access of such afinal variable is used as an expression, the result is a value, not a variable. Thus, it cannot be used as the operand of a postfix decrement operator.

15.15. Unary Operators

The operators+,-,++,--,~,!, and the cast operator (§15.16) are called theunary operators.

UnaryExpression:
PreIncrementExpression
PreDecrementExpression
+UnaryExpression
-UnaryExpression
UnaryExpressionNotPlusMinus
PreIncrementExpression:
++UnaryExpression
PreDecrementExpression:
--UnaryExpression
UnaryExpressionNotPlusMinus:
PostfixExpression
~UnaryExpression
!UnaryExpression
CastExpression

The following production from§15.16 is shown here for convenience:

CastExpression:

Expressions with unary operators group right-to-left, so that-~x means the same as-(~x).

This portion of the grammar contains some tricks to avoid two potential syntactic ambiguities.

The first potential ambiguity would arise in expressions such as(p)+q, which looks, to a C or C++ programmer, as though it could be either a cast to typep of a unary+ operating onq, or a binary addition of two quantitiesp andq. In C and C++, the parser handles this problem by performing a limited amount of semantic analysis as it parses, so that it knows whetherp is the name of a type or the name of a variable.

Java takes a different approach. The result of the+ operator must be numeric, and all type names involved in casts on numeric values are known keywords. Thus, ifp is a keyword naming a primitive type, then(p)+q can make sense only as a cast of a unary expression. However, ifp is not a keyword naming a primitive type, then(p)+q can make sense only as a binary arithmetic operation. Similar remarks apply to the- operator. The grammar shown above splitsCastExpression into two cases to make this distinction. The nonterminalUnaryExpression includes all unary operators, but the nonterminalUnaryExpressionNotPlusMinus excludes uses of all unary operators that could also be binary operators, which in Java are+ and-.

The second potential ambiguity is that the expression(p)++ could, to a C or C++ programmer, appear to be either a postfix increment of a parenthesized expression or the beginning of a cast, for example, in(p)++q. As before, parsers for C and C++ know whetherp is the name of a type or the name of a variable. But a parser using only one-token lookahead and no semantic analysis during the parse would not be able to tell, when++ is the lookahead token, whether(p) should be considered aPrimary expression or left alone for later consideration as part of aCastExpression.

In Java, the result of the++ operator must be numeric, and all type names involved in casts on numeric values are known keywords. Thus, ifp is a keyword naming a primitive type, then(p)++ can make sense only as a cast of a prefix increment expression, and there had better be an operand such asq following the++. However, ifp is not a keyword naming a primitive type, then(p)++ can make sense only as a postfix increment ofp. Similar remarks apply to the-- operator. The nonterminalUnaryExpressionNotPlusMinus therefore also excludes uses of the prefix operators++ and--.

15.15.1. Prefix Increment Operator++

A unary expression preceded by a++ operator is a prefix increment expression.

The result of the unary expression must be a variable of a type that is convertible (§5.1.8) to a numeric type, or a compile-time error occurs.

The type of the prefix increment expression is the type of the variable. The result of the prefix increment expression is not a variable, but a value.

At run time, if evaluation of the operand expression completes abruptly, then the prefix increment expression completes abruptly for the same reason and no incrementation occurs. Otherwise, the value1 is added to the value of the variable and the sum is stored back into the variable. Before the addition, binary numeric promotion (§5.6.2) is performed on the value1 and the value of the variable. If necessary, the sum is narrowed by a narrowing primitive conversion (§5.1.3) and/or subjected to boxing conversion (§5.1.7) to the type of the variable before it is stored. The value of the prefix increment expression is the value of the variableafter the new value is stored.

Note that the binary numeric promotion mentioned above may include unboxing conversion (§5.1.8) and value set conversion (§5.1.13). If necessary, value set conversion is applied to the sum prior to its being stored in the variable.

A variable that is declaredfinal cannot be incremented because when an access of such afinal variable is used as an expression, the result is a value, not a variable. Thus, it cannot be used as the operand of a prefix increment operator.

15.15.2. Prefix Decrement Operator--

A unary expression preceded by a-- operator is a prefix decrement expression.

The result of the unary expression must be a variable of a type that is convertible (§5.1.8) to a numeric type, or a compile-time error occurs.

The type of the prefix decrement expression is the type of the variable. The result of the prefix decrement expression is not a variable, but a value.

At run time, if evaluation of the operand expression completes abruptly, then the prefix decrement expression completes abruptly for the same reason and no decrementation occurs. Otherwise, the value1 is subtracted from the value of the variable and the difference is stored back into the variable. Before the subtraction, binary numeric promotion (§5.6.2) is performed on the value1 and the value of the variable. If necessary, the difference is narrowed by a narrowing primitive conversion (§5.1.3) and/or subjected to boxing conversion (§5.1.7) to the type of the variable before it is stored. The value of the prefix decrement expression is the value of the variableafter the new value is stored.

Note that the binary numeric promotion mentioned above may include unboxing conversion (§5.1.8) and value set conversion (§5.1.13). If necessary, format conversion is applied to the difference prior to its being stored in the variable.

A variable that is declaredfinal cannot be decremented because when an access of such afinal variable is used as an expression, the result is a value, not a variable. Thus, it cannot be used as the operand of a prefix decrement operator.

15.15.3. Unary Plus Operator+

The type of the operand expression of the unary+ operator must be a type that is convertible (§5.1.8) to a primitive numeric type, or a compile-time error occurs.

Unary numeric promotion (§5.6.1) is performed on the operand. The type of the unary plus expression is the promoted type of the operand. The result of the unary plus expression is not a variable, but a value, even if the result of the operand expression is a variable.

At run time, the value of the unary plus expression is the promoted value of the operand.

15.15.4. Unary Minus Operator-

The type of the operand expression of the unary- operator must be a type that is convertible (§5.1.8) to a primitive numeric type, or a compile-time error occurs.

Unary numeric promotion (§5.6.1) is performed on the operand.

The type of the unary minus expression is the promoted type of the operand.

Note that unary numeric promotion performs value set conversion (§5.1.13). Whatever value set the promoted operand value is drawn from, the unary negation operation is carried out and the result is drawn from that same value set. That result is then subject to further value set conversion.

At run time, the value of the unary minus expression is the arithmetic negation of the promoted value of the operand.

For integer values, negation is the same as subtraction from zero. The Java programming language uses two's-complement representation for integers, and the range of two's-complement values is not symmetric, so negation of the maximum negativeint orlong results in that same maximum negative number. Overflow occurs in this case, but no exception is thrown. For all integer valuesx,-x equals(~x)+1.

For floating-point values, negation isnot the same as subtraction from zero, because ifx is+0.0, then0.0-x is+0.0, but-x is-0.0. Unary minus merely inverts the sign of a floating-point number. Special cases of interest:

  • If the operand is NaN, the result is NaN. (Recall that NaN has no sign (§4.2.3).)

  • If the operand is an infinity, the result is the infinity of opposite sign.

  • If the operand is a zero, the result is the zero of opposite sign.

15.15.5. Bitwise Complement Operator~

The type of the operand expression of the unary~ operator must be a type that is convertible (§5.1.8) to a primitive integral type, or a compile-time error occurs.

Unary numeric promotion (§5.6.1) is performed on the operand. The type of the unary bitwise complement expression is the promoted type of the operand.

At run time, the value of the unary bitwise complement expression is the bitwise complement of the promoted value of the operand. In all cases,~x equals(-x)-1.

15.15.6. Logical Complement Operator!

The type of the operand expression of the unary! operator must beboolean orBoolean, or a compile-time error occurs.

The type of the unary logical complement expression isboolean.

At run time, the operand is subject to unboxing conversion (§5.1.8) if necessary. The value of the unary logical complement expression istrue if the (possibly converted) operand value isfalse, andfalse if the (possibly converted) operand value istrue.

15.16. Cast Expressions

A cast expression converts, at run time, a value of one numeric type to a similar value of another numeric type; or confirms, at compile time, that the type of an expression isboolean; or checks, at run time, that a reference value refers to an object whose class is compatible with a specified reference type or list of reference types.

The parentheses and the type or list of types they contain are sometimes called thecast operator.

CastExpression:
(PrimitiveType)UnaryExpression
(ReferenceType {AdditionalBound})UnaryExpressionNotPlusMinus
(ReferenceType {AdditionalBound})LambdaExpression

The following production from§4.4 is shown here for convenience:

AdditionalBound:

If the cast operator contains a list of types - that is, aReferenceType followed by one or moreAdditionalBound terms - then all of the following must be true, or a compile-time error occurs:

  • ReferenceType must denote a class or interface type.

  • The erasures (§4.6) of all the listed types must be pairwise different.

  • No two listed types may be subtypes of different parameterizations of the same generic interface.

The target type for the casting context (§5.5) introduced by the cast expression is either thePrimitiveType or theReferenceType (if not followed byAdditionalBound terms) appearing in the cast operator, or the intersection type denoted by theReferenceType andAdditionalBound terms appearing in the cast operator.

The type of a cast expression is the result of applying capture conversion (§5.1.10) to this target type.

Casts can be used to explicitly "tag" a lambda expression or a method reference expression with a particular target type. To provide an appropriate degree of flexibility, the target type may be a list of types denoting an intersection type, provided the intersection induces a functional interface (§9.8).

The result of a cast expression is not a variable, but a value, even if the result of the operand expression is a variable.

A cast operator has no effect on the choice of value set (§4.2.3) for a value of typefloat or typedouble. Consequently, a cast to typefloat within an expression that is not FP-strict (§15.4) does not necessarily cause its value to be converted to an element of the float value set, and a cast to typedouble within an expression that is not FP-strict does not necessarily cause its value to be converted to an element of the double value set.

It is a compile-time error if the compile-time type of the operand may never be cast to the type specified by the cast operator according to the rules of casting conversion (§5.5).

Otherwise, at run time, the operand value is converted (if necessary) by casting conversion to the type specified by the cast operator.

AClassCastException is thrown if a cast is found at run time to be impermissible.

Some casts result in an error at compile time. Some casts can be proven, at compile time, always to be correct at run time. For example, it is always correct to convert a value of a class type to the type of its superclass; such a cast should require no special action at run time. Finally, some casts cannot be proven to be either always correct or always incorrect at compile time. Such casts require a test at run time. See§5.5 for details.

15.17. Multiplicative Operators

The operators*,/, and% are called themultiplicative operators.

MultiplicativeExpression:
UnaryExpression
MultiplicativeExpression*UnaryExpression
MultiplicativeExpression/UnaryExpression
MultiplicativeExpression%UnaryExpression

The multiplicative operators have the same precedence and are syntactically left-associative (they group left-to-right).

The type of each of the operands of a multiplicative operator must be a type that is convertible (§5.1.8) to a primitive numeric type, or a compile-time error occurs.

Binary numeric promotion is performed on the operands (§5.6.2).

Note that binary numeric promotion performs value set conversion (§5.1.13) and may perform unboxing conversion (§5.1.8).

The type of a multiplicative expression is the promoted type of its operands.

If the promoted type isint orlong, then integer arithmetic is performed.

If the promoted type isfloat ordouble, then floating-point arithmetic is performed.

15.17.1. Multiplication Operator*

The binary* operator performs multiplication, producing the product of its operands.

Multiplication is a commutative operation if the operand expressions have no side effects.

Integer multiplication is associative when the operands are all of the same type.

Floating-point multiplication is not associative.

If an integer multiplication overflows, then the result is the low-order bits of the mathematical product as represented in some sufficiently large two's-complement format. As a result, if overflow occurs, then the sign of the result may not be the same as the sign of the mathematical product of the two operand values.

The result of a floating-point multiplication is determined by the rules of IEEE 754 arithmetic:

  • If either operand is NaN, the result is NaN.

  • If the result is not NaN, the sign of the result is positive if both operands have the same sign, and negative if the operands have different signs.

  • Multiplication of an infinity by a zero results in NaN.

  • Multiplication of an infinity by a finite value results in a signed infinity. The sign is determined by the rule stated above.

  • In the remaining cases, where neither an infinity nor NaN is involved, the exact mathematical product is computed. A floating-point value set is then chosen:

    • If the multiplication expression is FP-strict (§15.4):

      • If the type of the multiplication expression isfloat, then the float value set must be chosen.

      • If the type of the multiplication expression isdouble, then the double value set must be chosen.

    • If the multiplication expression is not FP-strict:

      • If the type of the multiplication expression isfloat, then either the float value set or the float-extended-exponent value set may be chosen, at the whim of the implementation.

      • If the type of the multiplication expression isdouble, then either the double value set or the double-extended-exponent value set may be chosen, at the whim of the implementation.

    Next, a value must be chosen from the chosen value set to represent the product.

    If the magnitude of the product is too large to represent, we say the operation overflows; the result is then an infinity of appropriate sign.

    Otherwise, the product is rounded to the nearest value in the chosen value set using IEEE 754 round-to-nearest mode. The Java programming language requires support of gradual underflow as defined by IEEE 754 (§4.2.4).

Despite the fact that overflow, underflow, or loss of information may occur, evaluation of a multiplication operator* never throws a run-time exception.

15.17.2. Division Operator/

The binary/ operator performs division, producing the quotient of its operands. The left-hand operand is thedividend and the right-hand operand is thedivisor.

Integer division rounds toward0. That is, the quotient produced for operandsn andd that are integers after binary numeric promotion (§5.6.2) is an integer valueq whose magnitude is as large as possible while satisfying |dq| |n|. Moreover,q is positive when |n| |d| andn andd have the same sign, butq is negative when |n| |d| andn andd have opposite signs.

There is one special case that does not satisfy this rule: if the dividend is the negative integer of largest possible magnitude for its type, and the divisor is-1, then integer overflow occurs and the result is equal to the dividend. Despite the overflow, no exception is thrown in this case. On the other hand, if the value of the divisor in an integer division is0, then anArithmeticException is thrown.

The result of a floating-point division is determined by the rules of IEEE 754 arithmetic:

  • If either operand is NaN, the result is NaN.

  • If the result is not NaN, the sign of the result is positive if both operands have the same sign, and negative if the operands have different signs.

  • Division of an infinity by an infinity results in NaN.

  • Division of an infinity by a finite value results in a signed infinity. The sign is determined by the rule stated above.

  • Division of a finite value by an infinity results in a signed zero. The sign is determined by the rule stated above.

  • Division of a zero by a zero results in NaN; division of zero by any other finite value results in a signed zero. The sign is determined by the rule stated above.

  • Division of a nonzero finite value by a zero results in a signed infinity. The sign is determined by the rule stated above.

  • In the remaining cases, where neither an infinity nor NaN is involved, the exact mathematical quotient is computed. A floating-point value set is then chosen:

    • If the division expression is FP-strict (§15.4):

      • If the type of the division expression isfloat, then the float value set must be chosen.

      • If the type of the division expression isdouble, then the double value set must be chosen.

    • If the division expression is not FP-strict:

      • If the type of the division expression isfloat, then either the float value set or the float-extended-exponent value set may be chosen, at the whim of the implementation.

      • If the type of the division expression isdouble, then either the double value set or the double-extended-exponent value set may be chosen, at the whim of the implementation.

    Next, a value must be chosen from the chosen value set to represent the quotient.

    If the magnitude of the quotient is too large to represent, we say the operation overflows; the result is then an infinity of appropriate sign.

    Otherwise, the quotient is rounded to the nearest value in the chosen value set using IEEE 754 round-to-nearest mode. The Java programming language requires support of gradual underflow as defined by IEEE 754 (§4.2.4).

Despite the fact that overflow, underflow, division by zero, or loss of information may occur, evaluation of a floating-point division operator/ never throws a run-time exception.

15.17.3. Remainder Operator%

The binary% operator is said to yield the remainder of its operands from an implied division; the left-hand operand is thedividend and the right-hand operand is thedivisor.

In C and C++, the remainder operator accepts only integral operands, but in the Java programming language, it also accepts floating-point operands.

The remainder operation for operands that are integers after binary numeric promotion (§5.6.2) produces a result value such that(a/b)*b+(a%b) is equal toa.

This identity holds even in the special case that the dividend is the negative integer of largest possible magnitude for its type and the divisor is-1 (the remainder is0).

It follows from this rule that the result of the remainder operation can be negative only if the dividend is negative, and can be positive only if the dividend is positive. Moreover, the magnitude of the result is always less than the magnitude of the divisor.

If the value of the divisor for an integer remainder operator is0, then anArithmeticException is thrown.

Example 15.17.3-1. Integer Remainder Operator

class Test1 {    public static void main(String[] args) {        int a = 5%3;  // 2        int b = 5/3;  // 1        System.out.println("5%3 produces " + a +                           " (note that 5/3 produces " + b + ")");        int c = 5%(-3);  // 2        int d = 5/(-3);  // -1        System.out.println("5%(-3) produces " + c +                           " (note that 5/(-3) produces " + d + ")");        int e = (-5)%3;  // -2        int f = (-5)/3;  // -1        System.out.println("(-5)%3 produces " + e +                           " (note that (-5)/3 produces " + f + ")");        int g = (-5)%(-3);  // -2        int h = (-5)/(-3);  // 1        System.out.println("(-5)%(-3) produces " + g +                           " (note that (-5)/(-3) produces " + h + ")");    }}

This program produces the output:

5%3 produces 2 (note that 5/3 produces 1)5%(-3) produces 2 (note that 5/(-3) produces -1)(-5)%3 produces -2 (note that (-5)/3 produces -1)(-5)%(-3) produces -2 (note that (-5)/(-3) produces 1)

The result of a floating-point remainder operation as computed by the% operator isnot the same as that produced by the remainder operation defined by IEEE 754. The IEEE 754 remainder operation computes the remainder from a rounding division, not a truncating division, and so its behavior isnot analogous to that of the usual integer remainder operator. Instead, the Java programming language defines% on floating-point operations to behave in a manner analogous to that of the integer remainder operator; this may be compared with the C library functionfmod. The IEEE 754 remainder operation may be computed by the library routineMath.IEEEremainder.

The result of a floating-point remainder operation is determined by the rules of IEEE 754 arithmetic:

  • If either operand is NaN, the result is NaN.

  • If the result is not NaN, the sign of the result equals the sign of the dividend.

  • If the dividend is an infinity, or the divisor is a zero, or both, the result is NaN.

  • If the dividend is finite and the divisor is an infinity, the result equals the dividend.

  • If the dividend is a zero and the divisor is finite, the result equals the dividend.

  • In the remaining cases, where neither an infinity, nor a zero, nor NaN is involved, the floating-point remainderr from the division of a dividendn by a divisord is defined by the mathematical relationr =n - (dq) whereq is an integer that is negative only ifn/d is negative and positive only ifn/d is positive, and whose magnitude is as large as possible without exceeding the magnitude of the true mathematical quotient ofn andd.

Evaluation of a floating-point remainder operator% never throws a run-time exception, even if the right-hand operand is zero. Overflow, underflow, or loss of precision cannot occur.

Example 15.17.3-2. Floating-Point Remainder Operator

class Test2 {    public static void main(String[] args) {        double a = 5.0%3.0;  // 2.0        System.out.println("5.0%3.0 produces " + a);        double b = 5.0%(-3.0);  // 2.0        System.out.println("5.0%(-3.0) produces " + b);        double c = (-5.0)%3.0;  // -2.0        System.out.println("(-5.0)%3.0 produces " + c);        double d = (-5.0)%(-3.0);  // -2.0        System.out.println("(-5.0)%(-3.0) produces " + d);    }}

This program produces the output:

5.0%3.0 produces 2.05.0%(-3.0) produces 2.0(-5.0)%3.0 produces -2.0(-5.0)%(-3.0) produces -2.0

15.18. Additive Operators

The operators+ and- are called theadditive operators.

AdditiveExpression:
MultiplicativeExpression
AdditiveExpression+MultiplicativeExpression
AdditiveExpression-MultiplicativeExpression

The additive operators have the same precedence and are syntactically left-associative (they group left-to-right).

If the type of either operand of a+ operator isString, then the operation is string concatenation.

Otherwise, the type of each of the operands of the+ operator must be a type that is convertible (§5.1.8) to a primitive numeric type, or a compile-time error occurs.

In every case, the type of each of the operands of the binary- operator must be a type that is convertible (§5.1.8) to a primitive numeric type, or a compile-time error occurs.

15.18.1. String Concatenation Operator+

If only one operand expression is of typeString, then string conversion (§5.1.11) is performed on the other operand to produce a string at run time.

The result of string concatenation is a reference to aString object that is the concatenation of the two operand strings. The characters of the left-hand operand precede the characters of the right-hand operand in the newly created string.

TheString object is newly created (§12.5) unless the expression is a constant expression (§15.28).

An implementation may choose to perform conversion and concatenation in one step to avoid creating and then discarding an intermediateString object. To increase the performance of repeated string concatenation, a Java compiler may use theStringBuffer class or a similar technique to reduce the number of intermediateString objects that are created by evaluation of an expression.

For primitive types, an implementation may also optimize away the creation of a wrapper object by converting directly from a primitive type to a string.

Example 15.18.1-1. String Concatenation

The example expression:

"The square root of 2 is " + Math.sqrt(2)

produces the result:

"The square root of 2 is 1.4142135623730952"

The+ operator is syntactically left-associative, no matter whether it is determined by type analysis to represent string concatenation or numeric addition. In some cases care is required to get the desired result. For example, the expression:

a + b + c

is always regarded as meaning:

(a + b) + c

Therefore the result of the expression:

1 + 2 + " fiddlers"

is:

"3 fiddlers"

but the result of:

"fiddlers " + 1 + 2

is:

"fiddlers 12"

Example 15.18.1-2. String Concatenation and Conditionals

In this jocular little example:

class Bottles {    static void printSong(Object stuff, int n) {        String plural = (n == 1) ? "" : "s";  loop: while (true) {            System.out.println(n + " bottle" + plural                    + " of " + stuff + " on the wall,");            System.out.println(n + " bottle" + plural                    + " of " + stuff + ";");            System.out.println("You take one down "                    + "and pass it around:");            --n;            plural = (n == 1) ? "" : "s";            if (n == 0)                break loop;            System.out.println(n + " bottle" + plural                    + " of " + stuff + " on the wall!");            System.out.println();        }        System.out.println("No bottles of " +                    stuff + " on the wall!");    }    public static void main(String[] args) {        printSong("slime", 3);    }}

the methodprintSong will print a version of a children's song. Popular values forstuff include "pop" and "beer"; the most popular value forn is100. Here is the output that results from running the program:

3 bottles of slime on the wall,3 bottles of slime;You take one down and pass it around:2 bottles of slime on the wall!2 bottles of slime on the wall,2 bottles of slime;You take one down and pass it around:1 bottle of slime on the wall!1 bottle of slime on the wall,1 bottle of slime;You take one down and pass it around:No bottles of slime on the wall!

In the code, note the careful conditional generation of the singular "bottle" when appropriate rather than the plural "bottles"; note also how the string concatenation operator was used to break the long constant string:

"You take one down and pass it around:"

into two pieces to avoid an inconveniently long line in the source code.


15.18.2. Additive Operators (+ and-) for Numeric Types

The binary+ operator performs addition when applied to two operands of numeric type, producing the sum of the operands.

The binary- operator performs subtraction, producing the difference of two numeric operands.

Binary numeric promotion is performed on the operands (§5.6.2).

Note that binary numeric promotion performs value set conversion (§5.1.13) and may perform unboxing conversion (§5.1.8).

The type of an additive expression on numeric operands is the promoted type of its operands.

If this promoted type isint orlong, then integer arithmetic is performed.

If this promoted type isfloat ordouble, then floating-point arithmetic is performed.

Addition is a commutative operation if the operand expressions have no side effects.

Integer addition is associative when the operands are all of the same type.

Floating-point addition is not associative.

If an integer addition overflows, then the result is the low-order bits of the mathematical sum as represented in some sufficiently large two's-complement format. If overflow occurs, then the sign of the result is not the same as the sign of the mathematical sum of the two operand values.

The result of a floating-point addition is determined using the following rules of IEEE 754 arithmetic:

  • If either operand is NaN, the result is NaN.

  • The sum of two infinities of opposite sign is NaN.

  • The sum of two infinities of the same sign is the infinity of that sign.

  • The sum of an infinity and a finite value is equal to the infinite operand.

  • The sum of two zeros of opposite sign is positive zero.

  • The sum of two zeros of the same sign is the zero of that sign.

  • The sum of a zero and a nonzero finite value is equal to the nonzero operand.

  • The sum of two nonzero finite values of the same magnitude and opposite sign is positive zero.

  • In the remaining cases, where neither an infinity, nor a zero, nor NaN is involved, and the operands have the same sign or have different magnitudes, the exact mathematical sum is computed. A floating-point value set is then chosen:

    • If the addition expression is FP-strict (§15.4):

      • If the type of the addition expression isfloat, then the float value set must be chosen.

      • If the type of the addition expression isdouble, then the double value set must be chosen.

    • If the addition expression is not FP-strict:

      • If the type of the addition expression isfloat, then either the float value set or the float-extended-exponent value set may be chosen, at the whim of the implementation.

      • If the type of the addition expression isdouble, then either the double value set or the double-extended-exponent value set may be chosen, at the whim of the implementation.

    Next, a value must be chosen from the chosen value set to represent the sum.

    If the magnitude of the sum is too large to represent, we say the operation overflows; the result is then an infinity of appropriate sign.

    Otherwise, the sum is rounded to the nearest value in the chosen value set using IEEE 754 round-to-nearest mode. The Java programming language requires support of gradual underflow as defined by IEEE 754 (§4.2.4).

The binary- operator performs subtraction when applied to two operands of numeric type, producing the difference of its operands; the left-hand operand is theminuend and the right-hand operand is thesubtrahend.

For both integer and floating-point subtraction, it is always the case thata-b produces the same result asa+(-b).

Note that, for integer values, subtraction from zero is the same as negation. However, for floating-point operands, subtraction from zero isnot the same as negation, because if x is+0.0, then0.0-x is+0.0, but-x is-0.0.

Despite the fact that overflow, underflow, or loss of information may occur, evaluation of a numeric additive operator never throws a run-time exception.

15.19. Shift Operators

The operators<< (left shift),>> (signed right shift), and>>> (unsigned right shift) are called theshift operators. The left-hand operand of a shift operator is the value to be shifted; the right-hand operand specifies the shift distance.

ShiftExpression:
AdditiveExpression
ShiftExpression<<AdditiveExpression
ShiftExpression>>AdditiveExpression
ShiftExpression>>>AdditiveExpression

The shift operators are syntactically left-associative (they group left-to-right).

Unary numeric promotion (§5.6.1) is performed on each operand separately. (Binary numeric promotion (§5.6.2) isnot performed on the operands.)

It is a compile-time error if the type of each of the operands of a shift operator, after unary numeric promotion, is not a primitive integral type.

The type of the shift expression is the promoted type of the left-hand operand.

If the promoted type of the left-hand operand isint, then only the five lowest-order bits of the right-hand operand are used as the shift distance. It is as if the right-hand operand were subjected to a bitwise logical AND operator& (§15.22.1) with the mask value0x1f (0b11111). The shift distance actually used is therefore always in the range0 to31, inclusive.

If the promoted type of the left-hand operand islong, then only the six lowest-order bits of the right-hand operand are used as the shift distance. It is as if the right-hand operand were subjected to a bitwise logical AND operator& (§15.22.1) with the mask value0x3f (0b111111). The shift distance actually used is therefore always in the range0 to63, inclusive.

At run time, shift operations are performed on the two's-complement integer representation of the value of the left operand.

The value ofn<<s isn left-shifteds bit positions; this is equivalent (even if overflow occurs) to multiplication by two to the powers.

The value ofn>>s isn right-shifteds bit positions with sign-extension. The resulting value isfloor(n/ 2s). For non-negative values ofn, this is equivalent to truncating integer division, as computed by the integer division operator/, by two to the powers.

The value ofn>>>s isn right-shifteds bit positions with zero-extension, where:

  • Ifn is positive, then the result is the same as that ofn>>s.

  • Ifn is negative and the type of the left-hand operand isint, then the result is equal to that of the expression(n>>s)+(2<<~s).

  • Ifn is negative and the type of the left-hand operand islong, then the result is equal to that of the expression(n>>s)+(2L<<~s).

The added term(2<<~s) or(2L<<~s) cancels out the propagated sign bit.

Note that, because of the implicit masking of the right-hand operand of a shift operator,~s as a shift distance is equivalent to31-s when shifting anint value and to63-s when shifting along value.

15.20. Relational Operators

The numerical comparison operators<,>,<=, and>=, and theinstanceof operator, are called therelational operators.

RelationalExpression:
ShiftExpression
RelationalExpression<ShiftExpression
RelationalExpression>ShiftExpression
RelationalExpression<=ShiftExpression
RelationalExpression>=ShiftExpression
RelationalExpressioninstanceofReferenceType

The relational operators are syntactically left-associative (they group left-to-right).

However, this fact is not useful. For example,a<b<c parses as(a<b)<c, which is always a compile-time error, because the type ofa<b is alwaysboolean and < is not an operator onboolean values.

The type of a relational expression is alwaysboolean.

15.20.1. Numerical Comparison Operators<,<=,>, and>=

The type of each of the operands of a numerical comparison operator must be a type that is convertible (§5.1.8) to a primitive numeric type, or a compile-time error occurs.

Binary numeric promotion is performed on the operands (§5.6.2).

Note that binary numeric promotion performs value set conversion (§5.1.13) and may perform unboxing conversion (§5.1.8).

If the promoted type of the operands isint orlong, then signed integer comparison is performed.

If the promoted type isfloat ordouble, then floating-point comparison is performed.

Comparison is carried out accurately on floating-point values, no matter what value sets their representing values were drawn from.

The result of a floating-point comparison, as determined by the specification of the IEEE 754 standard, is:

  • If either operand is NaN, then the result is false.

  • All values other than NaN are ordered, with negative infinity less than all finite values, and positive infinity greater than all finite values.

  • Positive zero and negative zero are considered equal.

    For example,-0.0<0.0 isfalse, but-0.0<=0.0 istrue.

    Note, however, that the methodsMath.min andMath.max treat negative zero as being strictly smaller than positive zero.

Subject to these considerations for floating-point numbers, the following rules then hold for integer operands or for floating-point operands other than NaN:

  • The value produced by the< operator istrue if the value of the left-hand operand is less than the value of the right-hand operand, and otherwise isfalse.

  • The value produced by the<= operator istrue if the value of the left-hand operand is less than or equal to the value of the right-hand operand, and otherwise isfalse.

  • The value produced by the> operator istrue if the value of the left-hand operand is greater than the value of the right-hand operand, and otherwise isfalse.

  • The value produced by the>= operator istrue if the value of the left-hand operand is greater than or equal to the value of the right-hand operand, and otherwise isfalse.

15.20.2. Type Comparison Operatorinstanceof

The type of theRelationalExpression operand of theinstanceof operator must be a reference type or the null type; otherwise, a compile-time error occurs.

It is a compile-time error if theReferenceType mentioned after theinstanceof operator does not denote a reference type that is reifiable (§4.7).

If a cast (§15.16) of theRelationalExpression to theReferenceType would be rejected as a compile-time error, then theinstanceof relational expression likewise produces a compile-time error. In such a situation, the result of theinstanceof expression could never be true.

At run time, the result of theinstanceof operator istrue if the value of theRelationalExpression is notnull and the reference could be cast to theReferenceType without raising aClassCastException. Otherwise the result isfalse.

Example 15.20.2-1. Theinstanceof Operator

class Point   { int x, y; }class Element { int atomicNumber; }class Test {    public static void main(String[] args) {        Point   p = new Point();        Element e = new Element();        if (e instanceof Point) {  // compile-time error            System.out.println("I get your point!");            p = (Point)e;  // compile-time error        }    }}

This program results in two compile-time errors. The cast(Point)e is incorrect because no instance ofElement or any of its possible subclasses (none are shown here) could possibly be an instance of any subclass ofPoint. Theinstanceof expression is incorrect for exactly the same reason. If, on the other hand, the classPoint were a subclass ofElement (an admittedly strange notion in this example):

class Point extends Element { int x, y; }

then the cast would be possible, though it would require a run-time check, and theinstanceof expression would then be sensible and valid. The cast(Point)e would never raise an exception because it would not be executed if the value ofe could not correctly be cast to typePoint.


15.21. Equality Operators

The operators== (equal to) and!= (not equal to) are called theequality operators.

EqualityExpression:
RelationalExpression
EqualityExpression==RelationalExpression
EqualityExpression!=RelationalExpression

The equality operators are syntactically left-associative (they group left-to-right).

However, this fact is essentially never useful. For example,a==b==c parses as(a==b)==c. The result type ofa==b is alwaysboolean, andc must therefore be of typeboolean or a compile-time error occurs. Thus,a==b==c does not test to see whethera,b, andc are all equal.

The equality operators are commutative if the operand expressions have no side effects.

The equality operators are analogous to the relational operators except for their lower precedence. Thus,a<b==c<d istrue whenevera<b andc<d have the same truth value.

The equality operators may be used to compare two operands that are convertible (§5.1.8) to numeric type, or two operands of typeboolean orBoolean, or two operands that are each of either reference type or the null type. All other cases result in a compile-time error.

The type of an equality expression is alwaysboolean.

In all cases,a!=b produces the same result as!(a==b).

15.21.1. Numerical Equality Operators== and!=

If the operands of an equality operator are both of numeric type, or one is of numeric type and the other is convertible (§5.1.8) to numeric type, binary numeric promotion is performed on the operands (§5.6.2).

Note that binary numeric promotion performs value set conversion (§5.1.13) and may perform unboxing conversion (§5.1.8).

If the promoted type of the operands isint orlong, then an integer equality test is performed.

If the promoted type isfloat ordouble, then a floating-point equality test is performed.

Comparison is carried out accurately on floating-point values, no matter what value sets their representing values were drawn from.

Floating-point equality testing is performed in accordance with the rules of the IEEE 754 standard:

  • If either operand is NaN, then the result of== isfalse but the result of!= istrue.

    Indeed, the testx!=x istrue if and only if the value ofx is NaN.

    The methodsFloat.isNaN andDouble.isNaN may also be used to test whether a value is NaN.

  • Positive zero and negative zero are considered equal.

    For example,-0.0==0.0 istrue.

  • Otherwise, two distinct floating-point values are considered unequal by the equality operators.

    In particular, there is one value representing positive infinity and one value representing negative infinity; each compares equal only to itself, and each compares unequal to all other values.

Subject to these considerations for floating-point numbers, the following rules then hold for integer operands or for floating-point operands other than NaN:

  • The value produced by the== operator istrue if the value of the left-hand operand is equal to the value of the right-hand operand; otherwise, the result isfalse.

  • The value produced by the!= operator istrue if the value of the left-hand operand is not equal to the value of the right-hand operand; otherwise, the result isfalse.

15.21.2. Boolean Equality Operators== and!=

If the operands of an equality operator are both of typeboolean, or if one operand is of typeboolean and the other is of typeBoolean, then the operation is boolean equality.

The boolean equality operators are associative.

If one of the operands is of typeBoolean, it is subjected to unboxing conversion (§5.1.8).

The result of== istrue if the operands (after any required unboxing conversion) are bothtrue or bothfalse; otherwise, the result isfalse.

The result of!= isfalse if the operands are bothtrue or bothfalse; otherwise, the result istrue.

Thus!= behaves the same as^ (§15.22.2) when applied toboolean operands.

15.21.3. Reference Equality Operators== and!=

If the operands of an equality operator are both of either reference type or the null type, then the operation is object equality.

It is a compile-time error if it is impossible to convert the type of either operand to the type of the other by a casting conversion (§5.5). The run-time values of the two operands would necessarily be unequal (ignoring the case where both values arenull).

At run time, the result of== istrue if the operand values are bothnull or both refer to the same object or array; otherwise, the result isfalse.

The result of!= isfalse if the operand values are bothnull or both refer to the same object or array; otherwise, the result istrue.

While== may be used to compare references of typeString, such an equality test determines whether or not the two operands refer to the sameString object. The result isfalse if the operands are distinctString objects, even if they contain the same sequence of characters (§3.10.5). The contents of two stringss andt can be tested for equality by the method invocations.equals(t).

15.22. Bitwise and Logical Operators

Thebitwise operators andlogical operators include the AND operator&, exclusive OR operator^, and inclusive OR operator|.

AndExpression:
EqualityExpression
AndExpression&EqualityExpression
ExclusiveOrExpression:
AndExpression
ExclusiveOrExpression^AndExpression
InclusiveOrExpression:
ExclusiveOrExpression
InclusiveOrExpression|ExclusiveOrExpression

These operators have different precedence, with& having the highest precedence and| the lowest precedence.

Each of these operators is syntactically left-associative (each groups left-to-right).

Each operator is commutative if the operand expressions have no side effects.

Each operator is associative.

The bitwise and logical operators may be used to compare two operands of numeric type or two operands of typeboolean. All other cases result in a compile-time error.

15.22.1. Integer Bitwise Operators&,^, and|

When both operands of an operator&,^, or| are of a type that is convertible (§5.1.8) to a primitive integral type, binary numeric promotion is first performed on the operands (§5.6.2).

The type of the bitwise operator expression is the promoted type of the operands.

For&, the result value is the bitwise AND of the operand values.

For^, the result value is the bitwise exclusive OR of the operand values.

For|, the result value is the bitwise inclusive OR of the operand values.

For example, the result of the expression:

0xff00 & 0xf0f0

is:

0xf000

The result of the expression:

0xff00 ^ 0xf0f0

is:

0x0ff0

The result of the expression:

0xff00 | 0xf0f0

is:

0xfff0

15.22.2. Boolean Logical Operators&,^, and|

When both operands of a&,^, or| operator are of typeboolean orBoolean, then the type of the bitwise operator expression isboolean. In all cases, the operands are subject to unboxing conversion (§5.1.8) as necessary.

For&, the result value istrue if both operand values aretrue; otherwise, the result isfalse.

For^, the result value istrue if the operand values are different; otherwise, the result isfalse.

For|, the result value isfalse if both operand values arefalse; otherwise, the result istrue.

15.23. Conditional-And Operator&&

The conditional-and operator&& is like& (§15.22.2), but evaluates its right-hand operand only if the value of its left-hand operand istrue.

ConditionalAndExpression:
InclusiveOrExpression
ConditionalAndExpression&&InclusiveOrExpression

The conditional-and operator is syntactically left-associative (it groups left-to-right).

The conditional-and operator is fully associative with respect to both side effects and result value. That is, for any expressionsa,b, andc, evaluation of the expression((a)&& (b))&& (c) produces the same result, with the same side effects occurring in the same order, as evaluation of the expression(a)&& ((b)&& (c)).

Each operand of the conditional-and operator must be of typeboolean orBoolean, or a compile-time error occurs.

The type of a conditional-and expression is alwaysboolean.

At run time, the left-hand operand expression is evaluated first; if the result has typeBoolean, it is subjected to unboxing conversion (§5.1.8).

If the resulting value isfalse, the value of the conditional-and expression isfalse and the right-hand operand expression is not evaluated.

If the value of the left-hand operand istrue, then the right-hand expression is evaluated; if the result has typeBoolean, it is subjected to unboxing conversion (§5.1.8). The resulting value becomes the value of the conditional-and expression.

Thus,&& computes the same result as& onboolean operands. It differs only in that the right-hand operand expression is evaluated conditionally rather than always.

15.24. Conditional-Or Operator||

The conditional-or operator|| operator is like| (§15.22.2), but evaluates its right-hand operand only if the value of its left-hand operand isfalse.

ConditionalOrExpression:
ConditionalAndExpression
ConditionalOrExpression|| ConditionalAndExpression

The conditional-or operator is syntactically left-associative (it groups left-to-right).

The conditional-or operator is fully associative with respect to both side effects and result value. That is, for any expressionsa,b, andc, evaluation of the expression((a)|| (b))|| (c) produces the same result, with the same side effects occurring in the same order, as evaluation of the expression(a)|| ((b)|| (c)).

Each operand of the conditional-or operator must be of typeboolean orBoolean, or a compile-time error occurs.

The type of a conditional-or expression is alwaysboolean.

At run time, the left-hand operand expression is evaluated first; if the result has typeBoolean, it is subjected to unboxing conversion (§5.1.8).

If the resulting value istrue, the value of the conditional-or expression istrue and the right-hand operand expression is not evaluated.

If the value of the left-hand operand isfalse, then the right-hand expression is evaluated; if the result has typeBoolean, it is subjected to unboxing conversion (§5.1.8). The resulting value becomes the value of the conditional-or expression.

Thus,|| computes the same result as| onboolean orBoolean operands. It differs only in that the right-hand operand expression is evaluated conditionally rather than always.

15.25. Conditional Operator? :

The conditional operator? : uses the boolean value of one expression to decide which of two other expressions should be evaluated.

ConditionalExpression:
ConditionalOrExpression
ConditionalOrExpression?Expression:ConditionalExpression
ConditionalOrExpression?Expression:LambdaExpression

The conditional operator is syntactically right-associative (it groups right-to-left). Thus,a?b:c?d:e?f:g means the same asa?b:(c?d:(e?f:g)).

The conditional operator has three operand expressions.? appears between the first and second expressions, and: appears between the second and third expressions.

The first expression must be of typeboolean orBoolean, or a compile-time error occurs.

It is a compile-time error for either the second or the third operand expression to be an invocation of avoid method.

In fact, by the grammar of expression statements (§14.8), it is not permitted for a conditional expression to appear in any context where an invocation of avoid method could appear.

There are three kinds of conditional expressions, classified according to the second and third operand expressions:boolean conditional expressions,numeric conditional expressions, andreference conditional expressions. The classification rules are as follows:

  • If both the second and the third operand expressions areboolean expressions, the conditional expression is a boolean conditional expression.

    For the purpose of classifying a conditional, the following expressions are boolean expressions:

    • An expression of a standalone form (§15.2) that has typeboolean orBoolean.

    • A parenthesizedboolean expression (§15.8.5).

    • A class instance creation expression (§15.9) for classBoolean.

    • A method invocation expression (§15.12) for which the chosen most specific method (§15.12.2.5) has return typeboolean orBoolean.

      Note that, for a generic method, this is the typebefore instantiating the method's type arguments.

    • Aboolean conditional expression.

  • If both the second and the third operand expressions arenumeric expressions, the conditional expression is a numeric conditional expression.

    For the purpose of classifying a conditional, the following expressions are numeric expressions:

    • An expression of a standalone form (§15.2) with a type that is convertible to a numeric type (§4.2,§5.1.8).

    • A parenthesized numeric expression (§15.8.5).

    • A class instance creation expression (§15.9) for a class that is convertible to a numeric type.

    • A method invocation expression (§15.12) for which the chosen most specific method (§15.12.2.5) has a return type that is convertible to a numeric type.

    • A numeric conditional expression.

  • Otherwise, the conditional expression is a reference conditional expression.

The process for determining the type of a conditional expression depends on the kind of conditional expression, as outlined in the following sections.

The following tables summarize the rules above by giving the type of a conditional expression for all possible types of its second and third operands. bnp(..) means to apply binary numeric promotion. The form "T | bnp(..)" is used where one operand is a constant expression of typeint and may be representable in typeT, where binary numeric promotion is used if the operand is not representable in typeT. The operand typeObject means any reference type other than thenull type and the eight wrapper classesBoolean,Byte,Short,Character,Integer,Long,Float,Double.

Table 15.25-A. Conditional expression type (Primitive 3rd operand, Part I)

3rdbyteshortcharint
2nd    
bytebyteshortbnp(byte,char)byte | bnp(byte,int)
Bytebyteshortbnp(Byte,char)byte | bnp(Byte,int)
shortshortshortbnp(short,char)short | bnp(short,int)
Shortshortshortbnp(Short,char)short | bnp(Short,int)
charbnp(char,byte)bnp(char,short)charchar | bnp(char,int)
Characterbnp(Character,byte)bnp(Character,short)charchar | bnp(Character,int)
intbyte | bnp(int,byte)short | bnp(int,short)char | bnp(int,char)int
Integerbnp(Integer,byte)bnp(Integer,short)bnp(Integer,char)int
longbnp(long,byte)bnp(long,short)bnp(long,char)bnp(long,int)
Longbnp(Long,byte)bnp(Long,short)bnp(Long,char)bnp(Long,int)
floatbnp(float,byte)bnp(float,short)bnp(float,char)bnp(float,int)
Floatbnp(Float,byte)bnp(Float,short)bnp(Float,char)bnp(Float,int)
doublebnp(double,byte)bnp(double,short)bnp(double,char)bnp(double,int)
Doublebnp(Double,byte)bnp(Double,short)bnp(Double,char)bnp(Double,int)
booleanlub(Boolean,Byte)lub(Boolean,Short)lub(Boolean,Character)lub(Boolean,Integer)
Booleanlub(Boolean,Byte)lub(Boolean,Short)lub(Boolean,Character)lub(Boolean,Integer)
nulllub(null,Byte)lub(null,Short)lub(null,Character)lub(null,Integer)
Objectlub(Object,Byte)lub(Object,Short)lub(Object,Character)lub(Object,Integer)

Table 15.25-B. Conditional expression type (Primitive 3rd operand, Part II)

3rdlongfloatdoubleboolean
2nd    
bytebnp(byte,long)bnp(byte,float)bnp(byte,double)lub(Byte,Boolean)
Bytebnp(Byte,long)bnp(Byte,float)bnp(Byte,double)lub(Byte,Boolean)
shortbnp(short,long)bnp(short,float)bnp(short,double)lub(Short,Boolean)
Shortbnp(Short,long)bnp(Short,float)bnp(Short,double)lub(Short,Boolean)
charbnp(char,long)bnp(char,float)bnp(char,double)lub(Character,Boolean)
Characterbnp(Character,long)bnp(Character,float)bnp(Character,double)lub(Character,Boolean)
intbnp(int,long)bnp(int,float)bnp(int,double)lub(Integer,Boolean)
Integerbnp(Integer,long)bnp(Integer,float)bnp(Integer,double)lub(Integer,Boolean)
longlongbnp(long,float)bnp(long,double)lub(Long,Boolean)
Longlongbnp(Long,float)bnp(Long,double)lub(Long,Boolean)
floatbnp(float,long)floatbnp(float,double)lub(Float,Boolean)
Floatbnp(Float,long)floatbnp(Float,double)lub(Float,Boolean)
doublebnp(double,long)bnp(double,float)doublelub(Double,Boolean)
Doublebnp(Double,long)bnp(Double,float)doublelub(Double,Boolean)
booleanlub(Boolean,Long)lub(Boolean,Float)lub(Boolean,Double)boolean
Booleanlub(Boolean,Long)lub(Boolean,Float)lub(Boolean,Double)boolean
nulllub(null,Long)lub(null,Float)lub(null,Double)lub(null,Boolean)
Objectlub(Object,Long)lub(Object,Float)lub(Object,Double)lub(Object,Boolean)

Table 15.25-C. Conditional expression type (Reference 3rd operand, Part I)

3rdByteShortCharacterInteger
2nd    
bytebyteshortbnp(byte,Character)bnp(byte,Integer)
ByteByteshortbnp(Byte,Character)bnp(Byte,Integer)
shortshortshortbnp(short,Character)bnp(short,Integer)
ShortshortShortbnp(Short,Character)bnp(Short,Integer)
charbnp(char,Byte)bnp(char,Short)charbnp(char,Integer)
Characterbnp(Character,Byte)bnp(Character,Short)Characterbnp(Character,Integer)
intbyte | bnp(int,Byte)short | bnp(int,Short)char | bnp(int,Character)int
Integerbnp(Integer,Byte)bnp(Integer,Short)bnp(Integer,Character)Integer
longbnp(long,Byte)bnp(long,Short)bnp(long,Character)bnp(long,Integer)
Longbnp(Long,Byte)bnp(Long,Short)bnp(Long,Character)bnp(Long,Integer)
floatbnp(float,Byte)bnp(float,Short)bnp(float,Character)bnp(float,Integer)
Floatbnp(Float,Byte)bnp(Float,Short)bnp(Float,Character)bnp(Float,Integer)
doublebnp(double,Byte)bnp(double,Short)bnp(double,Character)bnp(double,Integer)
Doublebnp(Double,Byte)bnp(Double,Short)bnp(Double,Character)bnp(Double,Integer)
booleanlub(Boolean,Byte)lub(Boolean,Short)lub(Boolean,Character)lub(Boolean,Integer)
Booleanlub(Boolean,Byte)lub(Boolean,Short)lub(Boolean,Character)lub(Boolean,Integer)
nullByteShortCharacterInteger
Objectlub(Object,Byte)lub(Object,Short)lub(Object,Character)lub(Object,Integer)

Table 15.25-D. Conditional expression type (Reference 3rd operand, Part II)

3rdLongFloatDoubleBoolean
2nd    
bytebnp(byte,Long)bnp(byte,Float)bnp(byte,Double)lub(Byte,Boolean)
Bytebnp(Byte,Long)bnp(Byte,Float)bnp(Byte,Double)lub(Byte,Boolean)
shortbnp(short,Long)bnp(short,Float)bnp(short,Double)lub(Short,Boolean)
Shortbnp(Short,Long)bnp(Short,Float)bnp(Short,Double)lub(Short,Boolean)
charbnp(char,Long)bnp(char,Float)bnp(char,Double)lub(Character,Boolean)
Characterbnp(Character,Long)bnp(Character,Float)bnp(Character,Double)lub(Character,Boolean)
intbnp(int,Long)bnp(int,Float)bnp(int,Double)lub(Integer,Boolean)
Integerbnp(Integer,Long)bnp(Integer,Float)bnp(Integer,Double)lub(Integer,Boolean)
longlongbnp(long,Float)bnp(long,Double)lub(Long,Boolean)
LongLongbnp(Long,Float)bnp(Long,Double)lub(Long,Boolean)
floatbnp(float,Long)floatbnp(float,Double)lub(Float,Boolean)
Floatbnp(Float,Long)Floatbnp(Float,Double)lub(Float,Boolean)
doublebnp(double,Long)bnp(double,Float)doublelub(Double,Boolean)
Doublebnp(Double,Long)bnp(Double,Float)Doublelub(Double,Boolean)
booleanlub(Boolean,Long)lub(Boolean,Float)lub(Boolean,Double)boolean
Booleanlub(Boolean,Long)lub(Boolean,Float)lub(Boolean,Double)Boolean
nullLongFloatDoubleBoolean
Objectlub(Object,Long)lub(Object,Float)lub(Object,Double)lub(Object,Boolean)

Table 15.25-E. Conditional expression type (Reference 3rd operand, Part III)

3rdnullObject
2nd  
bytelub(Byte,null)lub(Byte,Object)
ByteBytelub(Byte,Object)
shortlub(Short,null)lub(Short,Object)
ShortShortlub(Short,Object)
charlub(Character,null)lub(Character,Object)
CharacterCharacterlub(Character,Object)
intlub(Integer,null)lub(Integer,Object)
IntegerIntegerlub(Integer,Object)
longlub(Long,null)lub(Long,Object)
LongLonglub(Long,Object)
floatlub(Float,null)lub(Float,Object)
FloatFloatlub(Float,Object)
doublelub(Double,null)lub(Double,Object)
DoubleDoublelub(Double,Object)
booleanlub(Boolean,null)lub(Boolean,Object)
BooleanBooleanlub(Boolean,Object)
nullnulllub(null,Object)
ObjectObjectObject

At run time, the first operand expression of the conditional expression is evaluated first. If necessary, unboxing conversion is performed on the result.

The resultingboolean value is then used to choose either the second or the third operand expression:

  • If the value of the first operand istrue, then the second operand expression is chosen.

  • If the value of the first operand isfalse, then the third operand expression is chosen.

The chosen operand expression is then evaluated and the resulting value is converted to the type of the conditional expression as determined by the rules stated below.

This conversion may include boxing or unboxing conversion (§5.1.7,§5.1.8).

The operand expression not chosen is not evaluated for that particular evaluation of the conditional expression.

15.25.1. Boolean Conditional Expressions

Boolean conditional expressions are standalone expressions (§15.2).

The type of a boolean conditional expression is determined as follows:

  • If the second and third operands are both of typeBoolean, the conditional expression has typeBoolean.

  • Otherwise, the conditional expression has typeboolean.

15.25.2. Numeric Conditional Expressions

Numeric conditional expressions are standalone expressions (§15.2).

The type of a numeric conditional expression is determined as follows:

  • If the second and third operands have the same type, then that is the type of the conditional expression.

  • If one of the second and third operands is of primitive typeT, and the type of the other is the result of applying boxing conversion (§5.1.7) toT, then the type of the conditional expression isT.

  • If one of the operands is of typebyte orByte and the other is of typeshort orShort, then the type of the conditional expression isshort.

  • If one of the operands is of typeT whereT isbyte,short, orchar, and the other operand is a constant expression (§15.28) of typeint whose value is representable in typeT, then the type of the conditional expression isT.

  • If one of the operands is of typeT, whereT isByte,Short, orCharacter, and the other operand is a constant expression of typeint whose value is representable in the typeU which is the result of applying unboxing conversion toT, then the type of the conditional expression isU.

  • Otherwise, binary numeric promotion (§5.6.2) is applied to the operand types, and the type of the conditional expression is the promoted type of the second and third operands.

    Note that binary numeric promotion performs value set conversion (§5.1.13) and may perform unboxing conversion (§5.1.8).

15.25.3. Reference Conditional Expressions

A reference conditional expression is a poly expression if it appears in an assignment context or an invocation context (§5.2.§5.3). Otherwise, it is a standalone expression.

Where a poly reference conditional expression appears in a context of a particular kind with target typeT, its second and third operand expressions similarly appear in a context of the same kind with target typeT.

The type of a poly reference conditional expression is the same as its target type.

The type of a standalone reference conditional expression is determined as follows:

  • If the second and third operands have the same type (which may be the null type), then that is the type of the conditional expression.

  • If the type of one of the second and third operands is the null type, and the type of the other operand is a reference type, then the type of the conditional expression is that reference type.

  • Otherwise, the second and third operands are of typesS1 andS2 respectively. LetT1 be the type that results from applying boxing conversion toS1, and letT2 be the type that results from applying boxing conversion toS2. The type of the conditional expression is the result of applying capture conversion (§5.1.10) to lub(T1,T2).

Because reference conditional expressions can be poly expressions, they can "pass down" context to their operands. This allows lambda expressions and method reference expressions to appear as operands:

return ... ? (x-> x) : (x-> -x);

It also allows use of extra information to improve type checking of generic method invocations. Prior to Java SE 8, this assignment was well-typed:

List<String> ls = Arrays.asList();

but this was not:

List<String> ls = ... ? Arrays.asList() : Arrays.asList("a","b");

The rules above allow both assignments to be considered well-typed.

Note that a reference conditional expression does not have tocontain a poly expression as an operand in order tobe a poly expression. It is a poly expression simply by virtue of the context in which it appears. For example, in the following code, the conditional expression is a poly expression, and each operand is considered to be in an assignment context targetingClass<? super Integer>:

Class<? super Integer> choose(boolean b,                              Class<Integer> c1,                              Class<Number> c2) {    return b ? c1 : c2;}

If the conditional expression was not a poly expression, then a compile-time error would occur, as its type would be lub(Class<Integer>,Class<Number>) =Class<? extends Number> which is incompatible with the return type ofchoose.

15.26. Assignment Operators

There are 12assignment operators; all are syntactically right-associative (they group right-to-left). Thus,a=b=c meansa=(b=c), which assigns the value ofc tob and then assigns the value ofb toa.

AssignmentExpression:
ConditionalExpression
Assignment
Assignment:
LeftHandSideAssignmentOperatorExpression
LeftHandSide:
ExpressionName
FieldAccess
ArrayAccess
AssignmentOperator:
(one of)
=*=/=%=+=-=<<=>>=>>>=&=^=|=

The result of the first operand of an assignment operator must be a variable, or a compile-time error occurs.

This operand may be a named variable, such as a local variable or a field of the current object or class, or it may be a computed variable, as can result from a field access (§15.11) or an array access (§15.10.3).

The type of the assignment expression is the type of the variable after capture conversion (§5.1.10).

At run time, the result of the assignment expression is the value of the variable after the assignment has occurred. The result of an assignment expression is not itself a variable.

A variable that is declaredfinal cannot be assigned to (unless it is definitely unassigned (§16 (Definite Assignment))), because when an access of such afinal variable is used as an expression, the result is a value, not a variable, and so it cannot be used as the first operand of an assignment operator.

15.26.1. Simple Assignment Operator=

A compile-time error occurs if the type of the right-hand operand cannot be converted to the type of the variable by assignment conversion (§5.2).

At run time, the expression is evaluated in one of three ways.

If the left-hand operand expression is a field access expressione.f (§15.11), possibly enclosed in one or more pairs of parentheses, then:

  • First, the expressione is evaluated. If evaluation ofe completes abruptly, the assignment expression completes abruptly for the same reason.

  • Next, the right hand operand is evaluated. If evaluation of the right hand expression completes abruptly, the assignment expression completes abruptly for the same reason.

  • Then, if the field denoted bye.f is notstatic and the result of the evaluation ofe above isnull, then aNullPointerException is thrown.

  • Otherwise, the variable denoted bye.f is assigned the value of the right hand operand as computed above.

If the left-hand operand is an array access expression (§15.10.3), possibly enclosed in one or more pairs of parentheses, then:

  • First, the array reference subexpression of the left-hand operand array access expression is evaluated. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason; the index subexpression (of the left-hand operand array access expression) and the right-hand operand are not evaluated and no assignment occurs.

  • Otherwise, the index subexpression of the left-hand operand array access expression is evaluated. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason and the right-hand operand is not evaluated and no assignment occurs.

  • Otherwise, the right-hand operand is evaluated. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason and no assignment occurs.

  • Otherwise, if the value of the array reference subexpression isnull, then no assignment occurs and aNullPointerException is thrown.

  • Otherwise, the value of the array reference subexpression indeed refers to an array. If the value of the index subexpression is less than zero, or greater than or equal to thelength of the array, then no assignment occurs and anArrayIndexOutOfBoundsException is thrown.

  • Otherwise, the value of the index subexpression is used to select a component of the array referred to by the value of the array reference subexpression.

    This component is a variable; call its typeSC. Also, letTC be the type of the left-hand operand of the assignment operator as determined at compile time. Then there are two possibilities:

    • IfTC is a primitive type, thenSC is necessarily the same asTC.

      The value of the right-hand operand is converted to the type of the selected array component, is subjected to value set conversion (§5.1.13) to the appropriate standard value set (not an extended-exponent value set), and the result of the conversion is stored into the array component.

    • IfTC is a reference type, thenSC may not be the same asTC, but rather a type that extends or implementsTC.

      LetRC be the class of the object referred to by the value of the right-hand operand at run time.

      A Java compiler may be able to prove at compile time that the array component will be of typeTC exactly (for example,TC might befinal). But if a Java compiler cannot prove at compile time that the array component will be of typeTC exactly, then a check must be performed at run time to ensure that the classRC is assignment compatible (§5.2) with the actual typeSC of the array component.

      This check is similar to a narrowing cast (§5.5,§15.16), except that if the check fails, anArrayStoreException is thrown rather than aClassCastException.

      If classRC is not assignable to typeSC, then no assignment occurs and anArrayStoreException is thrown.

      Otherwise, the reference value of the right-hand operand is stored into the selected array component.

Otherwise, three steps are required:

  • First, the left-hand operand is evaluated to produce a variable. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason; the right-hand operand is not evaluated and no assignment occurs.

  • Otherwise, the right-hand operand is evaluated. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason and no assignment occurs.

  • Otherwise, the value of the right-hand operand is converted to the type of the left-hand variable, is subjected to value set conversion (§5.1.13) to the appropriate standard value set (not an extended-exponent value set), and the result of the conversion is stored into the variable.

Example 15.26.1-1. Simple Assignment To An Array Component

class ArrayReferenceThrow extends RuntimeException { }class IndexThrow          extends RuntimeException { }class RightHandSideThrow  extends RuntimeException { }class IllustrateSimpleArrayAssignment {    static Object[] objects = { new Object(), new Object() };    static Thread[] threads = { new Thread(), new Thread() };    static Object[] arrayThrow() {        throw new ArrayReferenceThrow();    }    static int indexThrow() {        throw new IndexThrow();    }    static Thread rightThrow() {        throw new RightHandSideThrow();    }    static String name(Object q) {        String sq = q.getClass().getName();        int k = sq.lastIndexOf('.');        return (k < 0) ? sq : sq.substring(k+1);    }    static void testFour(Object[] x, int j, Object y) {        String sx = x == null ? "null" : name(x[0]) + "s";        String sy = name(y);        System.out.println();        try {            System.out.print(sx + "[throw]=throw => ");            x[indexThrow()] = rightThrow();            System.out.println("Okay!");        } catch (Throwable e) { System.out.println(name(e)); }        try {            System.out.print(sx + "[throw]=" + sy + " => ");            x[indexThrow()] = y;            System.out.println("Okay!");        } catch (Throwable e) { System.out.println(name(e)); }        try {            System.out.print(sx + "[" + j + "]=throw => ");            x[j] = rightThrow();            System.out.println("Okay!");        } catch (Throwable e) { System.out.println(name(e)); }        try {            System.out.print(sx + "[" + j + "]=" + sy + " => ");            x[j] = y;            System.out.println("Okay!");        } catch (Throwable e) { System.out.println(name(e)); }    }    public static void main(String[] args) {        try {            System.out.print("throw[throw]=throw => ");            arrayThrow()[indexThrow()] = rightThrow();            System.out.println("Okay!");        } catch (Throwable e) { System.out.println(name(e)); }        try {            System.out.print("throw[throw]=Thread => ");            arrayThrow()[indexThrow()] = new Thread();            System.out.println("Okay!");        } catch (Throwable e) { System.out.println(name(e)); }        try {            System.out.print("throw[1]=throw => ");            arrayThrow()[1] = rightThrow();            System.out.println("Okay!");        } catch (Throwable e) { System.out.println(name(e)); }        try {            System.out.print("throw[1]=Thread => ");            arrayThrow()[1] = new Thread();            System.out.println("Okay!");        } catch (Throwable e) { System.out.println(name(e)); }        testFour(null, 1, new StringBuffer());        testFour(null, 9, new Thread());        testFour(objects, 1, new StringBuffer());        testFour(objects, 1, new Thread());        testFour(objects, 9, new StringBuffer());        testFour(objects, 9, new Thread());        testFour(threads, 1, new StringBuffer());        testFour(threads, 1, new Thread());        testFour(threads, 9, new StringBuffer());        testFour(threads, 9, new Thread());    }}

This program produces the output:

throw[throw]=throw => ArrayReferenceThrowthrow[throw]=Thread => ArrayReferenceThrowthrow[1]=throw => ArrayReferenceThrowthrow[1]=Thread => ArrayReferenceThrownull[throw]=throw => IndexThrownull[throw]=StringBuffer => IndexThrownull[1]=throw => RightHandSideThrownull[1]=StringBuffer => NullPointerExceptionnull[throw]=throw => IndexThrownull[throw]=Thread => IndexThrownull[9]=throw => RightHandSideThrownull[9]=Thread => NullPointerExceptionObjects[throw]=throw => IndexThrowObjects[throw]=StringBuffer => IndexThrowObjects[1]=throw => RightHandSideThrowObjects[1]=StringBuffer => Okay!Objects[throw]=throw => IndexThrowObjects[throw]=Thread => IndexThrowObjects[1]=throw => RightHandSideThrowObjects[1]=Thread => Okay!Objects[throw]=throw => IndexThrowObjects[throw]=StringBuffer => IndexThrowObjects[9]=throw => RightHandSideThrowObjects[9]=StringBuffer => ArrayIndexOutOfBoundsExceptionObjects[throw]=throw => IndexThrowObjects[throw]=Thread => IndexThrowObjects[9]=throw => RightHandSideThrowObjects[9]=Thread => ArrayIndexOutOfBoundsExceptionThreads[throw]=throw => IndexThrowThreads[throw]=StringBuffer => IndexThrowThreads[1]=throw => RightHandSideThrowThreads[1]=StringBuffer => ArrayStoreExceptionThreads[throw]=throw => IndexThrowThreads[throw]=Thread => IndexThrowThreads[1]=throw => RightHandSideThrowThreads[1]=Thread => Okay!Threads[throw]=throw => IndexThrowThreads[throw]=StringBuffer => IndexThrowThreads[9]=throw => RightHandSideThrowThreads[9]=StringBuffer => ArrayIndexOutOfBoundsExceptionThreads[throw]=throw => IndexThrowThreads[throw]=Thread => IndexThrowThreads[9]=throw => RightHandSideThrowThreads[9]=Thread => ArrayIndexOutOfBoundsException

The most interesting case of the lot is thirteenth from the end:

Threads[1]=StringBuffer => ArrayStoreException

which indicates that the attempt to store a reference to aStringBuffer into an array whose components are of typeThread throws anArrayStoreException. The code is type-correct at compile time: the assignment has a left-hand side of typeObject[] and a right-hand side of typeObject. At run time, the first actual argument to methodtestFour is a reference to an instance of "array ofThread" and the third actual argument is a reference to an instance of classStringBuffer.


15.26.2. Compound Assignment Operators

A compound assignment expression of the formE1 op= E2 is equivalent toE1 = (T) ((E1) op (E2)), whereT is the type ofE1, except thatE1 is evaluated only once.

For example, the following code is correct:

short x = 3;x += 4.6;

and results inx having the value7 because it is equivalent to:

short x = 3;x = (short)(x + 4.6);

At run time, the expression is evaluated in one of two ways.

If the left-hand operand expression is not an array access expression, then:

  • First, the left-hand operand is evaluated to produce a variable. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason; the right-hand operand is not evaluated and no assignment occurs.

  • Otherwise, the value of the left-hand operand is saved and then the right-hand operand is evaluated. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason and no assignment occurs.

  • Otherwise, the saved value of the left-hand variable and the value of the right-hand operand are used to perform the binary operation indicated by the compound assignment operator. If this operation completes abruptly, then the assignment expression completes abruptly for the same reason and no assignment occurs.

  • Otherwise, the result of the binary operation is converted to the type of the left-hand variable, subjected to value set conversion (§5.1.13) to the appropriate standard value set (not an extended-exponent value set), and the result of the conversion is stored into the variable.

If the left-hand operand expression is an array access expression (§15.10.3), then:

  • First, the array reference subexpression of the left-hand operand array access expression is evaluated. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason; the index subexpression (of the left-hand operand array access expression) and the right-hand operand are not evaluated and no assignment occurs.

  • Otherwise, the index subexpression of the left-hand operand array access expression is evaluated. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason and the right-hand operand is not evaluated and no assignment occurs.

  • Otherwise, if the value of the array reference subexpression isnull, then no assignment occurs and aNullPointerException is thrown.

  • Otherwise, the value of the array reference subexpression indeed refers to an array. If the value of the index subexpression is less than zero, or greater than or equal to thelength of the array, then no assignment occurs and anArrayIndexOutOfBoundsException is thrown.

  • Otherwise, the value of the index subexpression is used to select a component of the array referred to by the value of the array reference subexpression. The value of this component is saved and then the right-hand operand is evaluated. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason and no assignment occurs.

    For a simple assignment operator, the evaluation of the right-hand operand occurs before the checks of the array reference subexpression and the index subexpression, but for a compound assignment operator, the evaluation of the right-hand operand occurs after these checks.

  • Otherwise, consider the array component selected in the previous step, whose value was saved. This component is a variable; call its typeS. Also, letT be the type of the left-hand operand of the assignment operator as determined at compile time.

    • IfT is a primitive type, thenS is necessarily the same asT.

      The saved value of the array component and the value of the right-hand operand are used to perform the binary operation indicated by the compound assignment operator.

      If this operation completes abruptly (the only possibility is an integer division by zero - see§15.17.2), then the assignment expression completes abruptly for the same reason and no assignment occurs.

      Otherwise, the result of the binary operation is converted to the type of the selected array component, subjected to value set conversion (§5.1.13) to the appropriate standard value set (not an extended-exponent value set), and the result of the conversion is stored into the array component.

    • IfT is a reference type, then it must beString. Because classString is afinal class,S must also beString.

      Therefore the run-time check that is sometimes required for the simple assignment operator is never required for a compound assignment operator.

      The saved value of the array component and the value of the right-hand operand are used to perform the binary operation (string concatenation) indicated by the compound assignment operator (which is necessarily+=). If this operation completes abruptly, then the assignment expression completes abruptly for the same reason and no assignment occurs.

      Otherwise, theString result of the binary operation is stored into the array component.

Example 15.26.2-1. Compound Assignment To An Array Component

class ArrayReferenceThrow extends RuntimeException { }class IndexThrow          extends RuntimeException { }class RightHandSideThrow  extends RuntimeException { }class IllustrateCompoundArrayAssignment {    static String[] strings = { "Simon", "Garfunkel" };    static double[] doubles = { Math.E, Math.PI };    static String[] stringsThrow() {        throw new ArrayReferenceThrow();    }    static double[] doublesThrow() {        throw new ArrayReferenceThrow();    }    static int indexThrow() {        throw new IndexThrow();    }    static String stringThrow() {        throw new RightHandSideThrow();    }    static double doubleThrow() {        throw new RightHandSideThrow();    }    static String name(Object q) {        String sq = q.getClass().getName();        int k = sq.lastIndexOf('.');        return (k < 0) ? sq : sq.substring(k+1);    }    static void testEight(String[] x, double[] z, int j) {        String sx = (x == null) ? "null" : "Strings";        String sz = (z == null) ? "null" : "doubles";        System.out.println();        try {            System.out.print(sx + "[throw]+=throw => ");            x[indexThrow()] += stringThrow();            System.out.println("Okay!");        } catch (Throwable e) { System.out.println(name(e)); }        try {            System.out.print(sz + "[throw]+=throw => ");            z[indexThrow()] += doubleThrow();            System.out.println("Okay!");        } catch (Throwable e) { System.out.println(name(e)); }        try {            System.out.print(sx + "[throw]+=\"heh\" => ");            x[indexThrow()] += "heh";            System.out.println("Okay!");        } catch (Throwable e) { System.out.println(name(e)); }        try {            System.out.print(sz + "[throw]+=12345 => ");            z[indexThrow()] += 12345;            System.out.println("Okay!");        } catch (Throwable e) { System.out.println(name(e)); }        try {            System.out.print(sx + "[" + j + "]+=throw => ");            x[j] += stringThrow();            System.out.println("Okay!");        } catch (Throwable e) { System.out.println(name(e)); }        try {            System.out.print(sz + "[" + j + "]+=throw => ");            z[j] += doubleThrow();            System.out.println("Okay!");        } catch (Throwable e) { System.out.println(name(e)); }        try {            System.out.print(sx + "[" + j + "]+=\"heh\" => ");            x[j] += "heh";            System.out.println("Okay!");        } catch (Throwable e) { System.out.println(name(e)); }        try {            System.out.print(sz + "[" + j + "]+=12345 => ");            z[j] += 12345;            System.out.println("Okay!");        } catch (Throwable e) { System.out.println(name(e)); }    }    public static void main(String[] args) {        try {            System.out.print("throw[throw]+=throw => ");            stringsThrow()[indexThrow()] += stringThrow();            System.out.println("Okay!");        } catch (Throwable e) { System.out.println(name(e)); }        try {            System.out.print("throw[throw]+=throw => ");            doublesThrow()[indexThrow()] += doubleThrow();            System.out.println("Okay!");        } catch (Throwable e) { System.out.println(name(e)); }        try {            System.out.print("throw[throw]+=\"heh\" => ");            stringsThrow()[indexThrow()] += "heh";            System.out.println("Okay!");        } catch (Throwable e) { System.out.println(name(e)); }        try {            System.out.print("throw[throw]+=12345 => ");            doublesThrow()[indexThrow()] += 12345;            System.out.println("Okay!");        } catch (Throwable e) { System.out.println(name(e)); }        try {            System.out.print("throw[1]+=throw => ");            stringsThrow()[1] += stringThrow();            System.out.println("Okay!");        } catch (Throwable e) { System.out.println(name(e)); }        try {            System.out.print("throw[1]+=throw => ");            doublesThrow()[1] += doubleThrow();            System.out.println("Okay!");        } catch (Throwable e) { System.out.println(name(e)); }        try {            System.out.print("throw[1]+=\"heh\" => ");            stringsThrow()[1] += "heh";            System.out.println("Okay!");        } catch (Throwable e) { System.out.println(name(e)); }        try {            System.out.print("throw[1]+=12345 => ");            doublesThrow()[1] += 12345;            System.out.println("Okay!");        } catch (Throwable e) { System.out.println(name(e)); }        testEight(null, null, 1);        testEight(null, null, 9);        testEight(strings, doubles, 1);        testEight(strings, doubles, 9);    }}

This program produces the output:

throw[throw]+=throw => ArrayReferenceThrowthrow[throw]+=throw => ArrayReferenceThrowthrow[throw]+="heh" => ArrayReferenceThrowthrow[throw]+=12345 => ArrayReferenceThrowthrow[1]+=throw => ArrayReferenceThrowthrow[1]+=throw => ArrayReferenceThrowthrow[1]+="heh" => ArrayReferenceThrowthrow[1]+=12345 => ArrayReferenceThrownull[throw]+=throw => IndexThrownull[throw]+=throw => IndexThrownull[throw]+="heh" => IndexThrownull[throw]+=12345 => IndexThrownull[1]+=throw => NullPointerExceptionnull[1]+=throw => NullPointerExceptionnull[1]+="heh" => NullPointerExceptionnull[1]+=12345 => NullPointerExceptionnull[throw]+=throw => IndexThrownull[throw]+=throw => IndexThrownull[throw]+="heh" => IndexThrownull[throw]+=12345 => IndexThrownull[9]+=throw => NullPointerExceptionnull[9]+=throw => NullPointerExceptionnull[9]+="heh" => NullPointerExceptionnull[9]+=12345 => NullPointerExceptionStrings[throw]+=throw => IndexThrowdoubles[throw]+=throw => IndexThrowStrings[throw]+="heh" => IndexThrowdoubles[throw]+=12345 => IndexThrowStrings[1]+=throw => RightHandSideThrowdoubles[1]+=throw => RightHandSideThrowStrings[1]+="heh" => Okay!doubles[1]+=12345 => Okay!Strings[throw]+=throw => IndexThrowdoubles[throw]+=throw => IndexThrowStrings[throw]+="heh" => IndexThrowdoubles[throw]+=12345 => IndexThrowStrings[9]+=throw => ArrayIndexOutOfBoundsExceptiondoubles[9]+=throw => ArrayIndexOutOfBoundsExceptionStrings[9]+="heh" => ArrayIndexOutOfBoundsExceptiondoubles[9]+=12345 => ArrayIndexOutOfBoundsException

The most interesting cases of the lot are eleventh and twelfth from the end:

Strings[1]+=throw => RightHandSideThrowdoubles[1]+=throw => RightHandSideThrow

They are the cases where a right-hand side that throws an exception actually gets to throw the exception; moreover, they are the only such cases in the lot. This demonstrates that the evaluation of the right-hand operand indeed occurs after the checks for a null array reference value and an out-of-bounds index value.


Example 15.26.2-2. Value Of Left-Hand Side Of Compound Assignment Is Saved Before Evaluation Of Right-Hand Side

class Test {    public static void main(String[] args) {        int k = 1;        int[] a = { 1 };        k += (k = 4) * (k + 2);        a[0] += (a[0] = 4) * (a[0] + 2);        System.out.println("k==" + k + " and a[0]==" + a[0]);    }}

This program produces the output:

k==25 and a[0]==25

The value1 ofk is saved by the compound assignment operator+= before its right-hand operand(k = 4) * (k + 2) is evaluated. Evaluation of this right-hand operand then assigns4 tok, calculates the value6 fork + 2, and then multiplies4 by6 to get24. This is added to the saved value1 to get25, which is then stored intok by the+= operator. An identical analysis applies to the case that usesa[0].

In short, the statements:

k += (k = 4) * (k + 2);a[0] += (a[0] = 4) * (a[0] + 2);

behave in exactly the same manner as the statements:

k = k + (k = 4) * (k + 2);a[0] = a[0] + (a[0] = 4) * (a[0] + 2);

15.27. Lambda Expressions

A lambda expression is like a method: it provides a list of formal parameters and a body - an expression or block - expressed in terms of those parameters.

LambdaExpression:
LambdaParameters->LambdaBody

Lambda expressions are always poly expressions (§15.2).

It is a compile-time error if a lambda expression occurs in a program in someplace other than an assignment context (§5.2), an invocation context (§5.3), or a casting context (§5.5).

Evaluation of a lambda expression produces an instance of a functional interface (§9.8). Lambda expression evaluation doesnot cause the execution of the expression's body; instead, this may occur at a later time when an appropriate method of the functional interface is invoked.

Here are some examples of lambda expressions:

() -> {}                // No parameters; result is void() -> 42                // No parameters, expression body() -> null              // No parameters, expression body() -> { return 42; }    // No parameters, block body with return() -> { System.gc(); }  // No parameters, void block body() -> {                 // Complex block body with returns  if (true) return 12;  else {    int result = 15;    for (int i = 1; i < 10; i++)      result *= i;    return result;  }}                          (int x) -> x+1              // Single declared-type parameter(int x) -> { return x+1; }  // Single declared-type parameter(x) -> x+1                  // Single inferred-type parameterx -> x+1                    // Parentheses optional for                            // single inferred-type parameter(String s) -> s.length()      // Single declared-type parameter(Thread t) -> { t.start(); }  // Single declared-type parameters -> s.length()               // Single inferred-type parametert -> { t.start(); }           // Single inferred-type parameter(int x, int y) -> x+y  // Multiple declared-type parameters(x, y) -> x+y          // Multiple inferred-type parameters(x, int y) -> x+y    // Illegal: can't mix inferred and declared types(x, final y) -> x+y  // Illegal: no modifiers with inferred types

This syntax has the advantage of minimizing bracket noise around simple lambda expressions, which is especially beneficial when a lambda expression is an argument to a method, or when the body is another lambda expression. It also clearly distinguishes between its expression and statement forms, which avoids ambiguities or over-reliance on ';' tokens. When some extra bracketing is needed to visually distinguish either the full lambda expression or its body expression, parentheses are naturally supported (just as in other cases in which operator precedence is unclear).

The syntax has some parsing challenges. The Java programming language has always required arbitrary lookahead to distinguish between types and expressions after a '(' token: what follows may be a cast or a parenthesized expression. This was made worse when generics reused the binary operators '<' and '>' in types. Lambda expressions introduce a new possibility: the tokens following '(' may describe a type, an expression, or a lambda parameter list. Some tokens immediately indicate a parameter list (annotations,final); in other cases there are certain patterns that must be interpreted as parameter lists (two names in a row, a ',' not nested inside of '<' and '>'); and sometimes, the decision cannot be made until a '->' is encountered after a ')'. The simplest way to think of how this might be efficiently parsed is with a state machine: each state represents a subset of possible interpretations (type, expression, or parameters), and when the machine transitions to a state in which the set is a singleton, the parser knows which case it is. This does not map very elegantly to a fixed-lookahead grammar, however.

There is no special nullary form: a lambda expression with zero arguments is expressed as()-> .... The obvious special-case syntax,-> ..., does not work because it introduces an ambiguity between argument lists and casts:(x)-> ....

Lambda expressions cannot declare type parameters. While it would make sense semantically to do so, the natural syntax (preceding the parameter list with a type parameter list) introduces messy ambiguities. For example, consider:

foo( (x) < y , z > (w)-> v )

This could be an invocation offoo with one argument (a generic lambda cast to typex), or it could be an invocation offoo with two arguments, both the results of comparisons, the second comparingz with a lambda expression. (Strictly speaking, a lambda expression is meaningless as an operand to the relational operator>, but that is a tenuous assumption on which to build the grammar.)

There is a precedent for ambiguity resolution involving casts, which essentially prohibits the use of- and+ following a non-primitive cast (§15.15), but to extend that approach to generic lambdas would involve invasive changes to the grammar.

15.27.1. Lambda Parameters

The formal parameters of a lambda expression may have either declared types or inferred types. These styles cannot be mixed: it is not possible for a lambda expression to declare the types of some of its parameters but leave others to be inferred. Only parameters with declared types can have modifiers.

LambdaParameters:
InferredFormalParameterList:

The following productions from§4.3,§8.3, and§8.4.1 are shown here for convenience:

VariableModifier:
(one of)
Annotationfinal
VariableDeclaratorId:
Dims:

Receiver parameters are not permitted in theFormalParameters of a lambda expression, as specified in§8.4.1.

A lambda expression whose formal parameters have declared types is said to beexplicitly typed, while a lambda expression whose formal parameters have inferred types is said to beimplicitly typed. A lambda expression with zero parameters is explicitly typed.

If the formal parameters have inferred types, then these types are derived (§15.27.3) from the functional interface type targeted by the lambda expression.

The syntax for formal parameters with declared types is the same as the syntax for the parameters of a method declaration (§8.4.1).

The declared type of a formal parameter depends on whether it is a variable arity parameter:

  • If the formal parameter is not a variable arity parameter, then the declared type is denoted byUnannType if no bracket pairs appear inUnannType andVariableDeclaratorId, and specified by§10.2 otherwise.

  • If the formal parameter is a variable arity parameter, then the declared type is specified by§10.2. (Note that "mixed notation" is not permitted for variable arity parameters.)

No distinction is made between the following lambda parameter lists:

(int... x)-> ..(int[] x)-> ..

Consistent with the rules for overriding, either can be used, whether the functional interface's abstract method is fixed arity or variable arity. Since lambda expressions are never directly invoked, introducingint... where the functional interface usesint[] can have no impact on the surrounding program. In a lambda body, a variable arity parameter is treated just like an array-typed parameter.

The rules for annotation modifiers on a formal parameter declaration are specified in§9.7.4 and§9.7.5.

It is a compile-time error iffinal appears more than once as a modifier for a formal parameter declaration.

It is a compile-time error to use mixed array notation (§10.2) for a variable arity parameter.

The scope and shadowing of a formal parameter declaration is specified in§6.3 and§6.4.

It is a compile-time error for a lambda expression to declare two formal parameters with the same name. (That is, their declarations mention the sameIdentifier.)

It is a compile-time error if a lambda parameter has the name_ (that is, a single underscore character).

The use of the variable name_ in any context is discouraged. Future versions of the Java programming language may reserve this name as a keyword and/or give it special semantics.

It is a compile-time error if a receiver parameter (§8.4.1) appears in theFormalParameters of a lambda expression.

It is a compile-time error if a formal parameter that is declaredfinal is assigned to within the body of the lambda expression.

When the lambda expression is invoked (via a method invocation expression (§15.12)), the values of the actual argument expressions initialize newly created parameter variables, each of the declared or inferred type, before execution of the lambda body. TheIdentifier that appears in theVariableDeclaratorId or theInferredFormalParameterList may be used as a simple name in the lambda body to refer to the formal parameter.

A lambda parameter of typefloat always contains an element of the float value set (§4.2.3); similarly, a lambda parameter of typedouble always contains an element of the double value set. It is not permitted for a lambda parameter of typefloat to contain an element of the float-extended-exponent value set that is not also an element of the float value set, nor for a lambda parameter of typedouble to contain an element of the double-extended-exponent value set that is not also an element of the double value set.

When the parameter types of a lambda expression are inferred, the same lambda body can be interpreted in different ways, depending on the context in which it appears. Specifically, the types of expressions in the body, the checked exceptions thrown by the body, and the type correctness of code in the body all depend on the parameters' inferred types. This implies that inference of parameter types must occur "before" attempting to type-check the body of the lambda expression.

15.27.2. Lambda Body

A lambda body is either a single expression or a block (§14.2). Like a method body, a lambda body describes code that will be executed whenever an invocation occurs.

LambdaBody:

Unlike code appearing in anonymous class declarations, the meaning of names and thethis andsuper keywords appearing in a lambda body, along with the accessibility of referenced declarations, are the same as in the surrounding context (except that lambda parameters introduce new names).

The transparency ofthis (both explicit and implicit) in the body of a lambda expression - that is, treating it the same as in the surrounding context - allows more flexibility for implementations, and prevents the meaning of unqualified names in the body from being dependent on overload resolution.

Practically speaking, it is unusual for a lambda expression to need to talk about itself (either to call itself recursively or to invoke its other methods), while it is more common to want to use names to refer to things in the enclosing class that would otherwise be shadowed (this,toString()). If it is necessary for a lambda expression to refer to itself (as if viathis), a method reference or an anonymous inner class should be used instead.

A block lambda body isvoid-compatible if every return statement in the block has the formreturn;.

A block lambda body isvalue-compatible if it cannot complete normally (§14.21) and every return statement in the block has the formreturnExpression;.

It is a compile-time error if a block lambda body is neither void-compatible nor value-compatible.

In a value-compatible block lambda body, theresult expressions are any expressions that may produce an invocation's value. Specifically, for each statement of the formreturnExpression; contained by the body, theExpression is a result expression.

The following lambda bodies are void-compatible:

()-> {}()-> { System.out.println("done"); }

These are value-compatible:

()-> { return "done"; }()-> { if (...) return 1; else return 0; }

These are both:

()-> { throw new RuntimeException(); }()-> { while (true); }

This is neither:

()-> { if (...) return "done"; System.out.println("done"); }

The handling of void/value-compatible and the meaning of names in the body jointly serve to minimize the dependency on a particular target type in the given context, which is useful both for implementations and for programmer comprehension. While expressions can be assigned different types during overload resolution depending on the target type, the meaning of unqualified names and the basic structure of the lambda body do not change.

Note that the void/value-compatible definition is not a strictly structural property: "can complete normally" depends on the values of constant expressions, and these may include names that reference constant variables.

Any local variable, formal parameter, or exception parameter used but not declared in a lambda expression must either be declaredfinal or be effectively final (§4.12.4), or a compile-time error occurs where the use is attempted.

Any local variable used but not declared in a lambda body must be definitely assigned (§16 (Definite Assignment)) before the lambda body, or a compile-time error occurs.

Similar rules on variable use apply in the body of an inner class (§8.1.3). The restriction to effectively final variables prohibits access to dynamically-changing local variables, whose capture would likely introduce concurrency problems. Compared to thefinal restriction, it reduces the clerical burden on programmers.

The restriction to effectively final variables includes standard loop variables, but not enhanced-for loop variables, which are treated as distinct for each iteration of the loop (§14.14.2).

The following lambda bodies demonstrate use of effectively final variables.

void m1(int x) {    int y = 1;    foo(() -> x+y);    // Legal: x and y are both effectively final.}void m2(int x) {    int y;    y = 1;    foo(() -> x+y);    // Legal: x and y are both effectively final.}void m3(int x) {    int y;    if (...) y = 1;    foo(() -> x+y);    // Illegal: y is effectively final, but not definitely assigned.}void m4(int x) {    int y;    if (...) y = 1; else y = 2;    foo(() -> x+y);    // Legal: x and y are both effectively final.}
void m5(int x) {    int y;    if (...) y = 1;    y = 2;    foo(() -> x+y);    // Illegal: y is not effectively final.}void m6(int x) {    foo(() -> x+1);    x++;    // Illegal: x is not effectively final.}void m7(int x) {    foo(() -> x=1);    // Illegal: x is not effectively final.}void m8() {    int y;    foo(() -> y=1);    // Illegal: y is not definitely assigned before the lambda.}void m9(String[] arr) {    for (String s : arr) {        foo(() -> s);        // Legal: s is effectively final        // (it is a new variable on each iteration)    }}void m10(String[] arr) {    for (int i = 0; i < arr.length; i++) {        foo(() -> arr[i]);        // Illegal: i is not effectively final        // (it is not final, and is incremented)    }}

15.27.3. Type of a Lambda Expression

A lambda expression is compatible in an assignment context, invocation context, or casting context with a target typeT ifT is a functional interface type (§9.8) and the expression iscongruent with the function type of theground target type derived fromT.

Theground target type is derived fromT as follows:

  • IfT is a wildcard-parameterized functional interface type and the lambda expression is explicitly typed, then the ground target type is inferred as described in§18.5.3.

  • IfT is a wildcard-parameterized functional interface type and the lambda expression is implicitly typed, then the ground target type is the non-wildcard parameterization (§9.9) ofT.

  • Otherwise, the ground target type isT.

A lambda expression iscongruent with a function type if all of the following are true:

  • The function type has no type parameters.

  • The number of lambda parameters is the same as the number of parameter types of the function type.

  • If the lambda expression is explicitly typed, its formal parameter types are the same as the parameter types of the function type.

  • If the lambda parameters are assumed to have the same types as the function type's parameter types, then:

    • If the function type's result isvoid, the lambda body is either a statement expression (§14.8) or avoid-compatible block.

    • If the function type's result is a (non-void) typeR, then either i) the lambda body is an expression that is compatible withR in an assignment context, or ii) the lambda body is a value-compatible block, and each result expression (§15.27.2) is compatible withR in an assignment context.

If a lambda expression is compatible with a target typeT, then the type of the expression,U, is the ground target type derived fromT.

It is a compile-time error if any class or interface mentioned by eitherU or the function type ofU is not accessible from the class or interface in which the lambda expression appears.

For each non-static member methodm ofU, if the function type ofU has a subsignature of the signature ofm, then a notional method whose method type is the function type ofU is deemed to overridem, and any compile-time error or unchecked warning specified in§8.4.8.3 may occur.

A checked exception that can be thrown in the body of the lambda expression may cause a compile-time error, as specified in§11.2.3.

The parameter types of explicitly typed lambdas are required to exactly match those of the function type. While it would be possible to be more flexible - allow boxing or contravariance, for example - this kind of generality seems unnecessary, and is inconsistent with the way overriding works in class declarations. A programmer ought to know exactly what function type is being targeted when writing a lambda expression, so he should thus know exactly what signature must be overridden. (In contrast, this is not the case for method references, and so more flexibility is allowed when they are used.) In addition, more flexibility with parameter types would add to the complexity of type inference and overload resolution.

Note that while boxing is not allowed in a strict invocation context, boxing of lambda result expressions isalways allowed - that is, the result expression appears in an assignment context, regardless of the context enclosing the lambda expression. However, if an explicitly typed lambda expression is an argument to an overloaded method, a method signature that avoids boxing or unboxing the lambda result is preferred by the most specific check (§15.12.2.5).

If the body of a lambda is a statement expression (that is, an expression that would be allowed to stand alone as a statement), it is compatible with avoid-producing function type; any result is simply discarded. So, for example, both of the following are legal:

// Predicate has aboolean resultjava.util.function.Predicate<String> p = s-> list.add(s);// Consumer has avoid resultjava.util.function.Consumer<String> c = s-> list.add(s);

Generally speaking, a lambda of the form()->expr, whereexpr is a statement expression, is interpreted as either()->{returnexpr;} or()->{expr;}, depending on the target type.

15.27.4. Run-Time Evaluation of Lambda Expressions

At run time, evaluation of a lambda expression is similar to evaluation of a class instance creation expression, insofar as normal completion produces a reference to an object. Evaluation of a lambda expression is distinct from execution of the lambda body.

Either a new instance of a class with the properties below is allocated and initialized, or an existing instance of a class with the properties below is referenced. If a new instance is to be created, but there is insufficient space to allocate the object, evaluation of the lambda expression completes abruptly by throwing anOutOfMemoryError.

The value of a lambda expression is a reference to an instance of a class with the following properties:

  • The class implements the targeted functional interface type and, if the target type is an intersection type, every other interface type mentioned in the intersection.

  • Where the lambda expression has typeU, for each non-static member methodm ofU:

    If the function type ofU has a subsignature of the signature ofm, then the class declares a method that overridesm. The method's body has the effect of evaluating the lambda body, if it is an expression, or of executing the lambda body, if it is a block; if a result is expected, it is returned from the method.

    If the erasure of the type of a method being overridden differs in its signature from the erasure of the function type ofU, then before evaluating or executing the lambda body, the method's body checks that each argument value is an instance of a subclass or subinterface of the erasure of the corresponding parameter type in the function type ofU; if not, aClassCastException is thrown.

  • The class overrides no other methods of the targeted functional interface type or other interface types mentioned above, although it may override methods of theObject class.

These rules are meant to offer flexibility to implementations of the Java programming language, in that:

  • A new object need not be allocated on every evaluation.

  • Objects produced by different lambda expressions need not belong to different classes (if the bodies are identical, for example).

  • Every object produced by evaluation need not belong to the same class (captured local variables might be inlined, for example).

  • If an "existing instance" is available, it need not have been created at a previous lambda evaluation (it might have been allocated during the enclosing class's initialization, for example).

If the targeted functional interface type is a subtype ofjava.io.Serializable, the resulting object will automatically be an instance of a serializable class. Making an object derived from a lambda expression serializable can have extra run time overhead and security implications, so lambda-derived objects are not required to be serializable "by default".

15.28. Constant Expressions

ConstantExpression:
Expression

Aconstant expression is an expression denoting a value of primitive type or aString that does not complete abruptly and is composed using only the following:

Constant expressions of typeString are always "interned" so as to share unique instances, using the methodString.intern.

A constant expression is always treated as FP-strict (§15.4), even if it occurs in a context where a non-constant expression would not be considered to be FP-strict.

Constant expressions are used ascase labels inswitch statements (§14.11) and have a special significance for assignment conversion (§5.2) and initialization of a class or interface (§12.4.2). They may also govern the ability of awhile,do, orfor statement to complete normally (§14.21), and the type of a conditional operator? : with numeric operands.

Example 15.28-1. Constant Expressions

true(short)(1*2*3*4*5*6)Integer.MAX_VALUE / 22.0 * Math.PI"The integer " + Long.MAX_VALUE + " is mighty big."


Prev   Next
Chapter 14. Blocks and Statements Home Chapter 16. Definite Assignment

Legal Notice

[8]ページ先頭

©2009-2025 Movatter.jp