Project Coin/JSR 334 is an effort to add a set of small language changes to Java SE 7 under the JSR 336 umbrella JSR with the reference implementation developed in OpenJDK. The changes must be simultaneously small in specification, implementation, and testing. The small changes to the Java programming language in Java SE 7 are:
Binary integral literals and underscores in numeric literals
Improved Type Inference for Generic Instance Creation (diamond)
A description of the semantics for each feature as implemented in the JDK 7 developer preview, build b130, will follow. Non-normative discussion will appear as in block quotes as below:
Discussion: Text appearing here is only informative.
The documentation for a language change includes updates to the Java™ Language
Specification, Third Edition (JLSv3) and may also include
supporting library changes.
Since the changes will in part be phrased as differences from existing
JLSv3 text, having the JLSv3 text available to provide context is
recommended for a close reading of this document.
The full text of JLSv3 is available online.
Text that is deleted from JLSv3
will be diplayed like this,
while text that is added
will be renderded this way.
The language changes as given in this document may at times be less
formal than the eventual JLSv3 updates.
Readers should review the discussion section of a feature before
sending in a comment or question about that feature.
Previous discussions of design considerations may appear in the
coin-dev
archives.
For informational purposes, a summary of changes to the JSR 269 API in
the javax.lang.model.*
packages are listed in an
appendix.
Some of the changes are being made to directly support new language
features; other changes are usability improvements to the API.
These changes will go through a maintenance review of JSR 269 for
inclusion in the JSR 336 umbrella JSR for Java SE 7.
The list of types which can be switched on in JLSv3
§14.11 "The switch Statement" is augmented to include
String
:
"The type of the Expression must bechar
,byte
,short
,int
,Character
,Byte
,Short
,Integer
,String
, or an enum type (§8.9), or a compile-time error occurs."
No other explicit changes are necessary to support switching on a string.
Discussion: The lexical grammar of the switch statement does not need to be changed to support switching on a string since Strings are already included in the definition of constant expressions, JLSv3 §15.28, so the SwitchLabel production does not need to be augmented. The existing restrictions in JLSv3 §14.11 on no duplicate labels, at most one default, no
null
labels, etc. all apply to Strings without modification. The definite assignment analysis of switch statement, JLSv3 §16.2.9, is unchanged as well.The existing rules for the
switch
statement forbid anull
label and require aNullPointerException
to be thrown if the expression being switched on isnull
. Anull
expression can occur for both enum types and for boxed primitive types likeInteger
andFloat
. Therefore, consistency alone argues for these prohibitions to also be in place when switching on a string.The prohibition on duplicate string labels applies after any encoding step which maps a sequence of bytes of the input file to a sequence of logical characters and after the specified Unicode escape lexical translations (JLSv3 §3.2) are applied. Therefore, labels that are textually distinct in the source code may still be regarded as being duplicates after these translations occur. Whether or not string labels are distinct may depend on the encoding used by the compiler to interpret the bytes of the input sources.
In order to keep strings in switch a small language change, the JVM lookupswitch and tableswitch instructions in Java SE 7 do not support switching on a string. Instead, Java compilers are responsible for translating a switch on strings into some sequence of byte codes with the proper semantics. Many valid and efficient translation schemes are possible that have better expected performance than successive comparisons of the string being switched on with each
case
label constant. Direct JVM support for switching on a string may be added in a future version of the platform.
Binary integer literals are structured just like hexadecimal integer
literals except that binary digits are used instead of hexadecimal
digits and binary literals are prefixed by "0b
" rather
than "0x
".
In numeric literals, underscores are allowed as separators between digits. This applies to literals in any supported base: binary, octal, hexadecimal, or decimal.
The grammar changes below additions or modifications to JLSv3 §3.10.
- IntegerLiteral:
- DecimalIntegerLiteral
- HexIntegerLiteral
- OctalIntegerLiteral
- BinaryIntegerLiteral
- BinaryIntegerLiteral:
- BinaryNumeral IntegerTypeSuffixopt
- BinaryNumeral:
0
b
BinaryDigits0
B
BinaryDigits
- DecimalNumeral:
0
- NonZeroDigit Digitsopt
- NonZeroDigit Underscores Digits
- Underscores:
_
- Underscores
_
- Digits:
- Digit
Digits Digit- Digit DigitsAndUnderscoresopt Digit
- DigitsAndUnderscores:
- DigitOrUnderscore
- DigitsAndUnderscores DigitOrUnderscore
- DigitOrUnderscore:
- Digit
_
- HexDigits:
- HexDigit
- HexDigit
HexDigitsHexDigitsAndUnderscoresopt HexDigit
- HexDigitsAndUnderscores:
- HexDigitOrUnderscore
- HexDigitsAndUnderscores HexDigitOrUnderscore
- HexDigitOrUnderscore:
- HexDigit
_
- OctalNumeral:
0
OctalDigits0
Underscores OctalDigits
- OctalDigits:
- OctalDigit
- OctalDigit
OctalDigitsOctalDigitsAndUnderscoresopt OctalDigit
- OctalDigitsAndUnderscores:
- OctalDigitOrUnderscore
- OctalDigitsAndUnderscores OctalDigitOrUnderscore
- OctalDigitOrUnderscore:
- OctalDigit
_
- BinaryDigits:
- BinaryDigit
- BinaryDigit BinaryDigitsAndUnderscoresopt BinaryDigit
- BinaryDigitsAndUnderscores:
- BinaryDigitOrUnderscore
- BinaryDigitsAndUnderscores BinaryDigitOrUnderscore
- BinaryDigitOrUnderscore:
- BinaryDigit
_
- BinaryDigit: one of
0
1
No other language changes are necessary to support the new literal syntax.
Discussion: As written, due to reuse of the productions, these grammar changes imply underscores as separators are supported both in integral literals (for
int
,long
,short
, etc.) as well as for floating-point literals. Therefore allowed uses of underscores include:
1234_5678
1_2_3_4__5_6_7_8L
0b0001_0010_0100_1000
3.141_592_653_589_793d
0x1.ffff_ffff_ffff_fP1_023 // Double.MAX_VALUE
while disallowed uses of underscores include:
_1234
0x_1234
1234_
0x1.0_p_-1022
The grammar above for the literals is unambiguous, but as written requires a lookahead of more than 1 character because the recursion is in the middle of the Digits production. Since the underscores are separators, productions like
- Digits:
- Digit DigitsAndUnderscoresopt
would not be correct since an underscore could appear as a terminator of the literal. Since the lexical grammar has expository purposes, no attempt has been made to refactor the grammar to restore a look ahead of 1. In addition, in practice the underscores may be purged with a small amount of additional logic in a compiler's scanner as opposed to its parser proper.
Since the leading "
0
" used to specify an octal literal is itself a digit, underscores are allowed between the leading0
and subsequent value-carrying digits of an octal literal. This differs from the treatment of the hexadecimal and binary literal specifiers, "0x
" and "0b
", which are not made up entirely of digit characters of the base in question.Currently the methods in the
java.lang
package that convert strings to primitive numeric values do not support converting inputs strings with underscores (Oracle bug 6863378).
The grammar of a catch
clause of a try
statement (JLSv3 §14.20) is
extended to allow a series of exception types, separated by the "OR"
operator symbol, "|
", to be used in the declaration of
the exception parameter:
- CatchClause:
catch
(
FormalParameterCatchFormalParameter)
Block
- CatchFormalParameter:
- VariableModifiersopt CatchType VariableDeclaratorId
- CatchType:
- DisjunctiveType
- DisjunctiveType:
- ClassType
- ClassType
|
DisjunctiveType
Changing the handling of exception types affects the type system in
two ways: in addition to the usual type checking performed on all
types, exception types undergo an additional compile time analysis.
For the purpose of type checking, a catch parameter declared with a
disjunction has type lub(t1, t2, ...) (JLSv3 §15.12.2.7) where the ti
are the exception types the catch
clause is declared to
handle.
Informally, the lub (least upper bound) is the most specific supertype
of the types in question.
In the case of a multi-catch exception parameter, the least upper
bound of the types in question always exists since the types of all
the caught exceptions must be subclasses of Throwable
.
Therefore, Throwable
is an upper bound of the
types in question, but it may not be the least upper bound
since some subclass of Throwable
may be a superclass (and
thereby also a supertype) of the types in question and the exception
types in question may implement a common interface.
(A lub can be an intersection type of a superclass and one or more
interfaces.)
For the purpose of exception checking (JLSv3
§11.2), a throw
statement (JLSv3
§11.2.2) that rethrows a final
or effectively
final catch
parameter is treated as throwing precisely
those exception types that:
the try
block can throw,
no previous catch clause handles, and
are a subtype/supertype of one of the types in the declaration of the catch parameter (i.e. they are not disjoint).
Note to readers: the meaning and description of the more precise exception checking rules will be expanded upon in future drafts of the documentation; JLSv3 §11.3 "Handling of an Exception" may need to be revised as part of this effort.
An effectively final catch
parameter is an exception
parameter (JLSv3 §14.20) that is
not declared final
and is not the target of an assignment
expression (JLSv3 §15.26) in the scope
of the exception parameter.
Informally, if the catch
parameter is not modified and
then the exception is rethrown, the compiler knows the exception is
one of the exceptions throwable by the try
block, which
can be more precise than the declared type of the catch
parameter.
The exception parameter of a multi-catch clause (catch (Exception1 |
Exception2 e) {...}
) is implicitly final
.
It is a compile-time error if an exception parameter that is
implicitly final
is assigned to within the body of the
catch
clause.
Consequently, an explicit final
on a multi-catch
exception parameter is legal, but discouraged as a matter of style.
Discussion: There are contrived cases where the more precise exception analysis can stop compilation of currently valid programs (by the compiler identifying more dead code); one example is:
try { throw new DaughterOfFoo(); } catch (Foo e) { try { throw e; // used to throw Foo, now throws DaughterOfFoo } catch (SonOfFoo anotherException) { // Reachable? } }This will compile under source 6 and earlier using the imprecise analysis (the rethrow of
e
is regarded as beingFoo
or some subclass ofFoo
), but will not compile under the more precise analysis since the compiler will correctly view "catch (SonOfFoo ...)
" as unreachable. An examination of millions of lines of code in a diverse set of projects, including dozens of members of the Qualitas Corpus and the JDK, found no instances where these conditions occurred. Therefore, using a more precise exception analysis when recompiling existing code is viewed as having acceptable source compatibility risk. If the source can be modified, removing the dead code from the code would resolve the problem.Fuller support for disjunctive types may be added in future releases; forcing disjunctive
catch
parameters to befinal
or effectively final preserves flexibility if fuller support is added in the future.The revised exception analysis for
final
and effectivelyfinal
catch
parameters is more precise than the previously defined analysis. Therefore, when the new analysis is applied to existing code, allthrows
clauses on methods and constructors remain valid.
First, grammatical changes in JLSv3 §15.9 to the ClassInstanceCreationExpression: production:
- ClassInstanceCreationExpression:
new
TypeArgumentsoptClassOrInterfaceTypeTypeDeclSpecifier TypeArgumentsOrDiamondopt(
ArgumentListopt)
ClassBodyopt- Primary
.
new
TypeArgumentsopt IdentifierTypeArgumentsoptTypeArgumentsOrDiamondopt(
ArgumentListopt)
ClassBodyopt
- TypeArgumentsOrDiamond:
- TypeArguments
<
>
Additionally, the first sentence is changed:
A class instance creation expression specifies a class to be
instantiated, possibly followed by type arguments or diamond "<>"
(if the class
being instantiated is generic (§8.1.2), followed by (a possibly empty) list of
actual value arguments to the constructor.
A sentence is added to a following paragraph:
Both unqualified and qualified class instance creation expressions may
optionally end with a class body. Such a class instance creation
expression declares an anonymous class (§15.9.5)
and creates an instance of it.
It is a compile-time error if a class instance creation
expression declares an anonymous class but uses "<>"
in
place of a class type argument list.
In JLSv3 §15.9.1,
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 an unqualified class instance creation expression,
then let T be the ClassOrInterfaceType after the new token. then the class being instantiated is defined as follows. It is a compile-time error if TypeDeclSpecifier TypeArgumentsOrDiamondopt_ does not denote a type, T (§4.3, §4.5). It is also a compile-time error if the class or interface named by T is not accessible (§6.6) or if T is an enum type (§8.9). ...Otherwise, the class instance creation expression is a qualified class instance creation expression.
Let T be the name of the Identifier after theIt is a compile-time error ifnew
token.Tthe Identifier after the new token is not the simple name (§6.2) of an accessible (§6.6) non-final
inner class (§8.1.3) that is a member of the compile-time type of the Primary. It is also a compile-time error ifTthe name is ambiguous (§8.5) or ifTit denotes an enum type. When TypeArguments have been provided after the name, it is a compile-time error if the type arguments, when applied to the named class or interface, do not denote a well-formed parameterized type (§4.5). Let T be the type named by the identifier and any type arguments. An anonymous direct subclass of the class named by T is declared. The body of the subclass is the ClassBody 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 an unqualified class instance creation expression, then the
ClassOrInterfaceTypeTypeDeclSpecifier must denote a class that is accessible (§6.6) and is not an enum type and notabstract
, or a compile-time error occurs. When TypeArguments have been provided after the class name, it is a compile-time error if the type arguments, when applied to the class, do not denote a well-formed parameterized type (§4.5). When"<>"
is instead used to elide type arguments after the class name, it is a compile-time error if the class is not generic.In this case, theThe class being instantiated is the class denoted byClassOrInterfaceTypethe TypeDeclSpecifier.Otherwise, the class instance creation expression is a qualified class instance creation expression. It is a compile-time error if Identifier is not the simple name (§6.2) of an accessible (§6.6) non-
abstract
inner class (§8.1.3)TC that is a member of the compile-time type of the Primary. It is also a compile-time error if Identifier is ambiguous (§8.5), or if Identifier denotes an enum type (§8.9). When TypeArguments have been provided after the name, it is a compile-time error if the type arguments, when applied to C, do not denote a well-formed parameterized type (§4.5). When"<>"
is instead used to elide type arguments after the name, it is a compile-time error if C is not generic. The class being instantiated isthe class denoted by IdentifierC.The type of the class instance creation expression is the class type being instantiated.
In JLSv3 §15.9.3 (Choosing the Constructor and its Arguments),
Let C be the class
typebeing instantiated. To create an instance of C, i, a constructor of Cisand type of i are chosen at compile-time by the following rules. First, the actual arguments to the constructor invocation are determined.Second, a constructor of C and corresponding result type and throws clause are determined.
- If C is an anonymous class, and the direct superclass of C, S, is an inner class, then:
If the S is a local class and S occurs in a static context, then the arguments in the argument list, if any, are the arguments to the constructor, in the order they appear in the expression.
Otherwise, the immediately enclosing instance of i with respect to S is the first argument to the constructor, followed by the arguments in the argument list of the class instance creation expression, if any, in the order they appear in the expression.
- Otherwise the arguments in the argument list, if any, are the arguments to the constructor, in the order they appear in the expression.
The type of the class instance creation expression is the result type of the chosen constructor, as defined above. Note that
If the class instance creation expression uses
"<>"
to elide class type arguments, a list of methods m1...mk is defined for the purpose of overload resolution and type argument inference. Let c1...ck be the constructors of class C. Let x be a name that is not the name of any member method of C. For all i, 1≤i≤k, mi is defined in terms of ci as follows:
A substitution theta is first defined to instantiate the types in ci. Let F1...Fp be the type parameters of C, and let X1...Xp be type variables with distinct names that are not in scope in the body of C. If ci has type parameters F'1...F'q and the class instance creation provides constructor type arguments T1...Tq, then theta is [F1:=X1, ..., Fp:=Xp, F'1:=T1,..,F'p:=Tp]. Otherwise, if ci has type parameters F'1...F'q and the class instance creation elides constructor type arguments, let X'1...X'q be type variables with names distinct from each other and from X1..Xp, and that are not in scope in the body of C; then theta is [F1:=X1,..., Fp:=Xp, F'1:=X'1,...,F'q:=X'q]. Otherwise, theta is [F1:=X1,..,Fp:=Xp].
The modifiers of mi include all those of ci as well as
static
.The type parameters of mi (if any) are X1,..,Xp, X'1,..,X'q. The bound of each parameter, if any, is theta applied to the corresponding parameter bound in C or ci.
The return type of mi is theta applied to C<F1..Fp>.
The name of mi is x.
The (possibly empty) list of argument types of mi is theta applied to the argument types of ci.
The (possibly empty) list of thrown types of mi is theta applied to the thrown types of ci.
The body of mi is irrelevant.
To choose a constructor, we temporarily consider m1..mk to be members of C and the class instance creation expression to be replaced with a method invocation expression of the form C.x(a1..an), where x and a1..an are determined above. The method invocation is considered to appear in the same context as the class instance creation expression. Then one of m1..mk is chosen using the process described in §15.12.2, where C is the class to be searched. A compile-time error results if there is no unique most-specific method that is both applicable and accessible. Otherwise, where mi is the selected method, ci is the chosen constructor. The result type and throws clause of ci are the same as the return type and throws clause determined for mi (§15.12.2.6).
Otherwise, the class instance creation expression does not use
"<>"
to elide class type arguments. Let T be the type denoted by C followed by any class type arguments in the expression. The process described in §15.12.2, modified to handle constructors, is used to select one of the constructors of T and determine its throws clause.As in method invocations, a compile-time error results if there is no unique most-specific constructor that is both applicable and accessible. Otherwise, the result type is T.
the type of the class instance creation expressionthis type may be an anonymous class type, in which case the constructor being invoked is an anonymous constructor.
(Note that javac
in the JDK 7 developer preview
erroneously accepts diamond combined with non-generic classes and
accepts some uses of diamond with anonymous inner classes.
These bugs will be corrected in future builds.)
Discussion: Syntacticly, ClassOrInterfaceType expands to either a ClassType or InterfaceType (JLSv3 §4.3). Both ClassType and InterfaceType then in turn expand to
TypeDeclSpecifier TypeArgumentsopt
Therefore, "inlining" TypeDeclSpecifier for ClassOrInterfaceType followed by an optional TypeArgumentsOrDiamond captures the desired syntax.It is legal, but discouraged, to have whitespace between the "<" and ">" of a diamond.
Raw types have an existing meaning in Java programs and it is useful to maintain a distinction between raw types (hopefully in legacy code) and types inferred by the compiler. Therefore, the diamond syntax is used to mark locations where type inference is requested as opposed to interpreting all instances of raw types as inference sites.
Using diamond with anonymous inner classes is not supported since doing so in general would require extensions to the class file signature attribute to represent non-denotable types, a de facto JVM change.
try
-with-resources statement
The try
-with-resources feature has a number of supporting
library changes:
A new interface java.lang.AutoCloseable
.
Retrofitting libraries to implement the new interface.
Facilities to manage suppressed exceptions on
java.lang.Throwable
.
The new interface java.lang.AutoCloseable
:
package java.lang; /** * A resource that must be closed when it is no longer needed. * * @since 1.7 */ public interface AutoCloseable { /** * Closes this resource, relinquishing any underlying resources. * This method is invoked automatically by the {@code * try}-with-resources statement. * * Classes implementing this method are strongly encouraged to * be declared to throw more specific exceptions (or no exception * at all, if the close cannot fail). * * Note that unlike the {@link java.io.Closeable#close close} * method of {@link java.io.Closeable}, this {@code close} method * is not required to be idempotent. In other words, * calling this {@code close} method more than once may have some * visible side effect, unlike {@code Closeable.close} which is * required to have no effect if called more than once. * * However, while not required to be idempotent, implementers of * this interface are strongly encouraged to make their {@code * close} methods idempotent. * * @throws Exception if this resource cannot be closed */ void close() throws Exception; }
Types implementing or extending java.lang.AutoCloseable
:
java.beans.XMLDecoder
java.beans.XMLEncoder
java.io.Closeable
java.io.ObjectInput
java.io.ObjectOutput
java.sql.Connection
java.sql.ResultSet
java.sql.Statement
java.nio.channels.FileLock
(with an added close
method)
javax.sound.midi.MidiDevice
javax.sound.midi.Receiver
javax.sound.midi.Transmitter
javax.sound.sampled.Line
Types newly implementing or extending java.io.Closeable
:
java.util.Scanner
javax.imageio.stream.ImageInputStream
Two new methods are added to java.lang.Throwable
to
manage suppressed exceptions; in addition, the serial format is
updated:
/** * The list of suppressed exceptions, as returned by {@link * #getSuppressed()}. The list is initialized to a zero-element * unmodifiable sentinel list. When a serialized Throwable is * read in, if the {@code suppressedExceptions} field points to a * zero-element list, the field is reset to the sentinel value. * * @serial * @since 1.7 */ private List<Throwable> suppressedExceptions = SUPPRESSED_SENTINEL; /** * Appends the specified exception to the exceptions that were * suppressed in order to deliver this exception. This method is * typically called (automatically and implicitly) by the {@code * try}-with-resources statement. * * If the first exception to be suppressed is {@code null}, that * indicates suppressed exception information will not be * recorded for this exception. Subsequent calls to this method * will not record any suppressed exceptions. Otherwise, * attempting to suppress {@code null} after an exception has * already been successfully suppressed results in a {@code * NullPointerException}. * * Note that when one exception {@linkplain * #initCause(Throwable) causes} another exception, the first * exception is usually caught and then the second exception is * thrown in response. In contrast, when one exception suppresses * another, two exceptions are thrown in sibling code blocks, such * as in a {@code try} block and in its {@code finally} block, and * control flow can only continue with one exception so the second * is recorded as a suppressed exception of the first. * * @param exception the exception to be added to the list of * suppressed exceptions * @throws IllegalArgumentException if {@code exception} is this * throwable; a throwable cannot suppress itself. * @throws NullPointerException if {@code exception} is null and * an exception has already been suppressed by this exception * @since 1.7 */ public final void addSuppressed(Throwable exception) /** * Returns an array containing all of the exceptions that were * suppressed, typically by the {@code try}-with-resources * statement, in order to deliver this exception. * * If no exceptions were suppressed, an empty array is returned. * * @return an array containing all of the exceptions that were * suppressed to deliver this exception. * @since 1.7 */ public final Throwable[] getSuppressed() // Added explicit specification for readObject. /** * Reads a {@code Throwable} from a stream, enforcing * well-formedness constraints on fields. Null entries and * self-pointers are not allowed in the list of {@code * suppressedExceptions}. Null entries are not allowed for stack * trace elements. * * Note that there are no constraints on the value the {@code * cause} field can hold; both {@code null} and {@code this} are * valid values for the field. */ private void readObject(ObjectInputStream s)
The language specification changes involve §14.20 "The try
statement," and will eventually introduce a new subsection
§14.20.3 "Execution of try
-with-resources," although
the specification presented below is not partitioned as such.
SYNTAX: The existing set of grammar productions for TryStatement in §14.20 is augmented with an alternative including resources:
try
Block Catches
try
Block Catchesopt Finally
try
ResourceSpecification Block Catchesopt Finallyopt
Supporting new grammar productions are added:
(
Resources ;
opt )
;
Resources=
Expression
A try
-with-resources statement has a resource
specification that expresses resources to be automatically closed at
the end of the Block.
A resource specification declares one or more local variables; the
type of each variable must be a subtype of AutoCloseable
or a compile-time error occurs.
A variable must not have the same name as a variable declared earlier
in the resource specification, a local variable, or parameter of the
method or initializer block immediately enclosing the try
statement, or a compile-time error occurs.
The scope of a variable declared in a resource specification of a
try
-with-resources statement (§14.20) is from the
declaration rightward over the remainder of the resource specification
and the entire Block associated with the try.
Within the Block of the try
, the name of the
variable may not be redeclared as a local variable of the directly
enclosing method or initializer block, nor may it be redeclared as an
exception parameter of a catch clause in a try
statement
of the directly enclosing method or initializer block, nor may it be
redeclared as a variable in the resource specification, or a
compile-time error occurs.
However, a variable declared in a resource specification may be
shadowed (§6.3.1) anywhere inside
a class declaration nested within the Block of the
try
.
The meaning of a try
-with-resources statement with a
Catches clause or Finally block is given by translation
to a try
-with-resources statement with neither a
Catches clause nor a Finally block:
try
ResourceSpecification
Block
Catchesopt
Finallyopt
⇒
try {
try
ResourceSpecification
Block
}
Catchesopt
Finallyopt
After translation outward of any Catches clause or
Finally block to an outer try
, in a
try
-with-resources statement with no Catches
clause or Finally block that manages a single resource:
If the initialization of the resource completes abruptly because of a
throw of a value V, or if the Block of the
try
-with-resources statement completes abruptly because
of a throw of a value V and the automatic closing of the
resource completes normally, then the try
-with-resources
statement completes abruptly because of the throw of value V.
If the Block of the try
-with-resources
statement completes abruptly because of a throw of a value V1,
and the automatic closing of the resource completes abruptly because
of a throw of a value V2, then the
try
-with-resources statement completes abruptly because
of the throw of value V1 with V2 added to the suppressed
exception list of V1.
In a try
-with-resources statement that manages multiple resources:
If the initialization of a resource completes abruptly because of a
throw of a value V, or if the Block of the
try
-with-resources statement completes abruptly because
of a throw of a value V (which implies that the initialization
of all resources completed normally) and the automatic closings of all
initialized resources completes normally, then the
try
-with-resources statement completes abruptly because
of the throw of value V.
If the initialization of a resource completes abruptly because of a
throw of a value V1 and the automatic closings of one or more
resources (that were previously successfully initialized) complete
abruptly because of throws of values V2...Vn, then the
try
-with-resources statement completes abruptly because
of the throw of a value V1 with V2...Vn added to
the suppressed exception list of V1.
If the Block of the try
-with-resources statement
completes abruptly because of a throw of a value V1, and the
automatic closings of one or more resources (that were previously
successfully initialized) complete abruptly because of throws of
values V2...Vn, then the try
-with-resources
statement completes abruptly because of the throw of a value V1
with V2...Vn added to the suppressed exception list of
V1.
The exceptions that can be thrown by a try
-with-resources
statement are the exceptions that can be thrown by the Block of
the try
-with-resources statement plus the union of the
exceptions that can be thrown by the automatic closing of the
resources themselves.
Regardless of the number of resources managed by a
try
-with-resources statement, it is possible for a
Catches clause associated with the statement to catch an
exception due to initialization or automatic closing of any resource.
A try
-with-resources statement with a
ResourceSpecification clause that declares multiple
Resources is treated as if it were multiple
try
-with-resources statements, each of which has a
ResourceSpecification clause that declares a single
Resource.
When a try
-with-resources statement with n
Resources (n > 1) is translated, the result
is a try
-with-resources statement with n-1
Resources.
After n such translations, there are n nested
try
-catch-finally statements, and the overall translation
is complete.
The meaning of a try
-with-resources statement with a
ResourceSpecification clause and no Catches clause or
Finally block is given by translation to a local variable
declaration and a try-catch-finally
statement.
During translation, if the ResourceSpecification clause
declares one Resource, then the try-catch-finally
statement is not a try
-with-resources statement, and
ResourceSpecificationtail is empty.
If the ResourceSpecification clause declares n > 1
Resources, then the try-catch-finally
statement is
treated as if it were a
try
-with-resources-catch-finally
statement,
where ResourceSpecificationtail is a
ResourceSpecification consisting of the 2nd, 3rd, ..., nth
Resources in order.
The translation is as follows, where the identifiers
#primaryException
, #t
, and
#suppressedException
are fresh:
try
ResourceSpecification
Block
⇒
{
final
VariableModifiers_minus_final R#resource =
Expression;
Throwable #primaryException = null;
try
ResourceSpecificationtail
Block
catch (Throwable #t)
{
#primaryException = t;
throw #t;
} finally {
if (#primaryException != null) {
try {
#resource.close();
} catch(Throwable #suppressedException) {
#primaryException.addSuppressed(#suppressedException);
}
} else {
#resource.close();
}
}
(Note that subsequent to the JDK 7 developer preview, the
semantics of the desugaring of try
-with-resource was
amended to only call close
on a resource if the resource
is non-null.
This change will be reflected in future drafts.)
The value of VariableModifiers_minus_final is the set of
modifiers on the variable (except for final
, if present);
R is the type of the variable declaration; and
#resource
is the name of the variable declared in the
Resource.
The reachability and definite assignment rules for the
try
statement with a resource specification are
implicitly specified by the translations above.
Discussion: The
Throwable.printStackTrace
family of methods have their expected behavior updated to include displaying information about suppressed exceptions.The protocol around ignoring calls to
Throwable.addSuppressed
if the exception to be suppressed isnull
is intended to allow JVM implementations to host immutable exception objects.An implication of the combined grammar is that a
try
statement must have at least one of acatch
clause, afinally
block, and a resource specification. Furthermore, it is permissible for atry
statement to have exactly one of these three components.The grammar for a declared resource is
VariableModifiersopt Type VariableDeclaratorId=
Expression
rather than the simpler LocalVariableDeclaration
to disallow code like
AutoCloseable a, b, c
which is not useful in this context since the variables have to be initialized.The exception behavior of
close
methods is accounted for in determining the set of exceptions atry
-with-resources statement can throw.By design, no special accommodations are made to deal with the
ThreadDeath
error which is spawned by the long-deprecatedThead.stop
method.The expert group is discussing whether or not the
try
-with-resources statement should be altered to included separate handling forInterruptedException
. Proper handling ofInterruptedException
and a thread'sinterrupted
status is necessary for the correctness of various multi-threaded algorithms. As a general comment, it is ill-advised for theclose
method of anAutoCloseable
resource to throw an exception that should not be suppressed.Resource declarations in a resource specification are implicitly
final
. For consistency with existing declarations that have implicit modifiers, it is legal (though discouraged) for a programmer to provide an explicit "final
" modifier. By allowing non-final
modifiers, annotations such as@SuppressWarnings
will be preserved on the translated code, which implies@SuppressWarnings
on a resource will have the intended effect. It is unlikely that the Java programming language will ever ascribe a meaning to an explicitfinal
modifier in this location other than the traditional meaning.Unlike the fresh identifier in the translation of the enhanced-
for
statement, the#resource
variable is in scope in the Block of atry
-with-resources statement.The translation exploits the improved precision of exception analysis for an effectively
final
exception parameter.At least in Java SE 7, a class must have a method named "close" to implement the
AutoCloseable
interface and thus work with thetry
-with-resources statement. To allow methods with other names like "dispose" to be called at block exit instead, an adapter interface with a matching factory can be used to wrap the object in question and forward calls from "close" to the type-specific clean-up method. In the future, it is possible other mechanisms, such as interface injection, may also allow classes not declared to declareAutoCloseable
to be operated on by thetry
-with-resources statement
As part of this language change, an unchecked warning is required at declaration sites of varargs methods and constructors that have a non-reifiable element type (JLSv3 §4.7) for the varags parameter. Previously, call sites of such methods have generated unchecked warnings.
A new @Documented
annotation type,
java.lang.SafeVararags
, can be used to suppress warnings
related to unchecked warnings from varargs methods and constructors,
both the new mandatory warnings at the declaration site of a varargs
method or constructor with a non-reifiable element type and the
existing unchecked warnings at the call sites of such methods.
The documentation of the new SafeVarargs
annotation type is below.
Annotation Type SafeVarargs
@Documented @Retention(value=RUNTIME) @Target(value={CONSTRUCTOR,METHOD}) public @interface SafeVarargsA programmer assertion that the body of the annotated method or constructor does not perform potentially unsafe operations on its varargs parameter. Applying this annotation to a method or constructor suppresses unchecked warnings about a non-reifiable variable-arity (vararg) type and suppresses unchecked warnings about parameterized array creation at call sites.
In addition to the usage restrictions imposed by its
@Target
meta-annotation, compilers are required to implement additional usage restrictions on this annotation type; it is a compile-time error if a method or constructor declaration is annotated with a@SafeVarargs
annotation, and either:
- the declaration is a fixed-arity method or constructor
- the declaration is a variable-arity method that is neither
static
norfinal
.Compilers are encouraged to issue warnings when this annotation type is applied to a method or constructor declaration where:
- The variable-arity parameter has a reifiable element type, which includes primitive types,
Object
, andString
. (The unchecked warnings this annotation type suppresses already do not occur for a reifiable element type.)- The body of the method or constructor declaration performs potentially unsafe operations, such as an assignment to an element of the variable-arity parameter's array that generates an unchecked warning.
Future versions of the platform may mandate compiler errors for such unsafe operations.
The platform methods and constructors annotated with a
@SafeVarargs
annotation are:
public static <T> List<T> java.util.Arrays.asList(T... a)
public static <T> boolean java.util.Collections.addAll(Collection<? super T> c, T... elements)
public static <E extends Enum<E>> java.util.EnumSet<E> EnumSet.of(E first, E... rest)
protected final void javax.swing.SwingWorker.publish(V... chunks)
Discussion: The non-local effect of a
@SafeVarags
annotation suppressing warnings at call sites (in addition to the declaration site) differs from the effects of a@SuppressWarnings
annotation on a declaration.The canonical target for the a
@SafeVarargs
annotation is a method likejava.util.Collections.addAll
, whose declaration starts withpublic static <T> boolean java.util.Collections.addAll(Collection<? super T> c, T... elements)The varargs parameter has underlying type
T[]
, which is non-reifiable. However, the method fundamentally just reads from the input array and adds the elements to a collection, which is a safe operation with respect to the array. Therefore the warnings at call sites ofCollections.addAll
are arguably spurious and uninformative. Applying a@SafeVarargs
annotation to the method stops generation of unchecked warnings at the methods' call sites.In practice, the
EnumSet.of
should not generate unchecked warnings since the inferred type in any given application of the method should be some particular concrete enum type. This is a consequence of the additional restrictions imposed on enum types, such as they are all direct subclasses of the abstract classjava.lang.Enum
. However, adding@SafeVarargs
does correctly capture the semantics of the method.Generally safe operations on the varargs parameter include only reading from the parameter and treating the parameter in an invariant sense. Aliasing the parameter is potentially unsafe.
Since new unchecked warnings are being introduced, those diligently compiling with options like "
-Xlint:unchecked -Werror
" will see a build error under JDK 7 if any of the suspicious varargs method declarations are found. To address this, the@SafeVarargs
annotation can be applied to the declarations, if appropriate, or in the compiler reference implementation the@SuppressWarnings({"unchecked", "varargs"})
annotation can be applied. Unlike@SafeVarargs
, the@SuppressWarnings
annotation will not squelch unchecked warnings at the call site of the annotated method.Since a
@SafeVarargs
annotation is only applicable tostatic
methods,final
instance methods, and constructors, the annotation is not usable in a situation where method overriding occurs. Annotation inheritance only works on classes (not methods, interfaces, or constructors) so without changing annotation inheritance, aSafeVarargs
-style annotation cannot be passed through general instance methods in classes or through interfaces.Since it affects programming language semantics, the
SafeVarargs
annotation type is placed in thejava.lang
package.The
SafeVarargs
annotation type is declared with a runtimeRetentionPolicy
for several reasons. Some representation of theSafeVarargs
status is needed in class files to allow compilers to know to omit unchecked warnings at call sites of annotated methods, unchecked warnings that would otherwise be mandated by the language specification. If this information is stored using an annotation, the annotation type can have one of three retention policies, SOURCE, CLASS, or RUNTIME. With the SOURCE policy, the annotation would not be stored in the class file at all, which would not meet the requirements of eliding warnings when uses of the annotated method or constructor are compiled separately from the class declaring the method or constructor. That leaves CLASS and RUNTIME as potential retention policies. Both policies use equal space in the class file. However, an advantage of RUNTIME retention is that no explicit method is needed in a reflective APIs to query theSafeVarargs
status of a method or constructor since the presence or absence of the annotation can be tested. For example, there is no need for anisSafeVarargs
method on theMethod
andConstructor
classes in thejava.lang.reflect
package or for anisSafeVarargs
method injavax.lang.model.element.ExecutableElement
. Therefore, theSafeVarargs
annotation type is declared with RUNTIME retention and no methods are added to any of the platform's reflective APIs to query for this information. This information could conceivably be stored in a new class file attribute, but small language changes do not change the VM specification and a new recognized class file attribute is a VM change. An additional benefit of having the information in class files is enabling class file-based analysis tools to perform additional checks on the operations of annotated methods and constructors.
The JSR 269 language model follows somewhat different evolution rules than most APIs included in Java SE. In particular, while the changes to the API are binary compatible, certain source incompatible changes are made of necessity. In particular, methods are added to the visitor interfaces to allow operations on newly-added language constructors to be performed. This evolution path was expected during JSR 269's development and for that reason, developers were warned to not directly implement the visitor interfaces, but rather than extend one of the visitor utility classes. The utility classes are versioned per release and implement default behavior appropriate for that release.
Already implemented changes to the language model include:
New enum constant javax.lang.model.SourceVersion.RELEASE_7
New exception type
javax.lang.model.UnknownEntityException
added as a common
superclass for existing exception types
UnknownAnnotationValueException
,
UnknownElementException
, and
UnknownTypeException
.
New enum constant
javax.lang.model.element.ElementKind.RESOURCE_VARIABLE
.
New enum constant
javax.lang.model.type.TypeKind.DISJUNCTIVE
.
New mixin interfaces Parameterizable
and
QualifiedNameable
added to package
javax.lang.model.element
.
ExecutableElement
and TypeElement
are
retrofitted to extend Parameterizable
;
PackageElement
and TypeElement
are
retrofitted to extend QualifiedNameable
.
In the package description of
javax.lang.model.element
, requirements on when a model
must be provided are loosened to remove the requirement in case of an
"irrecoverable error that could not be removed by the generation of
new types," a condition which includes but is not limited to syntax
errors.
In the package javax.lang.model.type
,
MirroredTypesException
retrofitted to be the
superclass of MirroredTypeException
New method visitDisjunctive
added to visitor
interface javax.lang.model.type.TypeVisitor
.
Utility visitor implementations updated accordingly.
New utility visitors for release 7 in package
javax.lang.model.util
:
AbstractAnnotationValueVisitor7
AbstractElementVisitor7
AbstractTypeVisitor7
ElementKindVisitor7
ElementScanner7
SimpleAnnotationValueVisitor7
SimpleElementVisitor7
SimpleTypeVisitor7
TypeKindVisitor7
ElementKindVisitor
visitors
ElementScanner
visitors are updated to account for new
element kind RESOURCE_VARIABLE
.
Documentation comment defined in
javax.lang.model.util.Elements.getDocComment
.