Johannes Thönes

Software-Developer, ThoughtWorker, Permanent Journeyman, Ruby Enthusiast, Java and Devils Advocate.

JDK 7 Features: Project Coin

| Comments

Last recently I did a talk about the some of the new features in JDK7 or Java 7 (Project Coin, Concurrency Utils and InvokeDynamic) at the freshly founded Koblenz Java User Group . I’ll present the content of this presentation in written form in a series of  three or four blog post over the next few weeks or so. In this post I’ll start with the first four features of “Project Coin”.

Project Coin

Project Coin is a project about “small language changes”. Those are changes, mostly inside the compiler, that do improve the productivity of the developers but are small of scope.

The changes by Coin are very easy to grasp if you see them in code, so I’ll demonstrate them to you here.

You can test all the Coin features (as you can test all JDK 7 features) with the developer preview build available from OpenJDK. For Coin you need to use Netbeans 7 Beta, because Coin brings a few syntax changes. Netbeans even shows you, where you could use the new Coin features instead of old style and helps you with the conversion:

]

Integer Literal Enhancements

With Java you could always specify integer values (int or long) using the decimal notation, the octal notation (starting with 0) or the hexadecimal notation (starting 0x). For binaries you could use the Integer.parseInt(…) method. In JDK7 you will be able to specify such values in binary notation as well, if you start your declaration with an 0b. The definition of the decimal number 153 in all four representation can be found below:

1
2
3
4
5
6
7
8
9
int dec = 153;
int hex = 0x99;
int oct = 0231;
int bin = 0b10011001;

Assert.assertEquals(dec, hex);
Assert.assertEquals(hex, oct);
Assert.assertEquals(oct, bin);
Assert.assertEquals(bin, dec);

Besides this, you can now insert an underscore _ into an inger literal. You can use this, to make the literal more readable. The compiler will just ignore it. It  will look like this:

1
2
private long salary = 15_500_000_000L;
private int bitmask = 0b1010_1011;

Switch with Strings

In Java you have a switch satement available to check for the value of a variable and do several different thing in consequence. One of the thing you might do is, to perform an action for “yes”, “no”, “cancel” or “yes to all” according to the input of a user. You can determine what to do, by giving the user the possibilty to enter a char Y,N,C or A according to their wishes. This char can be used in a switch-case statement like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public void perfom(char userInput) {
  userInput = Character.toUpperCase(userInput);
  switch (userInput) {
    case 'Y':
      performYes();
      break;
    case 'N':
      performNo();
      break;
    case 'C':
      performCancel();
      break;
    case 'A':
      performYesToAll();
      break;
    default:
       throw new IllegalArgumentException();
  }
}

If you now want to add a new method “no to all”, you have a problem because there is no obivous char mapping. So you might want to use strings as user input instead. Unfortunalty, if you are using Java 6 or below, you cannot use switch-case with strings. So you have to use if-else statements, which some people consider to be a bit boilerplate:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public void perfom(String userInput) {
  userInput = userInput.toLowerCase(Locale.US);
  if (userInput.equals("YES")) {
    performYes();
  } else if (userInput.equals("NO")) {
    performNo();
  } else if (userInput.equals("CANCEL")) {
    performCancel();
  } else if (userInput.equals("YES TO ALL")) {
    performYesToAll();
  } else if (userInput.equals("NO TO ALL")) {
    performNoToAll();
  } else {
    throw new IllegalArgumentException();
  }
}

With Java 7 you can use switch for strings as well. So the code now can look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public void perfom(String userInput) {
  userInput = userInput.toLowerCase(Locale.US);
  switch (userInput) {
    case "YES":
      performYes();
      break;
    case "NO":
      performNo();
      break;
    case "CANCEL":
       performCancel();
       break;
    case "YES TO ALL":
       performYesToAll();
       break;
    case "NO TO ALL":
      performNoToAll();
      break;
    default:
      throw new IllegalArgumentException();
  }
}

The Diamond Syntax

I studied medical informatics - so I give you an example from the medical domain. You want to have a data structure, were you can find the medications of the patients groupped by the date they received their medication. For this you could come up with something like this:

1
Map>> medications = new HashMap>>();

What you can see is, that there is a very lengthy generic type declaration. But what is more: you have to repeat it. You have to write it inside the Map<…> of the type declation and inside the HashMap<…> of the intialization. You should not specify anything different in the initialization, because it breaks you program.

So why writing it? The good new is: You don’t neet to anymore. You can use the diamond syntax.

1
Map>> medications = new HashMap<>();

These  two angle brackes <> look like a diamond - that’s why it is called diamond syntax. They tell the compiler to copy the generic type from the declaration to the initialization. That’s all ;-)

Improved Var-args Warnings

To know, what this warning really is about, you have to understand what heap pollution means. As did not know this before, so I’ll explain it. If you already know, you can skip all the text and code until the last two code blocks. In Java, Arrays and generic types do not go well together. If you want to create an Array of objects which can be typed generically, you can define the generic type on declaration. But you cannot use it in initiazation:

1
List[] matrix = new List[23];

This can lead to something called Heap Pollution, when you assign an object with an “illegal” generic type to that array. If you try to access the object from the array as the type-signature tells you, you can face a ClassCastException, where you never though you would cast anything.

1
2
3
4
5
6
List[] matrix = new List[23];
List[] nonGenericMatrix = matrix;
// No exception
nonGenericMatrix[0] = Arrays.asList("String1", "String1");
// java.lang.Integer cannot be cast to java.lang.String
List vectorList = matrix[0];

This behaviour is contradictory to the behaviour of a array, without generic types. Here you would receive an ArrayStoreException, when you try to assign an illegally typed object to the array.

1
2
3
4
Integer[] vector = new Integer[3];
Object[] vectorObjects = vector;
// java.lang.ArrayStoreException
vectorObjects[0] = "String";

Heap Pollution becomes really tricky, when it comes to var-args were you pass an object with a generic type. Var-args will be treated by the virtual machine as arrays, so the problem is essentially the same.

What makes it more difficult, is that you might not have implemented the method you call yourself. You call the method and maybe store the result. And then, 10 years later you are using values from the array you once stored and …

1
2
3
4
5
6
7
8
9
10
11
12
public static  L[] createHeapPollution(L... args) {
  Object[] elements = args;
  elements[0] = Arrays.asList(12, 12);

 return args;
}

public static void main(String... args) {
  List[] polluted = createHeapPollution(Arrays.asList("a", "b", "c"));
  // java.lang.Integer cannot be cast to java.lang.String
  String element = polluted[0].get(0);
}

This was the reason, that in Java 6 you got the compiler warning “[unchecked] unchecked generic array creation of type java.util.ArrayList<java.lang.String>[] for varargs parameter” on the method call which used generic typed objects and var-args. This warning confused users of APIs, while the authors of those APIs got no warnings. To avoid this, a new compiler warning “[unchecked] Possible heap pollution from parameterized vararg type L” has been introduced, so the author of the library will get notified about the problem. He also can use the @SafeVars annotation, to promise that his method will not generate heap pollution. In this case the warning will dissapear on the side of the implementer and the caller of the method.

1
2
3
4
5
6
7
8
9
@SafeVarags
public static  L[] createHeapPollution(L... args) {
  return args;
}

public static void main(String... args) {
  List[] unpolluted = createNoHeapPollution(Arrays.asList("a", "b", "c"));
  String element = unpolluted[0].get(0);
}

What is comes next?

There are two addtitional features Project Coin introduces. They will be described in the next post on the JDK 7 subject. Stay tuned …

Comments