15

In Java, the Collections class contains the following method:

public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> c)

Its signature is well-known for its advanced use of generics, so much that it is mentioned in the Java in a Nutshell book and in the official Sun Generics Tutorial.

However, I could not find a convincing answer to the following question:

Why is the formal parameter of type Collection<? extends T>, rather than Collection<T>? What's the added benefit?

Marco
  • 298
  • 2
  • 7

5 Answers5

6

Type inference is a tricky topic that I'll admit that I don't know that much about. However, examine this example:

public class ScratchPad {
   private static class A implements Comparable<A> {
     public int compareTo(A o) { return 0; }
   }
   private static class B extends A {}
   private static class C extends B {}

   public static void main(String[] args)
   {
     Collection<C> coll = null;
     B b = Scratchpad.<B>min(coll);
   }

   public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> c)  {
     return null;
   }

   //public static <T extends Object & Comparable<? super T>> T min(Collection<T> c) {
   //  return null;
   //}
}

Consider that the first signature of min() allows the call to compile whereas the second does not. This isn't a very practical example, since one must ask why I would be explicitly typing the method to <B>, but perhaps there is an implicit inference where B would be the inferred type.

Mark Peters
  • 80,126
  • 17
  • 159
  • 190
  • I think it might be useful if A, B and C each have their implementation of compareTo (each class overwrites the previous' method). By calling min(coll) you tell it to use the compareTo of class B, instead of that of class C which might give a different order. – Andrei Fierbinteanu May 25 '10 at 20:12
  • I see your point. However, with the second signature of min I could have written `B b = Scratchpad.min(coll)` and it would have compiled just as happily (or so I think). – Marco May 25 '10 at 20:15
  • But you are just forcing this error to occur. Can you give a real world example why you'll need to force it to ``? – Pyrolistical May 25 '10 at 20:30
  • Actually I'm a dumbass, it'll always use the first method it encounters in the hierarchy of the runtime class, in this case C.compareTo. – Andrei Fierbinteanu May 25 '10 at 20:31
  • @frosty_hotboy: If I understand correctly where you're coming from, then no, that's not the case. Generics don't have an impact on selecting which virtual method to run. If C provided a compareTo(A) method, it would be used always regardless of the method's type parameter. If C tried to implement Comparable, there would be a compile-time error since you cannot implement the same interface twice with different arguments. – Mark Peters May 25 '10 at 20:34
  • @Marco: yes, exactly, since C is assignable to B. And in this case that is also the same as the implicit invocation. – Mark Peters May 25 '10 at 20:35
  • @Pyrolistical: I haven't found a better example yet, but I haven't given up. But while I am explicitly causing the difference to be shown, can you say that min *shouldn't* accept a Collection if the method's type argument is B? The caller of the library may be overly explicit, but it's a correct call nonetheless. Explicitness should not have adverse consequences (in general). It can sometimes improve clarity. – Mark Peters May 25 '10 at 20:49
5

One benefit of the ? is that it prohibits additions of items to the Collection

akf
  • 38,619
  • 8
  • 86
  • 96
  • 1
    can you clarify that for me please? i'm also interested in this question. – chris May 25 '10 at 18:19
  • 1
    This is true, although I wouldn't call it a benefit, and it's unrelated to the question. – Jorn May 25 '10 at 18:25
  • 1
    It is a promise that the collection will be unchanged, but the restriction applies only to the min/max function itself. – Kathy Van Stone May 25 '10 at 18:27
  • Since collection can potentially be any collection of type Collection, where V is a subtype of T, you can never be sure if you are adding an object of correct type to the passed in collection. – patentfox May 31 '17 at 06:39
4

I think it actually doesn't give you anything more for this method, however its a good habit to get into when T is part of the class and not just a static method.

They are including it here so it can become the new convention where every generic should be extended by ?

A class of T should follow PECS: What is PECS (Producer Extends Consumer Super)?

But a static method doesn't need to (at least the parameters, the return value should always)

Community
  • 1
  • 1
Pyrolistical
  • 27,624
  • 21
  • 81
  • 106
2

This is to support a legacy signature of the method in Java 1.4 ( and before ).

Prior to Java 5 the signature for these methods was

public static Object min ( Collection c );

With multiple bounds the erasure rules make the first bound the raw type of the method, so without Object & the signature would be

public static Comparable min ( Collection c );

and legacy code would break.

This is taken from O'Reilly's Java Generics and Collections book, chapter 3.6

Alexander Pogrebnyak
  • 44,836
  • 10
  • 105
  • 121
  • 4
    I think what you're saying applies to the "extends Object &..." part, while the question is about the "? extends T" part. – Marco May 25 '10 at 18:29
1

Building on the comments I put on Mark's answer, if you have something like

class Play {
    class A implements Comparable<A> {
        @Override
        public int compareTo(A o) {
            return 0;
        }
    }

    class B extends A {
    }

    class C extends A {
    }

    public static <T extends Object & Comparable<? super T>> T min(
            Collection<? extends T> c) {
        Iterator<? extends T> i = c.iterator();
        T candidate = i.next();

        while (i.hasNext()) {
            T next = i.next();
            if (next.compareTo(candidate) < 0)
                candidate = next;
        }
        return candidate;
    }

    public static List<? extends A> getMixedList() {
        Play p = new Play();
        ArrayList<A> c = new ArrayList<A>();
        c.add(p.new C());
        c.add(p.new B());
        return c;
    }

    public static void main(String[] args) {
        ArrayList<A> c = new ArrayList<A>();
        Collection<? extends A> coll = getMixedList();
        A a = Play.min(coll);
    }
}

It's clearer that min returns an object of type A (the actual signature is <A> A Play.min(Collection<? extends A> c) ). If you leave min(Collection<T>) without the extends part then Play.min(coll) will have the following signature <? extends A> ? extends A Play.min(Collection<? extends A> c) which isn't as clear.

Andrei Fierbinteanu
  • 7,656
  • 3
  • 31
  • 45