JDK7 Tackles Java Verbosity
The Java Language changes accepted for inclusion in JDK7 have been announced by Joseph Darcy. We already knew that closures were off the menu. So too, unfortunately, is language support for arbitrary-precision arithmetic. The final list is pretty non-controversial and includes a number of changes that will reduce the verbosity of Java programs (one of the main criticisms of Java from proponents of other languages). Java will never be as terse as Perl or Haskell, but that’s no bad thing. One of the strengths of Java is its readability. There are however some areas where the language is needlessly verbose and that’s what these changes are addressing.
Simplified Generics
The last major revision of the Java language was Java 5.0, which introduced generics, auto-boxing, enums, varargs and annotations. Despite the compromises of type erasure, generics have been a major improvement to the language. They have also contributed to the verbosity of Java code. The necessity to specify, in full, both the reference type and value type of a field or variable has led to some very long declarations:
Map<String, List<BigDecimal>> numberMap = new TreeMap<String, List<BigDecimal>>();
JDK7’s proposed diamond notation allows the programmer to omit the generic parameters on the righthand side if they are the same as the left:
Map<String, List<BigDecimal>> numberMap = new TreeMap<>();
Collection Literals
The long overdue addition of collection literals will help to reduce the size of Java code and make it more readable. Lists, sets and maps can be created and populated without the need for cumbersome instance initialisers:
List<Integer> powersOf2 = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024};
Map<String, Integer> ages = {"John" : 35, "Mary" : 28, "Steve" : 42};
Automatic Resource Management
Josh Bloch’s proposal for automatic resource management gives Java an alternative to C++’s RAII and C#’s using. It eliminates much of the boiler-plate exception handling that surrounds the proper creation and disposal of resources, such as IO streams, in Java code. The proposal introduces a new interface, Disposable, that resources will implement. The syntax of try/catch/finally is extended to allow resources to be specified at the start. These resources are then automatically disposed upon completion. Here’s an example of the new syntax in action (taken from the proposal):
static String readFirstLineFromFile2(String path) throws IOException
{
try (BufferedReader reader = new BufferedReader(new FileReader(path))
{
return reader.readLine();
}
}
Other Changes
As well as the above changes to tackle verbosity, JDK7 adds binary integer literals and the ability use String literals in switch statements. JDK7 will also fix the problem of mixing varargs parameters with generic types.
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)






