Cool Tools and Other Stuff

JavaOne 2010: Upcoming Java Features

by Eric Armstrong

September 23, 2010



Summary

An overview of upcoming features in Java.


In the Java booth, Jim Holmlund gave me an overview of upcoming features in Java. (Luckily for me, he had a copy of the speaker's slides. So it made up for the session I missed in the morning.)

Some of what's coming is pretty cool. Some is a bit dissapointing, compared to what I was hoping for. Here's my notes:

Java 7

Java 7 will get a variety of small language enhancements that are part of the COIN project:

Strings in Switch Statements

A long overdue addition, the switch statement will find uses outside of low-level tokenizers that switch on character bytes and integers. It will be possible to compare strings, making a "dispatch" utility that will have many uses.





A long overdue addition, the switch statement will find uses outside of low-level tokenizers that switch on character bytes and integers. It will be possible to compare strings, making a "dispatch" utility that will have many uses. Underscores in constants

When you're putting 1000000 miliseconds into a constant, you'll be able to make it more readable by writing it as 1_000_000. The compiler will then strip out the underscores to produce the actual constant.





When you're putting 1000000 miliseconds into a constant, you'll be able to make it more readable by writing it as 1_000_000. The compiler will then strip out the underscores to produce the actual constant. Multi-catch

Instead of being limited to a single exception per catch clause, you'll be able to catch multiple exceptions in one clause, and handle them each in the same way.



Instead of being limited to a single exception per clause, you'll be able to catch multiple exceptions in one clause, and handle them each in the same way. Autoclose interface

One of Ruby's goodnesses here. If you implement the autoclose interface, you can put input and output streams in a single try block and, when the block ends, all of the streams are closed. It's an important feature that saves you the headache of making sure that you close everything when an exception disrupts the flow of processing. It will also eliminate memory leaks that can accumulate when programs are terminated abnormally, either externally or internally. That capability, in turn, means that a VM will be able to stay up longer before memory leaks force it to its knees.





One of Ruby's goodnesses here. If you implement the autoclose interface, you can put input and output streams in a single try block and, when the block ends, all of the streams are closed. It's an important feature that saves you the headache of making sure that you close everything when an exception disrupts the flow of processing. It will also eliminate memory leaks that can accumulate when programs are terminated abnormally, either externally or internally. That capability, in turn, means that a VM will be able to stay up longer before memory leaks force it to its knees. Default methods for interfaces

When defining an interface, it will be possible to specify a default implementation for a method signature. That feature helps in two ways. First, it means that implementation code which is typically written the same way can be provided in one DRY location. Second, it means that an interface designer can provide null implementations for features to be added at a later date. The idea is that older code won't break when new features are added to implementation objects.



For example, let's say you publish a tree-processing interface. Any object that implements that interface can be given to your summation method, which will add up all the values in that tree. (A directory tree, for example, with a count of files in each directory.) I use that summation processor, and you do too. One day, you know you'll want to add up the file sizes, as well. But you don't have time to implement it right now. If you require tree interface to have a size() method, you force me to implement it, even though it's never used. But if you don't, you can't add it later without breaking my implementation. You naturally don't want to do that, so you define a default size() method. Then, when you get around to it, you define a diskSpace() method that takes a Tree object, and you define a size() method in your DirectoryTree implementation. Everything works for you. As for me, I never implement size() , but I don't care: I never use that newfangled diskSpace() method anyway, so the default implementation of t size() is good enough for me.





When defining an interface, it will be possible to specify a default implementation for a method signature. That feature helps in two ways. First, it means that implementation code which is typically written the same way can be provided in one DRY location. Second, it means that an interface designer can provide null implementations for features to be added at a later date. The idea is that older code won't break when new features are added to implementation objects. For example, let's say you publish a tree-processing interface. Any object that implements that interface can be given to your summation method, which will add up all the values in that tree. (A directory tree, for example, with a count of files in each directory.) I use that summation processor, and you do too. One day, you know you'll want to add up the file sizes, as well. But you don't have time to implement it right now. If you require tree interface to have a size() method, you force me to implement it, even though it's never used. But if you don't, you can't add it later without breaking my implementation. You naturally don't want to do that, so you define a default size() method. Then, when you get around to it, you define a diskSpace() method that takes a Tree object, and you define a method in your DirectoryTree implementation. Everything works for you. As for me, I never implement , but I don't care: I never use that newfangled method anyway, so the default implementation of t is good enough for me. Type "Inferencing"

This is one that sounded good on paper, until I found it what it actually meant. I was hoping for something that would put an end to "viral generics". You know, when a library returns a generic, and you call that API, now you have to put the generics on your variable to make the warning go away--and when you return it, everything that calls you has to have generics added. (Old languages used to have 4 pages of warnings, making it hard to spot the errors. To this day, I dislike warnings.)

So my expectation for "type inferencing" was that it would work sort of like Ruby or Scala. If f(x) returns an ArrayList of String, then there would be no need to code ArrayList<String> list = f(x) . Instead, you would just code list = f(x) , like you used to, and the compiler would figure it out.. No such luck. Instead of inferencing from right to left, as I expected, it works the other way around.

Instead of specifying this: List<List<String>> list = new ArrayList<List<String>>();

You'll be able to specify this: List<List<String>> list = new ArrayList<>();



Granted, it's an improvement. But it's a pretty small improvement. And it's not even really type inferencing. Instead, it's type deduction: If you tell the compiler what the type is on the left side of the assignment, it can figure out what the type has to be on the right side, a few characters later. I should hope so. Pardon my disappointment, but I was looking for a lot more.

Java 8(ish)

VM Support for Dynamic Languages:

These features will make it possible for truly dynamic languages to be implemented without compromise. (Fully dynamic type safety for languages like JRuby comes to mind as one of the features that will probably be implemented.)





These features will make it possible for truly dynamic languages to be implemented without compromise. (Fully dynamic type safety for languages like JRuby comes to mind as one of the features that will probably be implemented.) LambdaJ:

This features makes functions into first-class objects so that, for example, an anonymous function can be passed as an argument to a method, using syntax like this: #{..function definition here...}

That's an important step towards functional programming capabilities, of course. But it's only one of several steps that are needed, and it's going to be a year or two before Java 8 is available. (For more on that subject, see the next report.)

Next: Functional Programming, from Java to Scala

Talk Back!

Have an opinion? Readers have already posted 47 comments about this weblog entry. Why not add yours?

RSS Feed

If you'd like to be notified whenever Eric Armstrong adds a new entry to his weblog, subscribe to his RSS feed.

About the Blogger

Eric Armstrong has been programming and writing professionally since before there were personal computers. His production experience includes artificial intelligence (AI) programs, system libraries, real-time programs, and business applications in a variety of languages. He works as a writer and software consultant in the San Francisco Bay Area. He wrote The JBuilder2 Bible and authored the Java/XML programming tutorial available at http://java.sun.com. Eric is also involved in efforts to design knowledge-based collaboration systems.

This weblog entry is Copyright © 2010 Eric Armstrong. All rights reserved.