5 things you didn’t know about …
Local-variable type inference is the controversial headliner, but Java
10 brings welcome changes to garbage collection and container awareness in the
JVM
Content series:
This content is part # of # in the series: 5 things you didn’t know about …
https://www.ibm.com/developerworks/library/?series_title_by=**auto**
Stay tuned for additional content in this series.
This content is part of the series:5 things you didn’t know about …
Stay tuned for additional content in this series.
Java™ developers are accustomed to waiting years for a new Java
release, but the new, high frequency release cadence changes all of that.
It’s been just six short months since Java 9 emerged, and now Java 10 is
already knocking at the door. In six more months we’ll be welcoming Java
11. Some developers might find such a rapid releases overkill, but the new
cadence marks a long-needed change.
True to its number, Java 10 offers 10 new features, and this article offers the five
that I find most significant (you can
view them all on the Open JDK 10 project page).
1. Java’s new release cadence
Historically, the JDK release cadence has been driven by big, new features.
As recent examples, Java 8 introduced functional programming in the form
of lambdas and streams, and Java 9 introduced the modular Java system.
Each new version was hotly anticipated, but minor fixes were often left on
the shelf, waiting for larger components to be finalized. Java’s evolution
lagged behind other languages.
The new high-frequency cadence pushes Java forward in smaller increments.
Features that are ready by the release date will be included, and those
that aren’t can be scheduled for the next release, just six months away.
The first Java version under this new cycle was Java 9, which came out in
October 2017. Java 10 was released in March 2018, and Java 11 is
anticipated in September 2018.
As part of the new cadence, Oracle has said that it will only support each
major release until the next major one comes out. When Java 11 is
released, Oracle will stop supporting Java 10. Developers wanting to
ensure their Java version is supported will have to migrate to a major
release every 6 months. Developers who don’t want or need such frequent
migrations can utilize the LTS (long-term support) release, which is
updated every three years. The current LTS release, Java 8, will be
supported until Java 11 comes out this fall.
2. Local-variable type inference
Local-variable type inference is by far the most visible feature in Java
10. Strongly debated before finding its way into JDK 10, this feature
allows the compiler to infer the type of a local variable, rather than
requiring that the programmer explicitly specify it.
Listing 1 shows how a String
variable type would be defined
before Java 10.
Listing 1. Declare and assign a String variable
String name = "Alex";
Listing 2 shows the same String
variable defined in Java
10.
Listing 2. A String variable defined using local-variable
type inference
var name = "Alex";
As you can see, the only difference is the use of the var
reserved type name. Using the expression to the right, the compiler can
infer the type of the variable name
as String
.
That seems a bit easy, so let’s look at a more complex example. What if the
variable was assigned to the return value of a method call? In this case
it’s possible for the compiler to infer the variable type from the return
type of a method, as shown in Listing 3.
Listing 3. A String variable inferred from return
type
var name = getName(); String getName(){ return "Alex"; }
Using local variable types
As the name suggests, the local-variable type inference feature is only
available to local variables. It can’t be used to define instance or class
variables, nor can it be used in method parameters or return types.
However, you can use var
in classic and enhanced
for-loops where the type can be inferred from the iterator, as shown in
Listing 4.
Listing 4. Use var in loops
for(var book : books){} for(var i = 0; i < 10; i++){}
The most obvious reason to use this type is to reduce verbosity in your
code. Take a look at the example in Listing 5.
Listing 5. Long type names make long code
String message = "Incy wincy spider..."; StringReader reader = new StringReader(message); StreamTokenizer tokenizer = new StreamTokenizer(reader);
Note what happens when we re-write Listing 5 using the var
reserved type name.
Listing 6. The var type reduces code verbosity
var message = "Incy wincy spider..."; var reader = new StringReader(message); var tokenizer = new StreamTokenizer(reader);
The type declarations in Listing 6 line up vertically and the type is
mentioned once in each statement, to the right of the constructor call.
Imagine the benefits of using this type for the long class names common in
some Java frameworks.
Issues with local variable types
1. var obscures type
You’ve seen how var
can improve code readability, but on the
flipside it can also obscure it. Take a look at the example in Listing
7.
Listing 7. The return type is unclear
var result = searchService.retrieveTopResult();
In Listing 7 we have to guess at the return type. Code that makes the
reader guess what is happening is harder to maintain.
2. var doesn’t mix with lambdas
Type inference does not work well when used with lambdas, mainly due to the
lack of type information available to the compiler. The lambda expression
in Listing 8 will not compile.
Listing 8. Insufficient type information
Function<String, String> quotify = m -> "'" + message + "'"; var quotify = m -> "'" + message + "'";
In Listing 8 there isn’t enough type information in the right-hand
expression for the compiler to infer the variable type. Lambda statements
must always declare an explicit type.
3. var doesn’t mix with the diamond
operator
Type inference also doesn’t work well when used with the diamond operator.
Take a look at the example in Listing 9.
Listing 9. Using the diamond operator with var
var books = new ArrayList<>();
In Listing 9, what is the parameter type of the ArrayList
referenced by books
? You might know that you want the
ArrayList
to store a list of books, but the compiler can’t
infer that. Instead, the compiler will do the only thing it can
do, which is to infer an ArrayList
parameterized by the
Object
type: ArrayList<Object>()
.
The alternative is to specify the type in the diamond operator in the
right-hand expression. You can then let the compiler infer the variable
type from that, as shown in Listing 10. Otherwise, you must explicitly
declare the variable in the traditional way:
List<Book> books
. In truth, you might prefer this option
because it allows you to specify an abstract type and program to the
List
interface:
Listing 10. Specify the type
var books = new ArrayList<Book>();
3. Additions, removals, and
deprecations
Removals
Java 10 removes a number of tools:
- The command-line tool
javah
, but you can use
javac -h
instead. - The command-line option
-X:prof
, though you can use the
jmap
tool to access profiling information. - The
policytool
.
Some APIs that have been marked as deprecated since Java 1.2 have also been
permanently removed. These include the
java.lang.SecurityManager.inCheck
field and the following
methods:
java.lang.SecurityManager.classDepth(java.lang.String)
java.lang.SecurityManager.classLoaderDepth()
java.lang.SecurityManager.currentClassLoader()
java.lang.SecurityManager.currentLoadedClass()
java.lang.SecurityManager.getInCheck()
java.lang.SecurityManager.inClass(java.lang.String)
java.lang.SecurityManager.inClassLoader()
java.lang.Runtime.getLocalizedInputStream(java.io.InputStream)
java.lang.Runtime.getLocalizedOutputStream(java.io.OutputStream)
Deprecations
JDK 10 also deprecates some APIs. The java.security.acl
package has been marked as deprecated, and so have various related classes
(Certificate
, Identity
,
IdentityScope
, Singer
, auth.Policy
)
in the java.security package
. Also, the
CREDENTIAL_TYPES
in the
javax.management.remote.rmi.RMIConnectorServer
class is
marked deprecated. The finalize()
methods in
java.io.FileInputStream
and
java.io.FileOutputStream
have been marked as deprecated. So
has the finalize()
method in the
java.util.zip.Deflater
/Inflater
/ZipFile
classes.
Additions and inclusions
As part of the ongoing alignment of the Oracle JDK and Open JDK, Open JDK
now includes a subset of the root certificates authority that are
available in the Oracle JDK. These include Java Flight Recorder and Java
Mission Control. Additionally JDK 10 has added enhanced support for
Unicode extensions of BCP 47 language tags where appropriate in the
java.text
, java.time
, and java.util
packages. Another new feature allows the execution of a callback on
threads without performing a global VM safepoint. This makes it both
feasible and inexpensive to halt individual threads, rather than requiring
that you halt all threads or none.
4. Improved container awareness
If you deploy to containers like Docker then this feature is especially for
you. The JVM is now aware that it is running in a container, and will
query the container for the number of processors available for use, rather
than querying the host operating system. It’s also possible to externally
attach to a Java process running in a container, which makes monitoring
JVM processes easier.
Previously, the JVM was unaware of its container and would ask the host
operating system for the number of active CPUs. In some cases this led to
over-reporting resources to the JVM, causing problems when multiple
containers were running on the same operating system. In Java 10, you can
configure a container to use a subset of the host operating system’s CPUs,
and the JVM will be able to determine the number of CPUs in use. You also
can explicitly specify the number of processors the containerized JVM is
able to see, using the -XX:ActiveProcessorCount
flag.
5. Application class data sharing
The objective of this feature is to improve JVM startup times between runs
and with multiple JVMs running the same code, while also reducing the
memory footprint. This is achieved through sharing metadata about classes
among JVMs. The first run of the JVM collects and files data about the
classes it has loaded. It then makes the data file available to other JVMs
and subsequent runs of that JVM, saving time and resources in the JVM
initialization process. Class data sharing has actually been available for
some time, but restricted to system classes only. Now this feature has
been extended to include all application classes.
Conclusion
The headline feature in Java 10 is clearly the new var
reserved type name. It has the power to clarify and simplify code, though
if used carelessly it can also obscure meaning and intent. An IDE may be
able to help identify types when it is not clear, but not all code is read
in an IDE. Often we read code online in a GitHub repository, in a
debugger, or in code-review tools. Developers using this new feature are
advised to be mindful of code readability for future readers and
maintainers.
Java’s new, high frequency release cadence is a welcome change. It forces
the release of features that are ready at the release date, and gives
delayed features a shorter turnaround to the next release. The new cycle
will hasten Java’s progress, and developers won’t have to wait years for
features already developed and living on the shelf. There is some
reasonable concern about the shorter support lifespan from one major
release to the next, but the LTS should help buffer that issue. Another
risk is release fatigue, as developers tire of constant migrations. Still,
overall, I think this is a positive move that will help keep Java alive
and evolving for some time to come.
Downloadable resources
Related topics
Credit: Source link