Comments
Jeroen Wenting replied on Mon, 2009/08/31 - 7:27am
Stevi Deter replied on Mon, 2009/08/31 - 10:58am
in response to:
Jeroen Wenting
Jeroen,
I'm curious why you think automatic resource handilng "seems extremely dangerous".
As someone who also programs in C#, I find this approach extremely useful in scoping resource usage.
The only downside I can see is that obscuring the setup/teardown of resources can make them less forward in one's mind. The best comparison I can make is to the times I've been on projects that rely on Spring to manage database connections that develop connection leaks in the one or two specialized cases where the Spring management is circumvented. But that's more an issue of understanding the frameworks you're using rather than blindly using them.
Jeroen Wenting replied on Tue, 2009/09/01 - 1:27am
And most resource handling doesn't lend itself to a one liner like the example, would require the resource to be manually opened and closed.
I'd have been happier if they'd introduced some way to read a file or stream into memory with a single command and immediately close it again, with the BLOB (let's call it that) being accessible like the thing it was read from afterwards.
Something like
File f = new File("myfile.txt"); f.loadFile(); BufferedReader r = new BufferedReader(f);My main concern with things like this is transparency. There's no more explicit operations, people loose track of what goes wrong and where.Benjamin Winterberg replied on Tue, 2009/09/01 - 3:19am
The API doesnt change. If you want explicit resource handling you can do, but you are no longer forced to do so.
I/O in its current state is horrible. Its primarily because of the many checked exceptions you have to handle on closing resources. This results in heavy boilerplate finally blocks like this:
public static <T> T copy(T original) {
ByteArrayOutputStream bos = null;
ObjectInputStream in = null;
ObjectOutputStream out = null;
T obj = null;
try {
bos = new ByteArrayOutputStream();
out = new ObjectOutputStream(bos);
out.writeObject(original);
out.flush();
in = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
obj = (T) in.readObject();
}
catch(IOException e) {
LOG.error("copy", e);
throw new RuntimeException(e);
}
catch(ClassNotFoundException e) {
LOG.error("copy", e);
throw new RuntimeException(e);
}
finally {
Exception ex = null;
try {
bos.close();
}
catch (IOException e) {
LOG.error("copy", e);
ex = e;
}
try {
out.close();
}
catch (IOException e) {
LOG.error("copy", e);
ex = e;
}
try {
in.close();
}
catch (IOException e) {
LOG.error("copy", e);
ex = e;
}
if (ex != null) {
throw new RuntimeException(ex);
}
}
LOG.trace("Deep copy completed: " + obj);
return obj;
}
I appreciate the changes on that! Language features are for writing maintainable code. Let newbies learn their own lessons...
Ricky Clarkson replied on Tue, 2009/09/01 - 9:36am
Jeroen,
You would prefer resources to continue to be left unclosed and instead an extra method added which causes memory problems when we have large files or non-terminating streams.
As usual, I think the best thing to do is the opposite of what you suggest.
Ricky.
Anthony Goubard replied on Tue, 2009/09/01 - 12:04pm
Well, I think the the automatic resource management is quite confusing. I don't find it readable.
I see the following problems:
- long try statement
- can you catch exception? I think yes
- what if you close the stream in your code?
- if you catch the IOException, do you also catch the code in the try brackets?
- what if your code is "if (path.starts("http://")) stream = new URL(path).openStream() else stream = new FileInputStream(path);"?
I don't understand why can't we have "if an object implements Disposable and is no longer reachable/used => close it". Implementation of this should probably be done at compile time to keep backward compatibility.
...
I can see with it a new chapter in the Java Puzzlers book coming.
Jacek Furmankiewicz replied on Tue, 2009/09/01 - 3:58pm
in response to:
Anthony Goubard
Just an FYI, automatic resource management is already available today in JDK 1.6 via Project Lombok:
http://projectlombok.org/features/Cleanup.html
Anthony Goubard replied on Wed, 2009/09/02 - 1:56am
in response to:
Jacek Furmankiewicz
Thanks for pointing to this project, the code is indeed more readable than a
try (InputStream in = new FileInputStream(args[0])) {
try (OutputStream out = new FileOutputStream(args[1]) {
...
}
}
Jacek Furmankiewicz replied on Wed, 2009/09/02 - 6:31am
in response to:
Anthony Goubard
That is nothing. Did you discover Lombok's @Data yet?
http://projectlombok.org/features/Data.html
Now this has reduced my Java verbosity by leaps and bounds.This one annotation will do more to reduce the lines of Java code than all the Project Coin changes put together.
And once the bindable property support will be added:
http://code.google.com/p/projectlombok/issues/detail?id=27
then finally Java will get proper, easy two-way databinding for POJOs, despite Sun's total failure to deliver this in the last 10 years.
Project Lombok is Java developers taking back the language that Sun has failed to keep up to date. And you can use it today in production JDK 1.6 apps.
Rogerio Liesenfeld replied on Wed, 2009/09/02 - 6:56am
in response to:
Anthony Goubard
try (InputStream in = new FileInputStream(args[0]); OutputStream out = new FileOutputStream(args[1])) { ... }Anthony Goubard replied on Wed, 2009/09/02 - 9:22am
in response to:
Rogerio Liesenfeld
Thanks for fixing it. This totally shows my point of readable/usability + long try statements.
What if you need to do something else between the creation of the input stream and the creation of the output stream, you put all your "in between" code in the try statement?
Rogerio Liesenfeld replied on Wed, 2009/09/02 - 10:41am
We might still see a successful successor, though. I don't think that language will be Scala, but JavaFX Script. This assuming Oracle invests heavily on it, as they probably will.
Mike P(Okidoky) replied on Wed, 2009/09/02 - 8:33pm
I find it very strange to see multiple statement inside parenthesis:
try
(
InputStream in = new FileInputStream(fileIn);
OutputStream out = new FileOutputStream(fileOut);
)
{
out.write(in.read());
}
(ps. also note my indentation style, I forever maintain it's superior to putting brackets at the end of a code line).
Questions:
1. Can I only allocate resources that implement the Disposable interface? If I am free to put anything there, then the compiler wouldn't warn me that it's probably expected that the resource gets cleaned up, while it won't. It would be really good if only resources could be created if they implement that Disposable interface.
2. Can I still have a finally block, and does my finally block get to run before or after this implicit automatic call to Disposable?
Mike P(Okidoky) replied on Wed, 2009/09/02 - 8:37pm
Question about Collection literals:
Can I do this:
void test(Map<String, String> map)
{
}
void test2()
{
test( { "a": "A", "b" : "B" } );
}
Second question, can I nest, like so:
void test(Map<String, Map<String, Integer>> map)
{
}
void test2()
{
test( { "a": { "b": 123 } } );
}
???
Mike P(Okidoky) replied on Thu, 2009/09/03 - 12:04am
Another question. With Collection Literals, does List<Integer> list = { 1, 2, 3 }; become an ArrayList?
And does Map<Integer, Integer> map = { 1: 2, 3: 4 }; become a HashMap or LinkedHashMap (for key order)?
Serif Cay replied on Tue, 2009/09/08 - 3:52am
Map<String, List<BigDecimal>> numberMap = new TreeMap<>();
why do we need to use generics for right side. if compiler can understand with empty <>;
I think it can understand without <>.