Project Coin/JSR 334 Documentation v0.83

Table of Contents

Overview

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:

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.

Features

Strings in switch

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 be char, 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 a null label and require a NullPointerException to be thrown if the expression being switched on is null. A null expression can occur for both enum types and for boxed primitive types like Integer and Float. 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 integral literals and underscores in numeric literals

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 BinaryDigits
0 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 HexDigits HexDigitsAndUnderscoresopt HexDigit
HexDigitsAndUnderscores:
HexDigitOrUnderscore
HexDigitsAndUnderscores HexDigitOrUnderscore
HexDigitOrUnderscore:
HexDigit
_
OctalNumeral:
0 OctalDigits
0 Underscores OctalDigits
OctalDigits:
OctalDigit
OctalDigit OctalDigits OctalDigitsAndUnderscoresopt 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:

while disallowed uses of underscores include:

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 leading 0 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).


Multi-catch and more precise rethrow

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 ( FormalParameter CatchFormalParameter ) 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:

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 being Foo or some subclass of Foo), 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 be final or effectively final preserves flexibility if fuller support is added in the future.

The revised exception analysis for final and effectively final catch parameters is more precise than the previously defined analysis. Therefore, when the new analysis is applied to existing code, all throws clauses on methods and constructors remain valid.


Improved Type Inference for Generic Instance Creation (diamond)

First, grammatical changes in JLSv3 §15.9 to the ClassInstanceCreationExpression: production:

ClassInstanceCreationExpression:
new TypeArgumentsopt ClassOrInterfaceType TypeDeclSpecifier TypeArgumentsOrDiamondopt ( ArgumentListopt ) ClassBodyopt
Primary . new TypeArgumentsopt Identifier TypeArgumentsopt TypeArgumentsOrDiamondopt ( 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 a class instance creation expression does not declare an anonymous class, then:

In JLSv3 §15.9.3 (Choosing the Constructor and its Arguments),

Let C be the class type being instantiated. To create an instance of C, i, a constructor of C is and 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. The type of the class instance creation expression is the result type of the chosen constructor, as defined above. Note that the type of the class instance creation expression this 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:

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:

Types newly implementing or extending java.io.Closeable:

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:

TryStatement:
try Block Catches
try Block Catchesopt Finally
try ResourceSpecification Block Catchesopt Finallyopt

Supporting new grammar productions are added:

ResourceSpecification:
( Resources ;opt )
Resources:
Resource
Resource ; Resources
Resource:
VariableModifiersopt Type VariableDeclaratorId = 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:

In a try-with-resources statement that manages multiple resources:

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 is null 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 a catch clause, a finally block, and a resource specification. Furthermore, it is permissible for a try 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 a try-with-resources statement can throw.

By design, no special accommodations are made to deal with the ThreadDeath error which is spawned by the long-deprecated Thead.stop method.

The expert group is discussing whether or not the try-with-resources statement should be altered to included separate handling for InterruptedException. Proper handling of InterruptedException and a thread's interrupted status is necessary for the correctness of various multi-threaded algorithms. As a general comment, it is ill-advised for the close method of an AutoCloseable 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 explicit final 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 a try-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 the try-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 declare AutoCloseable to be operated on by the try-with-resources statement


Simplified Varargs Method Invocation

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 SafeVarargs

A 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:

Compilers are encouraged to issue warnings when this annotation type is applied to a method or constructor declaration where:


The platform methods and constructors annotated with a @SafeVarargs annotation are:


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 like java.util.Collections.addAll, whose declaration starts with


public 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 of Collections.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 class java.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 to static 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, a SafeVarargs-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 the java.lang package.

The SafeVarargs annotation type is declared with a runtime RetentionPolicy for several reasons. Some representation of the SafeVarargs 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 the SafeVarargs status of a method or constructor since the presence or absence of the annotation can be tested. For example, there is no need for an isSafeVarargs method on the Method and Constructor classes in the java.lang.reflect package or for an isSafeVarargs method in javax.lang.model.element.ExecutableElement. Therefore, the SafeVarargs 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.


Appendix — JSR 269 language model

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:


Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.