36

Is it feasible to say that generic wildcard types should not be used in return parameters of a method?

In other words, does make sense to declare an interface like the following:

interface Foo<T> {
  Collection<? extends T> next();
}

Additionally, is it ok to say that generic wildcard types does make sense only at method's parameter declaration?

jilt3d
  • 3,864
  • 8
  • 34
  • 41
  • http://stackoverflow.com/a/30548589/2158288 – ZhongYu May 30 '15 at 16:35
  • 1
    Something I'd like to highlight, since I don't think it's addressed well enough in an obvious place, is that a wildcard on a collection does *not* make that collection immutable. We can remove elements from the collection, we can add `null` to the collection and [we can even use wildcard capture to add non-`null` elements to the collection if it's not empty](https://ideone.com/xmlmWP). If it's a list, then we can also e.g. change the order of elements. (And that's all just aside from the issue of being able to cast the wildcard away.) – Radiodef Sep 11 '18 at 22:34

3 Answers3

36

The main benefit of using wildcard types, say in method formal parameter, is to provide flexibility to the user to pass, say any type of Collection, or List or anything that implements Collection (assuming that the collection is declared like Collection<?>). You would often find yourself using wildcard types in formal parameters.

But ideally you should avoid using them as return type of your method. Because that way, you would force the user of that method to use wildcard types at the caller end, even if they didn't want to. By using wildcard types, you're saying that, hey! this method can return any type of Collection, so it's your job to take care of that. You shouldn't do that. Better to use bounded type parameter. With bounded type parameter, the type will be inferred based on the type you pass, or the target type of the method invocation.

And here's a quote from Effective Java Item 28:

Do not use wildcard types as return types. Rather than providing additional flexibility for your users, it would force them to use wildcard types in client code.
Properly used, wildcard types are nearly invisible to users of a class. They cause methods to accept the parameters they should accept and reject those they should reject. If the user of a class has to think about wildcard types, there is probably something wrong with the class’s API.

jilt3d
  • 3,864
  • 8
  • 34
  • 41
Rohit Jain
  • 209,639
  • 45
  • 409
  • 525
  • So, as I understand - I do not lose any flexibility if I declare the return type without using wildcards, it only makes harder the usage of the interface? Otherwise, the only advantage I can think of is that it will "lock" the returning collection, and will make it kind of immutable, since we are not allowed to add arbitrary elements into a collection referenced using a wildcard. – jilt3d Apr 02 '14 at 15:21
  • 1
    @jilt3d Immutable is a completely different thing. Using bounded type paraemeters would rather provide type safety. You can still add elements that are compatible with the type of Collection. – Rohit Jain Apr 02 '14 at 15:27
  • 2
    @jilt3d Concerning the "immutability" (that I also mentioned in the EDIT of my answer) : This is correct concerning the possibility to add new elements to the collection. But it is **NOT** true in general: You can still add `null`, or simply call `collection.clear()` on the returned collection, for example. – Marco13 Apr 02 '14 at 15:28
  • Agree upon the "immitability". Can you edit your first paragraph so I can accept the answer - when you use `Collection` as a formal parameter and let say that `T` is `String`, you can still pass `List`. The main benefit of using wildcards in this case would be that I would be able to pass collections like `List`, for example (if we assume that `MyString extends String`). – jilt3d Apr 02 '14 at 16:41
  • @jilt3d Yes. BTW, `String` is final class. It can't be extended :) – Rohit Jain Apr 02 '14 at 16:46
  • Yeah, I forgot about the unfriendly nature of `String`. :) – jilt3d Apr 02 '14 at 16:50
  • @jilt3d I've edited the answer. You can accept it if it's fine now. – Rohit Jain Apr 02 '14 at 16:51
  • Can you please add a code block demonstrating how a bounded type parameter achieves the same goal of a method returning a wildcard? Ideally, provide methods (one for each type) and show that they allow the same expressiveness while eliminating the need for wildcards in client code. – Gili Aug 26 '15 at 18:36
  • There are many methods in the standard java reflection API that violate this rule. For example `Method.getReturnType()` which returns a `Class>`. :-) – fuemf5 Aug 03 '16 at 16:16
6

No, it is not feasible to say this.

Or to put it that way: It does make sense to have such an interface.

Imagine the following

interface Foo<T>  
{
    Collection<? extends T> next();
}

class FooInteger implements Foo<Number> 
{
    private final List<Integer> integers = new ArrayList<Integer>();
    void useInternally()
    {
        integers.add(123);
        Integer i = integers.get(0);
    }

