Aharon K
Aharon K

Reputation: 324

Check the Type of an entire Collection in Java

I am writing a method removeAll for an ArrayList. By the interface, removeAll takes a Collection<?>, however, for whatever reason, I want the Collection to be of only Strings. Is there any way to do this for the entire Collection at once?

(I am not talking about going through each element individually, like this:

for (Object el : c) {
    if (!(el instanceof String)) {
        throw new ClassCastException(String.format("Object %s is not of type String.", el.toString()));
    }
}

That is my backup, but I'd rather check the entire Collection at once if it's possible.)

I did try:

public boolean removeAll(Collection<?> c) {
    return subMethod((Collection<? extends String>) c, true); //true is unimportant here
}

but that just casts any Collection<Wrapper of Primitive> to a Collection<String>.

Edit: To be clear, I would like some other way to ensure the Collection only contains Strings.

Upvotes: 4

Views: 534

Answers (2)

wannaBeDev
wannaBeDev

Reputation: 739

May be something like:

boolean b = c.stream().allMatch(String.class::isInstance);
if(b){
      //
 }

Upvotes: 0

StriplingWarrior
StriplingWarrior

Reputation: 156469

No, there's no way to do this.

Java implements generics via erasure, so the Collection<> itself has no idea of what its type argument was when it was created.

The concept of a generic type being on the Collection only exists when the code is being compiled, and by implementing List.removeAll() you are tied to the specific signature provided by that method, which does not include the ? extends E specification that some methods like addAll() provide.

Further, the interface documentation for List.removeAll() explicitly says (emphasis added):

Throws:
ClassCastException - if the class of an element of this list is incompatible with the specified collection (optional)

So to fulfill the contract of this interface, you're expected to only throw an exception if an element in your own list is incompatible with your specific collection type: you should not throw an exception just because an item in the passed-in argument is incompatible. That's why the method signature doesn't include a <? extends E> in the first place: you're supposed to allow other types to be provided in the collection, and ignore them because they're clearly not going to match any values in your List.

If you want to ensure that the given collection only includes strings, one option would be to not implement the List interface. That has obvious draw-backs, but if your implementation is special it might be worthwhile for the consumers of your implementation to acknowledge that they're using a special class with special requirements, and it can't be handed to methods that only know what to do with a generalized List. If you do that, you've got a lot more flexibility, including declaring removeAll() as taking a Collection<String> or even a more specific, specialized, non-generic collection type that is guaranteed to only have Strings in it.

Upvotes: 2

Related Questions