1

Why is, in Collection<T>, the method boolean remove(Object o) not defined as boolean remove(T o)?

When I have a Collection<String> list i'm sure that I don't want to do list.remove(new Date()) for instance.

Edit: already solved: Why aren't Java Collections remove methods generic?

Question 2:

When I have a class:

class Value {
   Object getValue() {
   // return something;
   }
}

and then I want to implement a new cool list:

class CoolList<T extends Value> implements Collection<T> {
    // ...

    @Override
    public boolean remove(Object o) {
        try {
           T value = (T) o; // I mean the cast here
               removeInternal(value);
        } catch (ClassCastException e) {
           return false;
        }
    }
}

How can I do a clean cast without producing a warning (unchecked cast) and without using @SuspressWarning, is this even possible?

Edit: Internally I want the list to be able to recover deleted items and because of that I have internally a List<T> deletedItems. So the removeInternal() method appends the item to be deleted to the internal deletedItems list and then deletes it and because of that I need some sort of cast.

Thank you.

Community
  • 1
  • 1
lukstei
  • 844
  • 2
  • 8
  • 20
  • 5
    First question has already been asked: http://stackoverflow.com/questions/104799/why-arent-java-collections-remove-methods-generic – assylias Oct 22 '12 at 22:17

3 Answers3

2

Regarding your second question: just make removeInternal non-generic. It should use the same logic that is described in the answer to your first question: removeInternal(o) removes an object e such that (o==null ? e==null : o.equals(e)) is true. (If you implement logic that is not equivalent to this, you are violating the contract for the Collection interface.) There's no need for a generic removeInternal.

EDIT Here's an example of how one might implement a non-generic removeInternal:

private boolean removeInternal(Object o) {
    for (int i = 0; i < currentSize; ++i) {
        T elt = get(i);
        if (o == null ? elt == null : o.equals(elt)) {
            removeElementAtPosition(i);
            deletedItems.add(elt);
            return true;
        }
        return false;
    }
}

This assumes that removeElementAt(int) will correctly transfer the ith item to deletedItems and adjust the internal count of items. It's important to note that the element that was removed is not necessarily the same object as is passed in the argument; it just the first element that satisfies the equality predicate.

Ted Hopp
  • 232,168
  • 48
  • 399
  • 521
  • Ok thank you for your answer, please read the edit that will clarify my problem. – lukstei Oct 22 '12 at 22:34
  • @lukstei - When you find an object that satisfies the removal condition, you will know that it is of type T, even if the argument to `removeInternal` is declared to be of type `Object`. You shouldn't need a cast at all. – Ted Hopp Oct 22 '12 at 22:37
  • Yes, but I need to cast because I want to add it to the deltedEntries list which is of List – lukstei Oct 22 '12 at 22:53
  • @lukstei - You don't need to cast because the element you are removing is already known to be of type `T`. In particular, there's no requirement that the element you remove is identical to the element passed in the argument; they just have to be `equal()`. See my updated answer. – Ted Hopp Oct 22 '12 at 23:41
0

You can't cast to a generic type T like that. In this case, the most specific known type will be used, in your example Value.

What you could do instead is pass a parameter of type Class<T> in your collection constructor, then cast the value using class.cast(). This won't produce an unchecked cast warning, but is equally unsafe as the code in your example.

Jorn
  • 20,612
  • 18
  • 79
  • 126
0

It's not possible, but you shouldn't do it even if it is, either.

You should remove the item if it equals the other item. There deliberately is no requirement of it being the same type, so you should check if it equals and then remove - irrelevant of which type it is.

eis
  • 51,991
  • 13
  • 150
  • 199