import java.util.ArrayList;
import java.util.Collection;
public class UnsafeCollectionOperation {
public static void unsafeAdd(Collection c) {
c.add(new Integer(1));
}
public static void main(String[] args) {
Collection<String> c = new ArrayList<String>();
c.add("One");
c.add("Two");
unsafeAdd(c);
for (String s: c) {
System.out.println(s);
}
}
}
Here is what happens at runtime:
One
Two
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer
at UnsafeCollectionOperation.main(UnsafeCollectionOperation.java:17)
As you see from the exception above, the runtime exception does not offer any information on where exactly the unsafe type was added. My code is so small, so we can easily deduce where we went wrong, but when we deal with a lot of code, this task becomes very cumbersome. One way to deal with this problem is to use checked collection(see java.util.Collections). Checked collections are dynamically type safe views of collections. They perform a runtime type check every time an element is inserted into the collection. Any attempt to insert a wrong type will immediately result in ClassCastException. So we know exactly where we went wrong. Here is an example:
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
public class CheckedCollection {
public static void safeAdd(Collection c) {
c.add("three");
}
public static void unsafeAdd(Collection c) {
c.add(new Integer(1));
}
public static void main(String[] args) {
Collection<String> c = new ArrayList<String>();
c.add("One");
c.add("Two");
Collection<String> checkedCollection =
Collections.checkedCollection(c, String.class);
safeAdd(checkedCollection);
unsafeAdd(checkedCollection);
for (String s: checkedCollection) {
System.out.println(s);
}
}
}
Running the program produces:
Exception in thread "main" java.lang.ClassCastException: Attempt to insert class java.lang.Integer element into collection with element type class java.lang.String
at java.util.Collections$CheckedCollection.typeCheck(Collections.java:2206)
at java.util.Collections$CheckedCollection.add(Collections.java:2247)
at CheckedCollection.unSafeAdd(CheckedCollection.java:14)
at CheckedCollection.main(CheckedCollection.java:23)
From the exception above we know exactly where we went wrong.
Couple of note worthy points are:
- When a checked collection view is created using an existing collection, it will NOT discover incorrectly typed elements, if they already exist in the collection prior to creating the view.
- After creating the checked collection view, if any access happens through the original collection and not through the checked collection, it cannot ensure type safety.
- There is a performance overhead of a runtime type check every time an element is inserted into the collection.
No comments:
Post a Comment