views:

284

answers:

4

I'm working on a List implementation. Because of this, I'll have to override the methods

Collection.containsAll(Collection<?> c);
Collection.removeAll(Collection<?> c);
Collection.retainAll(Collection<?> c);

But as it's explained by Sun, they accept collections with any kind of content (note the <?>). So the collection is not checked by the compiler and it's up to me, to check it. But how to do it? instanceof on each element won't work because of type erasure. The next solution would be to cast each element an catch the ClassCastException. Look here:

public boolean containsAll( Collection<?> c ) {
    boolean foundAll = true;
    for ( Object element : c ) {
     try {
      foundAll &= this.contains( (T) element );
     } catch ( ClassCastException e ) {
      foundAll = false;
     }
    }
    return foundAll;
}

The other two methods look similar. That works. But it gives me compiler warning "warning: [unchecked] unchecked cast"! Unless I suppress it with "@SuppressWarnings("unchecked")", it won't compile fine.

I don't want to rely on "@SuppressWarnings("unchecked")" unless I really have to. Is there a way to avoid it? How would you implement those methods like containsAll(Collection<?> c)?

edit

Ok, sorry guys, I was not clear enough. I don't extend AbstractList, and I don't want to. My list is implemented by a balanced binary tree. I have an own implementation of insert(), remove(), contains() (that actually does a search for the leaf), etc, and all take an argument of (generic) type T. The key goal is to have a sorted list that can be modified while it's iterated through.

So... how do I avoid the warning in containsAll(Collection <?>)? I have to cast!

Thanks! craesh

+9  A: 

You don't need to cast your element to T when you call contains() since it is defined as boolean contains(Object o). Note that you can ask a Collection<String> if it contains() an Integer object. There's no casting necessary.

remove() takes an Object as well, so no casting should be necessary at all.

And by the way: extending AbstractList takes away most of the boring work of implementing a List.

Joachim Sauer
+1 for the hint on AbstractList, I tend to forget that one
Abel
Sorry, my fault: I simplified the example a bit too much. In this case the element would get casted in contains(). I have a method contains(T element), I call this one but didn't post it.
craesh
@craesh: it's fine that you provide those as well, but if you implement the `List` interface, then you can simply call the non-generic versons of those methods.
Joachim Sauer
+2  A: 

Just to clear up a misconception on generics:

instanceof on each element won't work because of type erasure.

No, that is not correct. instanceof will work just fine. "Type erasure" just means that you cannot get at the compile time type that was declared via generics for the collection you are getting - but you don't care about that anyway.

What you want to check is the run time type of the element you are getting. This is done via instanceof, is completely independent of generics, and will work.

Of course, as Joachim Sauer points out, you don't even need to check the type in this specific case, so the point is moot anyway...

Edit:

As a matter of fact, Java's AbstractCollection does it just like that:

public boolean containsAll(Collection<?> c) {
    Iterator<?> e = c.iterator();
    while (e.hasNext())
    if(!contains(e.next()))
        return false;
    return true;
}

(from the Sun JDK sources).

So you should really try to inherit from AbstractList or at least AbstractCollections

sleske
A: 

of course you can extends AbstractList in order to get these methods for free but you can also iterate this, instead of c:

@Override
public boolean containsAll(Collection<?> c) {
    Iterator<T> it = this.iterator();

    while (it.hasNext()) {
        if (!c.contains(it.next())) {
            return false;
        }
    }

    return true;
}

or simply:

@Override
public boolean containsAll(Collection<?> c) {
    for (Object o : this) {
        if (!c.contains(o)) {
            return false;
        }
    }

    return true;
}
dfa
Thanks, but in my case, that's no option. My list may contain up to 10k elements in my application. I have a binary search, so it's faster to search in my list than iterate though it.
craesh
A: 

If you don't want to extend AbstractList, at least extend AbstractCollection. Then you don't have to implement this method at all and the question is moot.

Kevin Bourrillion