Generic is very powerful tools, it allows us to get errors that usually only happen in runtime to compile time like the usual type error.
Generic is also very tempting and in normal case, is very easy to use in daily programming. But without a good thinking, we normally will lose the actual power of generic. Let’s we start with this bad news.
The last article I referred on article Java Tips: Iterate and cast is one example where we wrote a Java code using generic but not optimally. The code is as follow:
@SuppressWarnings("unchecked") public static <X> X cast(Object o) {
return (X) o;
}
What’s wrong with that? PPOW show the wrong cases to us.
Number telephoneNumber = cast("1234567");
session.setAttribute("digits", setOfDigits);
List<Character> characters = cast(session.getAttribute("digits"));
String authorName = cast(session.getAttribute("authorId"));
The errors that we usually get in compile time are missed and can only be get in runtime.
How to make it correct? It is actually pretty simple if we think it through. The essence of casting is to specify that certain superclass that we have is actually a subclass. This relationship is important. Knowing that we know that the argument of the method should be superclass of the result, and not an arbitrary object. So we can fix our method cast like following.
@SuppressWarnings("unchecked") public static <T, X extends T> X cast(T o) {
return (X) o;
}
And now try all the cases PPOW suggested and we will get an error in compile time. That’s good!
The last case PPOW suggested in the article is not really valid because even using a not tricky techniques, the error will only be happen in runtime. These codes compile correctly but all have problem in runtime.
Using original code:
// Because of an error we cast it to a map of String to String
Map<String, String> badMap = cast(session.getAttribute("map"));
// we pass the map between many objects and doing many operations on it
String s1 = badMap.get(1);
badMap.put("2", "2");
String s2 = badMap.get("2");
String s3 = badMap.get(2);
String s4 = badMap.get(123);
Using modified code:
// Because of an error we cast it to a map of String to String
Map<String, String> badMap2 = cast2(session.getAttribute("map"));
// we pass the map between many objects and doing many operations on it
String s1a = badMap.get(1);
badMap.put("2", "2");
String s2a = badMap.get("2");
String s3a = badMap.get(2);
String s4a = badMap.get(123);
Using normal cast:
// Because of an error we cast it to a map of String to String
Map<String, String> badMap3 = (Map<String, String>)(session.getAttribute("map"));
// we pass the map between many objects and doing many operations on it
String s1b = badMap.get(1);
badMap.put("2", "2");
String s2b = badMap.get("2");
String s3b = badMap.get(2);
String s4b = badMap.get(123);
As you can see, generic is easy to implement, but to implement it correctly is not that easy. I really suggest to read the white print of generic which honestly, I still don’t understand the whole of it. The latest edition of Effective Java also has some tips to work with generic.
Learn generic, it is worth it!

