Returning Collection<? extends Type> vs Collection<Type>
Asked Answered
K

3

5

What is the difference between these two methods?

Collection<Type> getTypes();

vs

Collection<? extends Type> getTypes();

Does it matter if Type is a class or an interface? Especially, when designing an API, which version would be preferred and why?

Kalfas answered 22/8, 2013 at 14:2 Comment(1)
One important thing to note here: Collection<Type> is not the same as Collection<SubType> where SubType extends Type.Pilfer
D
8
Collection<Type> getTypes();

Here, getTypes() must return a Collection<Type> (e.g. ArrayList<Type> or HashSet<Type>).

Collection<? extends Type> getTypes();

Here, getTypes() can return a Collection of anything that is or extends Type, (e.g. ArrayList<SubType> or HashSet<SubType>). So anything that can be returned from the first variant can also be returned from the second. In the second, however, you don't know what the type parameter of the collection actually is; you just know that it extends Type.

As for which should be preferred, it really depends on what you're trying to do, and what makes more sense logically. Bear in mind that when you have <? extends Type>, you don't actually know what ? is, and this can be hindering at times; more often than not the first variant is more suitable. You can use the second variant in a base class and override it in subclasses with something that is more akin to the first, for instance:

@Override
Collection<SubType> getTypes() {
    ...
}
Discounter answered 22/8, 2013 at 14:8 Comment(8)
Does this mean that the returned Collection<? extends Type> effectively becomes read-only? How would the client otherwise add to the collection?Kalfas
@Kalfas Right, you can't safely add anything to a Collection<? extends Type> because you don't know what the type parameter actually is.Discounter
"can return a Collection of anything that is or extends Type". Wrong! Collection<? extends Type> cannot contain objects of type Type. It has to be a subtype. Collection<? extends Type> can contain both. This is what I would see as one of the main differences between the two.Person
@stonedsquirrel A method with return type Collection<? extends Type> can return a Collection<Type>.Discounter
@Discounter Of course. Interpreted your sentence wrong. Sorry! Still the statement from my comment (after falsely telling your wrong) stays true ;-)Person
Not quite read only, as the clear() method still works and some iterators can delete().Scrimp
@stonedsquirrel: Your comment makes no sense. You say Collection<? extends Type> cannot contain objects of type Type, then you say it can.Fluke
@LouisWasserman Again: my bad! The second one was intended to be ´Collection<Type>´. Thanks for noticing. Must have been a little inattentive yesterday...Person
M
3

Returning with a wildcard type is generally discouraged, see the detailed reasons in the Generics FAQ. In short, it can make useless (or less useful) the returned object, because methods with parameters using the type argument can be called with 'null's only. For instance, with the Collection:

Collection<? extends Type> collection = ...
collection.add(null); // OK
collection.add(anInstanceOfType); // Error

In this case, this prevents adding anything to the collection (which is not a bad thing, it seems someone uses this to try to make the returned collection "readonly", here), but in general this can cause problems.

Muldon answered 22/8, 2013 at 14:21 Comment(1)
Doesn't answer "What is the difference between these two methods?" but still a good reference.Pursuer
C
0

<? extends Type> is a bounding wildcard generic. A collection defined in this way could be of any subclass of type, or Type. ie.

Collection<Type> typeCollection;
//or
Collection<SubType> subtypeCollection;
//where subtype is...
class SubType extends Type

All that matters in this case is that ? is of type Type.

Collection<Type> must be return a collection of Type. ie.

Collection<Type> collection;

Read the tutorials here. for more information. Which you chose will depend on your needs.

Here's an example. I use bounded wildcards when defining renderable item groups. For example.

public class SpriteGroup<T extends Sprite>

This would be a collection for Sprites, or any subclass of Sprite. This is useful because then I can define groups like so:

SpriteGroup<PhysicalSprite> physicalSprites = new SpriteGroup<PhysicalSprite>();
PhysicalSprite physicalSprite = physicalSprites.get(0);
SpriteGroup<ParticleSprite> particleSprite = new SpriteGroup<ParticleSprite>();
ParticleSprite particle = particleSprite.get(0);

Any get/set routines then return the type I specified (PhysicalSprite, ParticleSprite), which is desirable.

If I'd defined it as:

SpriteGroup<Sprite> spriteGroup = new SpriteGroup();
//all I can retrieve is a sprite, gotta cast now...
Sprite sprite = spriteGroup.get(0);

I'd need to cast them to access properties specific to each type of Sprite. Any subclass of SpriteGroup would be restricted likewise.

Cruzcruzado answered 22/8, 2013 at 14:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.