    @Override
    public Collection<? extends Number> next() 
    { 
        return integers;
    }
}

// Using it:
Foo<Number> foo = new FooInteger();
Collection<? extends Number> next = foo.next();
Number n = next.iterator().next();

If you wrote the return type as Collection<T>, you could not return a collection containing a subtype of T.

Whether or not it is desirable to have such a return type depends on the application case. In some cases, it may simply be necessary. But if it is easy to avoid, then you can do this.


EDIT: Edited the code to point out the difference, namely that you might not always be able to choose the type internally. However, in most cases returning something that involves a wildcard can be avoided - and as I said, if possible, it should be avoided.

The example sketched above should still be considered as an example to emphasize the key point. Although, of course, such an implementation would be a bad practice, because it is exposing an internal state.

In this and similar cases, one can often return something like a

return Collections.<Number>unmodifiableList(integers);

and by this, declare the return type as Colletion<Number>: The unmodifiableList method solves the problem of the exposed internal state, and has the neat property that it allows changing the type parameter to a supertype, because the list is then... well, unmodifiable anyhow.

Marco13
  • 53,703
  • 9
  • 80
  • 159
  • Actually, even though if I declare the return type as Collection, I can return collection containing elements which are subtypes of T: `final Collection arrayList = new ArrayList(); arrayList.add(new Integer(0));` – jilt3d Apr 02 '14 at 15:14
  • @jilt3d Added an explaination as an EDIT – Marco13 Apr 02 '14 at 15:26
  • Looking at the edited example, I still see no reason why does make sense to declare the return type with wildcards? – jilt3d Apr 02 '14 at 15:54
  • @jilt3d The collection is internally declared as `List`. And you could not return it from this method if the return type had to be `Collection`. When the retun type is `Collection extends Number>`, then you can also return any `Collection`. (Again: This is only an artificial example, but I think it shows that there are cases where such a return type makes sense - regardless of whether it should be avoided in favor of conciseness) – Marco13 Apr 02 '14 at 16:19
  • 1
    Well, you can declare the internal collection as `private final List integers = new ArrayList();` and you will still be able to add an `Integer` instance. Yes, this time you will get a `Number` when you call get() (instead of an `Integer`) but in a real-world scenario this is preferable anyway. – jilt3d Apr 02 '14 at 16:33
  • What about this? `interface Foo { Collection next(); } class FooInteger implements Foo { private final List integers = new ArrayList(); void useInternally() { integers.add(123); Integer i = integers.get(0); } @Override public Collection next() { return integers; } }` – beatrice Oct 31 '19 at 14:17
  • @beatrice I haven't compiled this, but *think* the point is replacing the wildcard by another `<...>` type parameter, right? If this is the case, one should be careful: Types with many `` parameters tend to be hard to use and hard to understand. I think one should only add a type parameter when it is really relevant for the interface. – Marco13 Oct 31 '19 at 15:26
  • for me there are valid use cases for wildcard but they are rare. e.g. i created an interface that is implemented by domain and entity (with different types of collections for same field). With this i am able to implement 1 validator for both. – dermoritz Jul 28 '20 at 08:53
-1

https://rules.sonarsource.com/java/RSPEC-1452

It is highly recommended not to use wildcard types as return types. Because the type inference rules are fairly complex it is unlikely the user of that API will know how to use it correctly. Let's take the example of method returning a "List<? extends Animal>". Is it possible on this list to add a Dog, a Cat, ... we simply don't know. And neither does the compiler, which is why it will not allow such a direct use. The use of wildcard types should be limited to method parameters.

This rule raises an issue when a method returns a wildcard type.

Noncompliant Code Example

  List<? extends Animal> getAnimals(){...}  

Compliant Solution

  List<Animal> getAnimals(){...}    or

  List<Dog> getAnimals(){...}
valeesi
  • 125
  • 2
  • 9
Abhishek Kumar
  • 4,532
  • 5
  • 31
  • 53
  • 4
    it's considered rude to quote a source without mentioning the source at all. So, be honest and state you copied this explanation from [Sonar Rule 1452](https://rules.sonarsource.com/java/RSPEC-1452). – Jacob van Lingen Jun 12 '19 at 13:36
  • 1
    @JacobvanLingen thanks for reminding me. I've updated with the source. :) – Abhishek Kumar Jul 18 '19 at 13:22