As
code re-usability is an important characteristic of any object-oriented
language. For example,class inheritance provides re-usability of a
class. J2SE 5.0 takes re-usability to the next level by introducing a
very powerful feature called generic programming, which enables you to
write code that can be reused for different types of objects.
In this post I am going to explore generic programming from the perspective of collections.
Generic Collections
When
you retrieve an element from a collection, you need to cast it to the
right type. If you make a type mistake in casting, the compiler will not
catch it, but you will get a runtime error. It is desired that the
errors be caught during compilation and not when the application is
running. The solution to this problem is provided by the generic
collections introduced in J2SE 5.0, which provide a way for you to
declare the type of a collection so that the compiler can check it. You
can still use the non-generic collections and they will work. However,
using generic collections is less error prone.
For example, consider the following code snippet:
ArrayList myList = new ArrayList();
String st = "Flemingo";
myList.add(st);
String st1 = (String) myList.get(0);
System.out.println(st1);
This is perfectly fine code for non-generic collections and will compile and run even in J2SE 5.0 and generate the following output:
Flemingo
However, it will generate a compiler error if you replace line 4 with the following line:
String st1 = myList.get(0);
That means the compiler requires you to cast to a type. However, it has no way of ensuring that you are casting to a correct type, as long as you are casting to an object. For example, the code will compile without an error if you replace line 4 with the following line:
Of course, you will get an exception at runtime. We can rewrite the same code fragment in generic collections as shown here:
ArrayList<String> myList = new
ArrayList()<String>;
String st = "Flemingo";
myList.add(st);
String st1 = myList.get(0);
System.out.println(st1);
Note
that line 4 does not have any explicit casting. However, it will still
accept the correct cast, but it’s not required. Unlike the non-generic
collections, here the compiler will not let you cast incorrectly. For
example, you will receive a compiler error if you replace line 4 with
the following line:
Integer st1 = (Integer) myList.get(0);
This
has become possible due to line 1, where you have declared the type of
the myList collection elements as String. You could have declared any
object reference type. It’s important that you get used to the angle
bracket notation: when you see something like <E>, read it as of
type E. The overall result of using generics, especially in large
applications, is improved readability, robustness, and reliability.
Below code snippet presents a complete code example to demonstrate the
use of generic collections using ArrayList. Of course, the same
principles apply to any Collection implementation.
public static void main(String[] args)
{
ArrayList<String>
myList = new ArrayList<String>();
String
st1 = "ready";
String
st2 = "set";
String
st3 = "go";
myList.add(st1);
myList.add(st2);
myList.add(st3);
String
st;
Iterator<String>
itr = myList.iterator();
while (itr.hasNext()) {
st
= itr.next();
System.out.println(st);
}
}
The output of Code Snippet is:
ready
set
go
set
go
Note
that the iterator in line 12 has been declared of type String. This is
essential, because otherwise the compiler will generate an error.
Generic programming goes beyond just collections and has a more general dimension to it: instead of specifying a type in a class or in a method, you can just say some type in a generic way, and then specify it at a later time.
Reference(s): SCJP Exam for J2SE 5
No comments:
Post a Comment