Saturday, April 30, 2011

A snapshot of project coin in JDK7

Hi, at last I downloaded the JDK and adopted the early IntelliJ 10.5 release so to play with this new version (can't adopt Netbeans, really can't :) ).
In order to prepare a small meeting with Oracle evangelists about the new release, I tuned some really little test (yes I like that!!) to play the new stuff.
I did not practice everything but before embracing the new NIO.2 (this is a tradition for me: since nearly 15 years I always discover the I/O API improvements on each new JDK, superstition I guess).

I started very easy with the coin project testing the improvement on the switch statement concerning the ability to switch on String.

Driving my test with TDD (forever thank you Mr Beck), I designed a small StringSwitch class tested this way:
 @Test
public void switch_WithFoo_ShouldReturnBar() {
assertThat(new StringSwitch().respond("foo"), is(equalTo("bar")));
}

@Test
public void switch_WithDean_ShouldReturnMartin() {
assertThat(new StringSwitch().respond("dean"), is(equalTo("martin")));
}

@Test
public void switch_WithUnknown_ShouldReturnUnknown() {
assertThat(new StringSwitch().respond("anybody"), is(equalTo("unknown")));
}
This drove to the following bunch of code:

public String respond(final String message) {
final String response;
switch (message) {
case "foo":
response = "bar";
break;
case "dean":
response = "martin";
break;
default:
response = "unknown";
}
return response;
}
Easy stuff :)Still easy (yep I know), a small enhancement on syntax for numeric literals. The driven test looked like:

@Test public void million_ShouldBe_Divided() {
assertThat(new Amount(1_000_000).divideByThousand(), is(equalTo(1_000)));
}

@Test
public void evaluateBinary() {
assertThat(0b1110 >> 1, is(equalTo(0b111)));
}
Elegant and easy to read. A valuable feature when you have been programming in a bank believe me.
For previous C developers, one should notice that additional literal style has been added for short and bytes.

There must be a lot to say about the diamond notation and the multiple try/catch statements, but I have been lazy on these ones. I simply verified that it was possible to adopt the less chatty diamond notation, TDD programming a dumb list wrapper:

@Test
public void newListDiamond_ShouldBeEmpty() {
assertThat(new ListDiamond().isEmpty(), is(true));
}

@Test public void newListDiamond_WithOneElement_ShouldNotBeEmpty() {
assertThat(new ListDiamond().with("string").isEmpty(), is(not(true)));
}
This leads to the following definition of the ListDiamond class:
public final class ListDiamond {
private final List list;

public ListDiamond() {
super();
list = new ArrayList<>();
}

public boolean isEmpty() {
return withList().isEmpty();
}

public ListDiamond with(final String string) {
withList().add(string);
return this;
}

private List withList() {
return list;
}
}

Just imagine how simpler it will be with more complex map of list or list of list, actually obfuscating the code.

What interested me most I must confess was the try-with-resource statement. Basically this improvement prevent from the production of entangled code when we do come to the point of closing resources we have allocated. See what I mean ? You know this piggy code you got to write each time you open streams, JDBC connections etc.
Let see an example. Suppose I want to load a file of properties so I will be able to store than modify the lines.

My dumb TDD practice leads me to the following tests methods:

@Test public void newWrapper_ShouldBeEmpty() {
assertThat(new PropertiesWrapper().isEmpty(), is(true));
}

@Test
public void newWrapper_loadedWithTestFile_ShouldNotBeEmpty() throws IOException {
assertThat(new PropertiesWrapper().loaded().isEmpty(), is(not(true)));
}

At the beginning, the wrapper is empty, then I load and the wrapper is not empty anymore.
Using the try-with-resources improvement, this leads to the following code


public final class PropertiesWrapper {
private List list ;
  public PropertiesWrapper() {
super();
list = new LinkedList<>();
}

public boolean isEmpty() {
return list.isEmpty();
}

public PropertiesWrapper loaded() throws IOException {
load();
return this;
}


private void load() throws IOException {
try (final BufferedReader br = new BufferedReader(new FileReader("test.properties"))) {
String line;
while ((line = br.readLine()) != null) {
lines().add(line);
}
}

}

private List lines() {
return list;
}
}

This is it, simple, efficient. No entangled code caught in a finally scope, wrapping itself another un readable try-catch-finally clause. Because now in JDK 7, the BufferedReader implements the Closeable, so the AutoCloseable interface, this special try clause, binds the open/close life cycle of the managed AutoCloseable for it can be closed without nothing to do.

For fun I conceived another test for an imaginary FileCopyCat tool class (by the way un-necessary in JDK7 ). This class copies a file content to a file destination.
The main test looked like

@Test
public void streamCopy_WithExistingFile_ShouldDuplicateFile() throws IOException {
final File source = folder.newFile("sources.properties");
final File copy = new File(folder.getRoot().getAbsolutePath() + "\\copy.properties");
assertThat(copy.exists(), is(not(true)));
new FileCopyCat().streamCopy(source, copy);
assertThat(copy.exists(), is(true));
}

The class content I wrote became:

public final class FileCopyCat {
public FileCopyCat() {
super();
}

void streamCopy(final File source, final File target) throws IOException {
try (final InputStream fis = new FileInputStream(source);
final OutputStream fos = new FileOutputStream(target)) {

byte[] buf = new byte[8192];

int i;
while ((i = fis.read(buf)) != -1) {
fos.write(buf, 0, i);
}
}
}
}


Still no cluttered code, the compiler handles that for you. It seems that this improvement will be included in JDBC 4.1

That's a beginning. I have been working on the NIO.2 and will propose soon you some funny stuff I hope. By the way a tremendous book is being prepared at Manning: The well-grounded Java Developer, targetting the JDK7 and JVM languages. I downloaded the MEAP, sounds promising :)

Be seeing you !!




0 comments:

Post a Comment