Dan is the founder of Rectangular Software, an independent UK software company that provides development services and builds its own mobile and web applications. Dan has over a decade of experience in the software industry, building a wide variety of systems including casino, poker and spread-betting platforms, mobile applications, e-commerce websites, and network security software. His other programming interests include artificial intelligence, particularly evolutionary computation, and functional programming in Haskell. He has authored, or contributed to, a number of open source Java projects. Dan has posted 34 posts at DZone. You can read more from them at their website. View Full User Profile

JDK7 Tackles Java Verbosity

08.31.2009
| 14744 views |
  • submit to reddit

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.

From http://blog.uncommons.org

Published at DZone with permission of its author, Dan Dyer.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags:

Comments

Jeroen Wenting replied on Mon, 2009/08/31 - 7:27am

First is nice, second is useful, third seems extremely dangerous. At least we've been spared the function pointers (oops, "closures").

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

Every time a shortcut is created for things like this, more people forget they need to close resources properly.
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

The code you wrote is incorrect. The correct version is:
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

It's obvious to me that Java, the language, won't see radical changes anymore, only small improvements. And that's probably a good thing.

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 <>.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.