Java offers checked versions of the collection classes List,
Set
and Map
. Both normal and checked collections provide type checking, but checked collections just make it easier to spot a type-error when it occurs. Let’s see the difference.
A checked list can be obtained from a factory method exposed by the Collections
class.
public static <E> List<E> checkedList(List<E> list, Class<E> type)
The method expects a list object and a type token and returns the checked list. The type token should be the same class as the parameter type declared by the list.
According to the documentation, a checked list is a “dynamically typeset view over the specified list”. We also learn that:
To illustrate the point, let’s define a method that can add “pears” to “apples”. We can pretend the method is from a third-party library written before the introduction of generics (in JDK5).
@SuppressWarnings("unchecked") void unsafeAdd(Collection c, Object e) { c.add(e); }
The author used a raw type java.util.Collection
and annotated the method with @SuppressWarning
to silence the compiler.
For the sake of the argument, let’s also examine a type-safe version of the same method.
// add element to collection in a generic fashion <T> void add(Collection<T> c, T e) { c.add(e); }
If we try to call the add()
method in a way that violates type guarantees, our code doesn’t even compile. On the other hand, with the unsafe method we get no such warning.
Now let’s see what happens when we attempt to pass an normal/unchecked list to the unsafeAdd
method.
List<Integer> list = Arrays.asList(1, 2, 3); unsafeAdd(list, "4");
Here’s the stack trace:
Exception java.lang.UnsupportedOperationException at AbstractList.add (AbstractList.java:153)
The UnsupportedOperationException
is a generic error thrown by the parent class which that doesn’t really point to the actual problem. Had we performed many different operations on the list (i.e. in the same method scope), it would have been unclear which one caused the error.
Now let’s pass a checked list to the unsafeAdd
method.
List<Integer> ckList = Collections.checkedList(list, Integer.class); unsafeAdd(ckList, "5");
Now we get another error – a better one. Here’s the stack trace:
Exception java.lang.ClassCastException: Attempt to insert class java.lang.String element into collection with element type class java.lang.Integer | at Collections$CheckedCollection.typeCheck (Collections.java:3047)
The ClassCastException
correctly identifies the problem and has a nice, helpful message.
Conclusion
While both checked and unchecked lists prevent type violations, checked list operations fail immediately, with a clear, appropriate exception that is useful for debugging.