2

The api says "Returns a dynamically typesafe view of the specified collection" but still what is the need for it when generics can detect at compile time if anything suspicious is being inserted into a collection.

the doc says "The generics mechanism in the language provides compile-time (static) type checking, but it is possible to defeat this mechanism with unchecked casts"

but even this won't work

List<Integer> list = new ArrayList<Integer>();
Object o = new Float(1.2);
Integer i = (Integer)o; // line3
list.add(i);

but even this one wud fail at run time with a ClassCastException being thrown at line3 because o actually holds a Float , can't convert it to Integer . So , I am wondering how would one even go around static compile-time generic checking to justify the existence of checkedList method

Sarabjeet
  • 264
  • 2
  • 17
  • 1
    *"[…] it is possible to defeat this mechanism with **unchecked** casts."* My emphasis in bold. `(Integer)o` is a **checked** cast. – Radiodef Apr 03 '15 at 05:05

2 Answers2

7

This can be done by not using generics, which could be done if you use a library that was built with a version of Java that doesn't have generics.

The following code is an example of how to do this with generics:

List<Integer> list = new ArrayList<Integer>();
List unsafeList = list; // Cast to a list that is not using generics
Object o = new Float(1.2);
unsafeList.add(o);
// list now contains a non Integer object.

This does generate several warnings, but you can of course ignore those if you want.

Thirler
  • 20,239
  • 14
  • 63
  • 92
  • Hi, I have one more question if you could please answer, its unrelated to this one, but I am asking here to spare one new post for a minor query `ArrayList.containsAll( list)` is returning me false even though the 2 lists contain the same number of and meaningfully equivalent objects (i.e `equals()` method returns true ) I have tested this on a one-to-one object basis in the list. but when I do collectively using `containsAll()` method it returns me false. – Sarabjeet Apr 01 '15 at 11:48
  • I think you should ask a separate question for this, with a clear reproduction of the steps in them. All I can think of is a bug in the equals implementation where a.equals(b) != b.equals(a). (or possible a bug in another part of your code). – Thirler Apr 01 '15 at 12:03
  • hi I have posted [here](http://stackoverflow.com/questions/29390340/contains-method-in-list-not-working-as-expected) – Sarabjeet Apr 01 '15 at 12:05
0

You're right, the method doesn't make sens when using a checked type list (generics) and it's ridiculous trying to add a Float when you know your list expects an int.

When the documentation says "it is possible to defeat this mechanism with unchecked casts.", it doesn't deal with your obvious not permitted cast. It deals with that code :

List list = new ArrayList<>();
Integer i = 3;
Object o = new Float(1.2);
Float f = new Float(2.1);
list.add(i); // warning
list.add(o); // warning
list.add(f); // warning
// list contains [3, 1.2, 2.1]

Then, it says "Usually this is not a problem, as the compiler issues warnings on all such unchecked operations.", that's why your IDE issues warnings. It's legal, it works but has no sens.

Finally, documentation says that "...type checking alone is not sufficient. For example, suppose a collection is passed to a third-party library..." because you can use a type checked collection (to guarantee the type on your side) and pass it to a library that accepts unchecked one. Bad things happens here, the library can do the legal and working bad code we have seen :

public class Library {
  public void addNumbers(List list) { // unchecked type
    list.add("5");
    list.add(Duration.ofMinutes(6));
  }
}

public static void main( String[] args ) {
    Library library = new Library();
    List<Integer> list = new ArrayList<>(); // checked type
    Integer i1 = 3;
    Integer i2 = 4;
    list.add(i1);
    list.add(i2);
    library.addNumbers(list);
    // list contains [3, 4, 5, PT6M]
}

To avoid a third-party adding wrong type values, you must pass it an uncheckedList...

public class Library {
  public void addNumbers(List list) {
    list.add("5");
    list.add(Duration.ofMinutes(6));
  }
}
public static void main( String[] args ) {
    Library library = new Library();
    List<Integer> list = new ArrayList<>();
    Integer i1 = 3;
    Integer i2 = 4;
    list.add(i1);
    list.add(i2);
    List<Integer> checkedList = Collections.checkedList(list, Integer.class);
    library.addNumbers(checkedList); // ClassCastException
}

Notice that if you add value to the checkedList, your initial list will be populated...

Zrop
  • 11
  • 3