Generics in Java 5 Explained - Java
Home » Java, Tech Notes

Generics in Java 5 Explained

2 July 2009 4 Comments

Generics, is an important feature introduced in Java 5. Java introduced many other features, but this is the only feature which adds flexibility to strongly type data types. In this article, we try to find answers to these questions: Why do we need this feature? What is this feature? What are different scenarios in usage of Generics? When can we not use Generics? Wherever applicable we take a code example and understand the concept better. Reader of this article should already know the concepts of Java version prior to this release.

What are Generics?

There is little in the name generics, and so is the case with generics. This concept already exists in other languages like C++. Let us take a simple example of collection and understand generics. This is how we would have written code without generics.

import java.util.HashMap;
import java.util.Map;

public class WithoutGenericsExample {

	public static void main(String[] args) {
		Map data = new HashMap();
		data.put("Key1", new Integer(100));
		System.out.println((Integer)data.get("Key1"));
	}
}

Take a closer look at the last line involving casting of object pulled out of the HashMap. There is no restriction from Map or HashMap on what type of object we add to this collection. The only requirement is – it should be an object i.e. we cannot add primitive to the collection unless it is wrapped in its respective object. Can you visualize problem with above approach?

User of the data from collection is expecting that the data should be of type Integer, but the creator of data is not having any such restriction. If the data added is of type other than Integer then there will be a ClassCastException. E.g. instead of Integer you add String to the collection, and end up in ClassCastException when you try to call any method of Integer. When do you come to know about this problem? It is at runtime, which is not correct. The solution is – use of generics. Let us change above code to use generics.

import java.util.HashMap;
import java.util.Map;

public class GenericsExample {

	public static void main(String[] args) {
		Map<String, Integer> data = new HashMap<String, Integer>();
		data.put("Key1", new Integer(100));
		System.out.println(data.get("Key1"));
	}
}

In this code, we are fixing the problem we sited in first code snippet. While declaring and instantiating the collections, by using this new feature called generics, we are restricting the kind of objects we can add to the collection. This collection will allow only Strings as key and Integer as value. As we have restricted to add only Integer values to the collection, we can be confident of getting the values in return of data type Integer only.

Let us see how does this work? This is compile time business. Once we declare that the collection is going to contain certain type of data, then compiler restricts all operations on the collection to this data type only. If at all you try to add any other type of data then there is compile time error. This means that the compiled code is generated using the generics only.

Mind you, Java 5 does not restrict you to use generics whenever you use collections. If you are not using generics where it should be, then Java compiler will generate a warning message, that’s it. You can definitely get rid of these warning messages by suppressing warnings.

Scenarios to Consider:

What we have seen is a simple example, where we restricted the collection to contain certain type of values only. Practical scenarios are going to be more complex than this. There will be many combinations which you will have to consider. In following discussion, we take most important scenarios and see how we can improve our Java code using generics.

Wild Cards:

Here you don’t know the type of data you are going to deal with. Use ‘?’ in this scenario.

Map<?, Integer> data = new HashMap<?, Integer>();

This allows you to add object key of any type. As you are giving freedom to add any value to the collection, you also need to be careful while retrieving this value, otherwise you might end up in ClassCastException again.

Bounded Wild Cards:

In wild cards, there is complete freedom to add any object type. In this scenario, we add partial restriction. Let us see how. We have following hierarchy of classes, and we don’t know which type of object will actually go in the collection above. But we definitely know that it will be of base type Vehicle.

genericshierarchy

This is how  generics can be used to add the restriction of having only objects of base type Vehicle.

Map<String,? extends Vehicle> data = new HashMap<String,? extends Vehicle>();
data.put("Key1", new Car());

Subtypes:

We continue with the Vehicle example above. Suppose there is another class which calls to get Cars from above class. The method will return List<Car>. Instead of this we have an option to use more abstract type i.e. List<Vehicle> to return, but there is a possibility of a problem here. If we are returning List<Vehicle> when the caller actually needs only Cars, then we are adding weak restriction when the expected one is strong. This might break the caller program by returning a Vehicle which is not a Car.

Hence while using generics in hierarchies; the restriction should be defined considering all aspects of current as well as the user programs.

Generic Methods:

Let the method definition itself identify what kind of parameters it is going to handle. Let us take an example first.

	public<String, Integer> void getData(Map<String, Integer> inputData, List<String> conditions){
		//some operations
	}

In this method, the collections are dealing with object types String and Integer. Now when we use generics at method level, we add <String, Integer> after the access modifier to restrict any other parameter input to this method.

Generic Classes:

In this scenario, we take the generic method concept to a level up, i.e. at class level. In this case the class itself will have the types it is going to deal defined in its declaration. Here is an example where the GenericExample type is declared along with the class definition and used inside the class.

public class GenericClass<GenericExample> {

	private String name;
	private GenericExample ge;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public GenericExample getGe() {
		return ge;
	}

	public void setGe(GenericExample ge) {
		this.ge = ge;
	}

}

Limitations:

In this section we will try to find out some of the limitations in use of generics.

  • By this time you must have understood the possible applicability of generics. Generics are used mainly when one object contains other object. It may be a simple class or a collection. You can add restriction on what can be added to other class. It is not possible to add such a restriction in other ways of reusing e.g. inheritance.
  • Generics work on objects and not on primitive data types.
  • When the instances of certain declared classes are injected using Dependency Injection (say using Spring), then you can have partial usage of generics i.e. only the declarations will be made using generics, but actual instantiation depends on if the injection supports generics.
  • Generics reduce the polymorphic nature of code. At compile time only, we finalize the concrete data types to be dealt with, this leaves little opportunity for runtime alteration.

Wrong Use of Generics:

When we define generics, we use Object as a data type where we are not sure about the actual type.

Map<String, Object> data = new HashMap<String, Object>();

We are not doing any value add by defining the generic as Object (You must be remembering that Object class is the Super parent class).

Previous Next

 

More Related Posts in Java, Tech Notes

4 Comments »

  • Veera said:

    there is an advantage in using Generics. The code for type casting is avoided if we use Generics.

    i.e.
    List myList = new ArrayList();
    while(myList.iterator().hasNext()){
    String temp = myList.iterator().next();
    }

    the list value can be directly applied to temp, without type casting it to String, because of the Generics.

  • opensas said:

    mmmm… I’m kind of newbie to this stuff, but I think that in the second case you forgot the use of generics… just ommited the cast… methinks….

  • admin said:

    Thanks, some problem had removed stuff in angular braces. It is corrected now.

  • Shaheen said:

    I think this i a good tutorial for Generics in java– It is really helpful– but could you please explain it in more elaborate terms

Leave your response!

Add your comment below, or trackback from your own site. You can also subscribe to these comments via RSS.

Be nice. Keep it clean. Stay on topic. No spam.

You can use these tags:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

This is a Gravatar-enabled weblog. To get your own globally-recognized-avatar, please register at Gravatar.