Saturday, November 1, 2008

Java 5.0 Generics

Generics:

JDK 1.5 introduces several extensions to the Java programming language.
One of these is the introduction of generics. Generics allow you to abstract over types.The most common examples are container types, such as those in the Collection hierarchy.

The feature of Generics in Java allows Applications to create classes and objects that can operate on any defined types. Programmers can now make use of the Generics feature for a much better code. There is no need for un-necessary casting when dealing with Objects in a Collection.

Generics programming enables Classes and Methods to operate on well defined parametric types allowing clients to substitute a suitable Java type at the compile time. This prevents un-necessary casting being done in the Application code and to prevent any wrong data-type being used. To make things clear, consider the following statements.

Map contacts = new HashMap();
contacts.put(new Long(9912345678L), "Jenny");
contacts.put(new Long(9912345679L), "Johny");

Set contactValues = contacts.entrySet();
Iterator contactIterator = contactValues.iterator();

while (contactIterator.hasNext())
{
Map.Entry anEntry = (Map.Entry)contactIterator.next(); // Line A
Long number = (Long)anEntry.getKey(); // Line B
String name = (String)anEntry.getValue(); // Line C
System.out.println(number + ":" + name);
}

The above code populates a Map, keyed with mobile phone for a person name. The next pieces of code try to iterate over the Map, thereby printing the data within it. Look at the casts down at lines A, B and C. Even though we know that we are going to add phone numbers (which is of type Long) and a person name (probably a String) into the Map, we are doing an explicit cast to get the appropriate data. The other problem we find here is, what if the client put some other data other than the Long data-type for the Key.

contacts.put(new String("9912345678L"), "Jenny");

The above code will definitely raise an exception at the run-time. So, we find two major dis-advantages in the older code (code compiled with java 1.4 compiler or before). One is the need to have absurd cast that is being spread across the code. The other thing is that there is no procedural mechanism through which we can prevent wrong data-type being added to the above Collection.

The solution to the above problems is having Generics in the programming code. Let us see how the above code is re-written using Generics.

Map<Long, String> contacts = new HashMap<Long, String>();
contacts.put(new Long(9912345678L), "Jenny");
contacts.put(new Long(9912345679L), "Johny");

Set<Map.Entry<Long, String>> contactValues = contacts.entrySet();
Iterator<Map.Entry<Long, String>> contactIterator = contactValues.iterator();

while (contactIterator.hasNext())
{
Map.Entry<Long, String> anEntry = contactIterator.next();
Long number = anEntry.getKey();
String name = anEntry.getValue();
System.out.println(number + ":" + name);
}

Let us analyze what has happened in the above code. The declaration Map contacts = new HashMap(); has now changed to Map<Long, String> contacts = new HashMap<Long, String>();

The former is called a Raw Map and the latter is an example of a Generic Map. If we look at the declaration of the Map and the HashMap classes, we will find something similar to the following,

public interface Map<K,V> { ... }

The above declaration can be interpreted as : Map has two parametric types called K (meaning Key) and V (meaning Value). The name of the parametric types can be anything, that doesn't matter. These changes to Map and all its related collection classes is there right from Java 5.0. So, whenever a clients references a Map interface, it cannot plainly do like the following,

Map mapObject = new HashMap();

The compiler (Java 5.0) as soon as encountering this statement will issue a warning telling that, the declaration of Map is a raw-type and its references should be parameterized. Since the declaration of the Map interface is now parameterized with Keys and Values in the form of <K, V>, the client referencing the Map should provide a suitable type for the parametric types. Going back to our code,

Map<Long, String> contacts = new HashMap<Long, String>();

We want the key for the Map to be of type Long and the value for the corresponding Key to be of type String. We also have parameterized the HashMap class with Long and String, since the class declaration for HashMap has also changed.

public class HashMap<K,V> implements Map<K,V> { … }

The usage of parametric types has not only affected Map and HashMap but all the collection related classes and interfaces in the java.util package. In our code, contacts are made to populate in the map object by calling the Map.put() method. Now, the call to Map.entrySet() will return a Set containing entries which is of type Map.Entry. Now let us have a look over the Map.entrySet() method,

Set<Map.Entry<K, V>> entrySet();

The return type of Map.entrySet() is a Set which is parameterized with Map.Entry. Map.Entry is a class that will store an entry, which is nothing but a combination of Key and value. Note that Map.Entry is again parameterized with K (for Key) and V (for Value). In our case, the key is of type Long and the value is of type String, we have something like the following in the later part of the code,

Set<Map.Entry<Long, String>> contactValues = contacts.entrySet();

The same thing applies for Iterator which is parameterized with Map.Entry which is again parameterized with Long and String. While traversing over the elements within the while loop, we have statements like the following,

...
Map.Entry<Long, String> anEntry = contactIterator.next();
Long number = anEntry.getKey();
String name = anEntry.getValue();
...

Since we well know that the Iterator is typed with Map.Entry<Long, String>, there is no need for an explicit type-cast. Same is the case for Map.getKey() and Map.getValue(). Since the Map has been parameterized with Long and String, it is not possible to add types other than the defined types. So now the following code will raise a compilation error.

contacts.put(new String(""), new Long(1L));

This ensures type-safe programming and it prevents the client code from adding any wrong data-type to the Collection.

0 comments:

Blog Widget by LinkWithin

JS-Kit Comments

  © Blogger template Newspaper III by Ourblogtemplates.com 2008

Back to TOP