Search code examples
javagenericseffective-java

collection of date using generics


I am reading about Generics in Effective Java item 23. It is mentioned as below:

While the prospect of accidentally inserting a coin into a stamp collection may appear far-fetched, the problem is real. For example, it is easy to imagine someone putting a java.util.Date instance into a collection that is supposed to contain only java.sql.Date instances.

I am not able to understand what does author mean by "it is easy to imagine someone putting a java.util.Date instance into a collection that is supposed to contain only java.sql.Date instances"?

Collection<java.util.Date> dateColl = new ArrayList();
String strDate = "2011-12-31 00:00:00";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd hh:mm:ss");
java.util.Date date = sdf.parse(strDate);
java.sql.Date sqlDate = new Date(date.getTime());

dateColl.add(sqlDate);

Why above code is not throwing compilation error?


Solution

  • I am not able to understand what does author mean by "it is easy to imagine someone putting a java.util.Date instance into a collection that is supposed to contain only java.sql.Date instances"?

    In your example :

    Collection<java.util.Date> dateColl = new ArrayList();
    java.util.Date date = sdf.parse(strDate);
    ...
    dateColl.add(date);
    

    you do the reverse. You declare a Collection of java.util.Date. And besides you have added a java.util.Date instance in the collection of java.util.Date instance. You never use the java.sql.Date instance you declare and of course adding a java.util.Date instance in a collection of java.util.Date doesn't require any cast and doesn't question about type compatibility.

    In a OOP point of view : a java.sql.Date IS a java.util.Date type. So, it is legal :

    Collection<java.util.Date> dateColl = new ArrayList();
    dateColl.add(new java.sql.Date(...));
    

    To understand the problem, you should declare :

    Collection<java.sql.Date> dateColl = new ArrayList();
    

    and then try to add a java.util.Date instance. There, you will have a compilation problem since "you are putting a java.util.Date instance into a collection that is supposed to contain only java.sql.Date instances".

    Without using generics in Collection classes, the compilation will not fail and therefore at the runtime, you may have ClassCastException if you expect to have a collection which contains only java.sql.Date instances :

    Here, you will have a ClassCastException in the loop since you could not cast the java.util.Date instance to a java.sql.Date instance :

    Collection mySqlDates = new ArrayList();
    mySqlDates.add(new java.sql.Date(...));
    mySqlDates.add(new java.util.Date(...));
    
    for (Object object : mySqlDates) {
        java.sql.Date sqlDate = (java.sql.Date) object; 
    }