Fix Version/s: None
A preview language or VM feature is a new feature of the Java SE Platform that is fully specified, fully implemented, and yet impermanent. It is available in a JDK feature release to provoke developer feedback based on real world use; this may lead to it becoming permanent in a future Java SE Platform.
Define a model for partitioning new language and VM features based on whether they are permanent or impermanent in the Java SE Platform (that is, whether they will exist in the same form for all future releases, or will exist in a different form or not at all).
Communicate the intent that code which uses preview language and VM features from an older release of the Java SE Platform will not necessarily compile or run on a newer release.
Outline the relationship between preview language and VM features on the one hand, and Java SE and JDK APIs on the other hand.
It is not necessary for all new language and VM features to be available initially as preview features.
It is not necessary for this JEP to mandate specific mechanisms for collecting and evaluating developer feedback about preview language and VM features.
Nothing in this JEP should be interpreted as encouraging or allowing fragmentation of the Java SE Platform.
The Java SE Platform has global reach, so the cost of a mistake in the design of a Java language or VM feature is high. ("VM feature" encompasses the class file format and the JVM bytecode instruction set.) A mistake may be a hard technical error (such as a flaw in the type system), a soft usability problem (such as a surprising interaction with an older feature), or a poor architectural choice (such as one that forecloses on directions for future features).
To build confidence in the correctness and completeness of a new language or VM feature, it is desirable for the feature to enjoy a period of broad exposure after its specification and implementation are stable but before it achieves final and permanent status in the Java SE Platform. To achieve the broadest possible exposure, and to maximize the likelihood of swift feedback, the feature may be included in a JDK feature release on a preview basis. Previewing a feature in the JDK will encourage tool vendors to build good support for the feature before the bulk of Java developers use it in production.
Over the six-month course of the JDK feature release, and perhaps the following release too, the feature's "real world" strengths and weaknesses will be evaluated to decide if it has a long-term role in the Java SE Platform. Ultimately, the feature will either be granted final and permanent status (with or without refinements) or be removed.
Design of a Preview Feature
A preview language or VM feature is a new feature whose design, specification, and implementation are all complete, but which would benefit from a period of broad exposure and evaluation before either achieving final and permanent status in the Java SE Platform or else being refined or removed.
The key properties of a preview language or VM feature are:
High quality. A preview feature must display the same level of technical excellence and finesse as a final and permanent feature of the Java SE Platform. For example, a preview feature must respect traditional Java principles such as readability and compatibility, and it must receive appropriate treatment in the reflective and debugging APIs of the Java SE Platform. As a general rule, for anything not explicitly spelled out in this JEP, the policy is "No different for a preview feature than for a final and permanent feature."
Not experimental. A language or VM feature that is considered experimental, risky, incomplete, or unstable must not be previewed in a JDK feature release. An experimental feature must be iterated and stabilized in its own project, which in turn produces binaries that are clearly distinguished from binaries of the JDK Project. For the purpose of comparison, if an experimental feature is considered 25% "done", then a preview feature should be at least 95% "done". To make a further comparison, the level of completeness and stability expected for a preview language or VM feature is considerably higher than the level expected for an incubating API.
Universally available. The Umbrella JSR for the Java SE $N Platform enumerates the preview features in the platform. The desire for feedback and the expectation of quality means that these features are not "optional"; they must all be supported in full by every implementation of the Umbrella JSR. They are specified in appendices of the Java SE $N Editions of the Java Language Specification (JLS) and the Java Virtual Machine Specification (JVMS). The Java Compatibility Kit for Java SE $N checks conformance of an implementation's preview features to the appropriate appendix.
This JEP does not constrain the shape of a preview feature. A preview language feature may add declaration, statement, expression, and literal forms to the syntax of the Java language; it may modify the static semantics (typing) of pre-existing declarations, statements, expressions, and literals; and it may modify the dynamic semantics (execution) of statements or expressions. A preview VM feature may make additions and modifications of a similar nature to the class file format and the bytecode instruction set. Unlike incubating APIs, which have their own
jdk.incubator namespace for packages and modules, there is no requirement that a preview language or VM feature adopts a striking syntactic form to denote that the feature is available on a preview basis.
As a potential example of a preview feature, consider the changing role of the
_ character. It was redefined from an identifier to a keyword in order to reserve it for future language features. To provide a migration period for existing code, the redefinition was spread over two JDK releases: in JDK 8, the use of
_ as an identifier caused
javac to give a warning, while in JDK 9, it caused an error. In the regime described by this JEP, Java SE 8 would specify a preview language feature that defines
_ as a keyword.
javac in JDK 8 would give a warning for the use of
_ as an identifier, unless preview features are enabled, in which case
javac would give an error. Subsequently, Java SE 9 would specify the definition of
_ as a keyword on a final and permanent basis, so
javac in JDK 9 would always give an error for the use of
_ as an identifier, even when preview features are not enabled.
Use of Preview Features
Because preview language and VM features have not achieved final and permanent status in the Java SE Platform, they are unavailable by default at compile time and run time. Developers who wish to use preview language features in their programs must explicitly enable them in the compiler and the runtime system. That is, developers must "opt in" twice: once at compile time, when Java source code uses preview language features, and again at run time, when the corresponding class files are executed. These class files are special; they should not be distributed beyond the control of the developer who chose to use preview language features.
In order to allow the runtime system to detect when "opt in" is necessary, compilers must emit class files which (i) memorialize the use of preview language features by the original source code, and (ii) record the use of preview VM features in the constant pool entries and attributes of the class files. In more detail:
If Java source code uses a preview language feature of Java SE $N, then a Java compiler must record that the emitted class file depends on the preview VM features of Java SE $N. This applies even if the preview language feature is "syntactic sugar", i.e., it can be compiled without relying on preview VM features (such as novel class file constructs).
If a compiler (Java or non-Java) emits a class file which uses a preview VM feature of Java SE $N, then the compiler must record that the emitted class file depends on the preview VM features of Java SE $N. For a Java compiler, this requirement applies even if the Java source code uses no preview language features, because a Java compiler may choose to implement a final and permanent language feature by translation to a preview VM feature.
A class file denotes that it depends on the preview VM features of Java SE $N by having a
major_version item that corresponds to Java SE $N and a
minor_version item that has all 16 bits set. For example, a class file that depends on the preview VM features of Java SE 13 would have version 57.65535.
minor_versionis preferred to
access_flags, which is already very busy insofar as every bit is allocated to a flag when viewing the union of
method_infostructures. Unused bits in any one structure are best left for use by actual features.
minor_versionis also preferred to a custom attribute or a special constant pool entry because the VM's processing of the constant pool may depend on whether preview features are enabled, and those constructs would be read too late.
The unsubtle bit pattern in
minor_versionis deliberately chosen in preference to an individual bit. We wish to avoid well-meaning but ultimately misguided guesses at future roles, and therefore bit patterns, for the item. We also wish to avoid the particular confusion around the lowest bit: if a Java SE 13 class file with preview content had version 57.1, it would be easy to interpret incorrectly as the "next" version after 57.0.
A JVM implementation for Java SE $N must not define a class file that depends on the preview VM features of a different Java SE release, even if the JVM implementation would otherwise understand the class file's version. Specifically,
ClassLoader.defineClass must fail for the bytes of the class file. This prevents the class files from running years into the future, long after the preview language features that were enjoyed by the developer have been removed or finalized in a different form. In essence, Java SE $N+1 does not claim backwards compatibility with the preview features of Java SE $N.
If preview language features are not enabled at compile time, developers should not expect the compiler to compile source code which uses preview language features of any Java SE release, or to compile source code against class files which depend on preview VM features of any Java SE release. Similarly, if preview VM features are not enabled at run time, a JVM implementation will not load a class file that depends on the preview VM features of any Java SE release.
Example use of preview features
This JEP mandates the presence of a mechanism to enable preview features, which are otherwise disabled. This JEP also forbids the mechanism from enabling preview features on an individual basis, because all preview features have equal status in the Java SE Platform.
This JEP does not, however, specify an actual mechanism. Therefore, to aid understanding, this section outlines a possible mechanism for enabling preview features in the command-line tools of the JDK:
jshell, and possibly
jlink. The mechanism is a single command-line flag,
javac in JDK $N accepts the
--enable-preview flag only in combination with
--release $N or
-source $N. (For brevity, only
--release is mentioned in the rest of this JEP.)
The meaning of
--enable-previewchanges from one JDK to the next. Requiring the developer to spell out a concrete version number with
--releasesets the expectation that code relies on the preview features found specifically in JDK $N, and may not compile in future if JDK $N+1 has different preview features.
--enable-previewitself does not take a version number because it would be easy to misinterpret. For a developer using JDK 13, the flag
--enable-preview 14appears to suggest a commitment of what JDK 14 will contain, but no such commitment is possible.
There is no expectation that
javac in JDK $N will understand preview features from JDK $N-1 or any other prior release. For example, it would be costly for JDK 13 to support preview features from JDK 12 which were changed or dropped in response to feedback. Consequently,
--enable-preview is illegal if the operand to
--release is not $N.
On JDK 13:
javac Foo.java // Do not enable any preview features javac --release 13 --enable-preview Foo.java // Enable all preview features of Java SE 13 javac --release 12 --enable-preview Foo.java // DISALLOWED
On JDK 14:
javac Foo.java // Do not enable any preview features javac --release 14 --enable-preview Foo.java // Enable all preview features of Java SE 14 javac --release 13 --enable-preview Foo.java // DISALLOWED
When the preview language features of Java SE $N are enabled (
--release $N --enable-preview):
$N must be the Java SE Platform release implemented by the JDK containing the compiler. Only a compiler in JDK $N may support the preview language features defined by Java SE $N, even if the compiler habitually supports the final and permanent features defined by Java SE $N-1 and other prior releases. Developers should not expect
javacin JDK $N to compile source code which uses preview language features of other Java SE releases, or to compile source code against class files which depend on preview VM features (see below) of other Java SE releases.
If a compile-time error occurs due to the incorrect use of a preview language feature of Java SE $N, then
javacmay indicate that the error is associated specifically with a preview language feature. (This helps to highlight that the feature, as well as the compile-time errors associated with it, may vary in future Java SE releases.)
classfile emitted by
javacdepends on the preview VM features of Java SE $N, regardless of whether the source code corresponding to the
classfile actually uses preview language features of Java SE $N.
If a preview language feature of Java SE $N is a declaration form (e.g., record type declarations) rather than a statement or expression form, then for any source code that refers to an entity declared using the preview feature,
javacissues a suppressible "preview warning" akin to a "deprecation warning". (
javacdoes not record, in the
classfile emitted for the source code, that the
classfile depends on a preview VM feature of Java SE $N.) The output of
javadocshould highlight where an API refers to an entity declared with the preview feature, and also highlight the preview declaration of the entity itself.
Whether preview language features are enabled or disabled,
javac in JDK $N prints a message if it detects the use of a preview language feature of Java SE $N in source code. This message cannot be turned off by using
@SuppressWarnings in source code, because developers must be unfailingly aware of their reliance on the Java SE $N version of a preview language feature; the feature may change subtly in Java SE $N+1. The message looks like this:
Note: Some input files use a preview language feature. Note: Recompile with -Xlint:preview for details.
The off-by-default "preview" analysis suggested by the message provides information about each use of a preview language feature of Java SE $N. Additionally, on a best effort basis, the analysis may provide information about the use of preview language features of other Java SE releases.
The use of deprecated program elements causes
javacto print a similar message, suggesting to
Recompile with -Xlint:deprecation for details.However, developers can hide that message by using
@SuppressWarnings("removal"). The suppression of removal warnings, which indicate use of terminally deprecated elements, is discouraged, but it is permitted because the effect of removing such elements in a future Java SE release will be immediately and abundantly clear to developers (their programs will fail to recompile). In contrast, a preview language feature could be changed in a source-compatible but not behaviorally-compatible manner in a future Java SE release; programs which used the feature would recompile successfully, but have a different meaning. In effect, the future of a preview language feature is less predictable than the future of a terminally deprecated program element. Accordingly, the risk of using a preview language feature is higher than the risk of using a terminally deprecated program element, so the warning message for a preview feature is stiffer.
javadoc in JDK $N support the preview language features of Java SE $N only if
--enable-preview is specified at startup.
java launcher in JDK $N takes a flag to enable the preview VM features of Java SE $N. This enables execution of any class file that depends on those preview VM features, either because it truly refers to those features or because it was compiled from source code which used preview language features.
On JDK 13:
java Foo // Do not enable any preview features java --enable-preview Foo // Enable all preview features of Java SE 13 java --enable-preview -jar App.jar // Enable all preview features of Java SE 13 java --enable-preview -m App // Enable all preview features of Java SE 13
On JDK 14:
java Foo // Do not enable any preview features java --enable-preview Foo // Enable all preview features of Java SE 14 java --enable-preview -jar App.jar // Enable all preview features of Java SE 14 java --enable-preview -m App // Enable all preview features of Java SE 14
When the preview VM features of Java SE $N are enabled (
$N must be the Java SE Platform release to which the JVM implementation conforms. Only a JVM implementation which conforms to Java SE $N may support the preview features defined by Java SE $N. (It is extremely unlikely that a JVM implementation for Java SE $N+1 would want to support the preview features defined by Java SE $N.)
If a class file's use of a preview VM feature of Java SE $N causes an exception during loading, linking, or execution, then the JVM implementation may indicate that the exception is due to an preview VM feature of Java SE $N.
Whether preview VM features are enabled or not, class files that do not depend on preview VM features are loaded, linked, and executed in the ordinary way.
The JVM implementation in JDK $N has an off-by-default ability to show which loaded classes depend on the preview VM features of Java SE $N. To enable the ability, pass
-Xlog:class+preview to the
javap in JDK $N does not accept the
--enable-preview flag. It automatically highlights where a class file depends on preview VM features of Java SE $N. For a class file that depends on preview VM features of an earlier Java SE release,
javap in JDK $N makes a best effort to render the preview content.
Relationship to Java SE APIs
A preview language or VM feature in Java SE $N may rely on any API that is final and permanent in Java SE $N-1. For example, if multi-catch had been a preview feature, then it could legitimately have relied on the longstanding hierarchy of exception types under
More interestingly, a preview language or VM feature in Java SE $N will often be co-developed with enhancements to the
javax.* APIs in Java SE $N. Co-developed APIs fall into three buckets:
Essential. The API exists because code cannot enjoy the preview feature without it. Such an API lives in
java.*and the JLS will refer to it in normative text. For example, the enhanced-for statement relies on
java.lang.Iterable, and the try-with-resources statement relies on
Reflective. The API exists to expose the preview feature in the Core Reflection API, Method Handle API, Language Model API, Annotation Processing API, Compiler API, or JNI. Typically, this exposure is only necessary if the preview feature is a declaration form (such as enum types or record types) rather than a statement, expression, or literal form. For example, repeatable annotation types prompted additional methods in
java.lang.Class. Reflective APIs live in
javax.*depending on their history. The JLS will not refer to a reflective API in normative text, but may refer to it in non-normative text.
Convenient. The API is a collection of useful types and methods that promote or assist usage of the preview feature but are not essential for it. The JLS is unlikely to refer to the API in any way. For example, the Streams API is convenient for developers, especially when lambda expressions are given as arguments, but lambda expressions do not technically rely on it.
If a preview language or VM feature does not eventually achieve final and permanent status in the Java SE Platform, then its essential APIs in
java.* and its reflective APIs in
javax.* must be removed swiftly. It is important to communicate this possibility when the APIs are introduced, so that developers do not think of them as permanent, unchanging parts of the Java SE Platform. Furthermore, essential APIs are "special" -- they may be useful to broad swathes of Java programs regardless of whether those programs use any preview language features -- and so the use of essential APIs deserves sterner treatment than the use of reflective APIs. For example, if the enhanced-for statement had been a preview feature, then it would have been necessary to sternly warn against general-purpose use of the
java.lang.Iterable interface that was essential to co-develop with the statement.
For essential APIs in
java.*, this JEP adopts the following policy: ("source code reference to an essential API element" means the element is overridden, invoked, or referenced by name)
The JLS for Java SE $N must enumerate not only the preview language features defined by Java SE $N, but also the essential API elements associated with each preview feature.
The narrative specification of an essential API element must clearly document the element's impermanent nature and discourage general-purpose use of the element. At the very least, the API developer should write an
@previewtag in the element's
javadoccomment, as follows:
@preview This class/method/field is associated with $FEATURE_NAME, a preview feature of the Java language. Programs can only use this method when preview features are enabled. Preview features may be removed in a future release, or upgraded to permanent features of the Java language.
When compiling with preview features disabled, any source code reference to an essential API element associated with a preview feature must generate a compile-time error. An error is justified because a later release might remove the API element or incompatibly change its behavior. An error is also consistent with the treatment of code that uses a preview language feature when preview features are disabled.
When compiling with preview features enabled, any source code reference to an essential API element associated with a preview feature must generate a warning. This warning is suppressible with
@SuppressWarnings("preview"), unlike the warning given by
javacwhen it detects the use of a preview language feature in source code; the use of an essential API element is considered slightly less severe (and hence suppressible) than the use of a preview language feature.
For reflective APIs in
javax.*, and also for supported JDK APIs such as
com.sun.source.tree.*, this JEP recommends that any source code reference should generate a suppressible lint-style warning, whether preview features are enabled or disabled. The narrative specification of a reflective API element should document the element's impermanent nature as follows:
@preview This method/field/enum is associated with $FEATURE_NAME, a preview feature of the Java language. Preview features may be removed in a future release, or upgraded to permanent features of the Java language.
An earlier version of this JEP proposed to use the deprecation mechanism for flagging APIs associated with preview features. Consequently, in Java SE 12 and 13, the APIs associated with preview features were terminally deprecated at birth, that is, annotated with
@Deprecated(forRemoval=true, since=...)when they were introduced. For example, Java SE 13 declared an essential API associated with text blocks, and a reflective API associated with switch expressions. However, the deprecation-based approach was eventually dropped because it was confusing to see an API element introduced in the same Java SE release as it was deprecated, that is, to see
@Deprecated(forRemoval=true, since="13")on the same API element.
Relationship to Incubating APIs
An incubating API is an API of non-trivial size that is under development for eventual inclusion in the Java SE Platform or the JDK, but is not yet sufficiently proven.
A preview language or VM feature must not rely on an incubating API, since the API is not part of the Java SE Platform. For example, if a preview language feature was to expand the
catch statements to support a third kind of exception class (alongside the checked exception classes and the unchecked exception classes), then it would not be appropriate for the root class of this new kind (i.e., the analog of
java.lang.RuntimeException) to reside in an incubating API.
A preview language or VM feature may be associated informally with an incubating API that is offered for developer convenience, perhaps as an alternative to the convenient
java.* APIs described above. For example, if a preview language feature introduced multi-line string literals, then it may be advertised alongside new string-processing methods (e.g., to strip newlines, adjust indentation, etc) which reside in the
jdk.incubator.strings package long before they are committed to the
The implementation of a preview language feature by
javac, or the implementation of a preview VM feature by HotSpot, may rely on incubating APIs. For example, if
javac implements multi-line strings (a preview language feature) by storing them in a new kind of constant pool entry (a preview VM feature), then
javac may emit class files whose bytecode retrieves multi-line strings by invoking methods in the package
jdk.incubator.strings.classfile (an incubating API). As a convenience to developers, the incubator module which contains this package would be resolved automatically when the
--enable-preview flag is passed to
javac or the
It is conceivable that the implementation of a preview language or VM feature could rely on an incubating API whose own implementation relies on a different preview language or VM feature; implementers may have to collaborate in order to avoid circularity.
In the JEP Process, every new language and VM feature is drafted as a JEP and moves through various phases of candidacy and endorsement before being integrated into a JDK feature release. It is envisaged that a JEP can be drafted, reviewed, endorsed, submitted, and have development work start without regard to whether the feature will be integrated as a preview feature. This affirms, for a given release of the Java SE Platform, that the technical quality of a preview feature is equal to that of a final and permanent feature.
In other words, previewing should not be top of mind when a feature is designed and developed. Still, at some point, a JEP owner may warm to the idea of making the feature available on a preview basis. The owner is free to discuss the implications in the JEP, such as the possibility of the feature being previewed and later removed. (This would be especially appropriate in the somewhat risky situation where the feature relies on new
java.* APIs, since user code can refer to them despite strong advice not to. If feedback is likely to cause changes to the APIs, or if they are so attractive that their use will spread far beyond the preview feature, then the owner should consider if previewing is really appropriate.) The owner is also free to reflect previewing in the feature's implementation (such as the choice of package names for internal classes) and in related processes (such as compatibility review).
The formal step to preview availability occurs when the JEP reaches Proposed To Target status. At that time, the JEP owner must state if they wish the feature to be available as a preview in the proposed release. If and when the JEP reaches Targeted status, it must be flagged as a preview feature by having "(Preview)" appended to its title, e.g., "JEP 326: Raw String Literals (Preview)". The preview feature will be listed alongside permanent features in the Specification of the Java SE Platform, e.g., see the feature descriptions for Java SE 12). After the JEP is Targeted, it cannot easily change from preview to permanent, or vice versa; it must return to Candidate status first.
After a preview feature's code has been integrated into JDK $N, the JEP is closed as usual. Much evangelism lies ahead for the JEP owner! The technique or channel by which the owner requests or receives feedback from developers is left to the discretion and experience of the JEP owner. Given the fast six-month cadence for JDK feature releases, it is completely acceptable for the JEP owner to re-preview the feature in JDK $N+1 to gain further feedback; in this case, they should file a new JEP for JDK $N+1 to indicate this intent.
Eventually, the JEP owner must decide the preview feature's fate. If the decision is to remove the preview feature, then the owner should file an issue in JBS to remove the feature in the next JDK feature release; no new JEP is needed. On the other hand, if the decision is to finalize, then the owner should file a new JEP, noting refinements informed by developer feedback; this JEP will ultimately reach Targeted status for the next JDK feature release.
class file could denote that it depends on the preview VM feature of Java SE $N even if nothing in the
class file truly does. This would typically occur if source code uses a preview language feature that "compiles away"; if not for the
minor_version item of 65535, the
class file could be executed on a JVM implementation for Java SE $N in the ordinary way. An alternative approach would be less strict: require a
class file to denote that it depends on preview VM features only if something in the
class file truly does. (This could be coupled with a run-time check that
class files with a
minor_version of 65535 genuinely do use preview VM features and/or APIs connected with preview features.) However, such
class files could be widely distributed and executed for many years, long after the preview language feature is changed or removed. This is undesirable because the developer has no motivation to re-code to avoid the preview language feature; they can treat it as effectively final and permanent.
The JDK Project could publish Early Access (EA) binaries during stabilization of the release, prior to General Availability (GA). EA binaries may give new features the broad exposure necessary to provoke useful feedback. If refinements could be designed, specified, and implemented prior to GA, then there would be no need to preview the features in a GA release. Historically, however, EA binaries have not been widely downloaded and tested by developers at large; this is likely to be even more true when GA releases occur every six months.
In some cases, project-specific EA binaries are a plausible carrier for features that need feedback:
when the feature is not yet of the technical quality required for inclusion in a GA release of the JDK Project;
when the target audience of the EA binaries is small or heavily focused on the project, and the high visibility of a GA release is not yet desired;
when preview features are somehow pervasive and thus difficult to factor as separately packaged APIs, isolated language features, or discrete VM mechanisms.
A different way to include disabled features in a GA release is to hide them behind existing flags for conditional behavior. These include -Xlint:future in javac and -Xfuture in HotSpot. Alternatively, source code which uses an preview language feature could have an annotation on the class or method declaration to indicate that
javac should enable the preview feature automatically. (One benefit of this local, source-driven scheme is that the annotation could denote which Java SE release included the preview feature. Later versions of
javac would refuse to compile the code, avoiding the problem where the feature's semantics, but not syntax, changed after preview and would thus "silently" modify the meaning of the code.)
Risks and Assumptions
Under the six-month cadence, a language or VM feature which "misses the train" has only a short wait before the chance to catch the next one. The decision to preview a language or VM feature means including the feature in the stabilization branch, so the train has been caught, yet the final and permanent feature is not truly on board. This could cause confusion. Worse, it might tempt a feature owner who is in danger of missing the train to label their feature as a preview in order to catch it.
It is assumed that the time frame for feedback on a preview language or VM feature (typically six months, but more if it re-previews) is sufficient to allow non-trivial course corrections. However, because exploiting new language features can demand substantial refactoring of existing programs, the time frame may not be sufficient for thorough exploration by developers.