views:

136

answers:

5

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?

+3  A: 

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

akf
can you clarify that for me please? i'm also interested in this question.
oedo
This is true, although I wouldn't call it a benefit, and it's unrelated to the question.
Jorn
It is a promise that the collection will be unchanged, but the restriction applies only to the min/max function itself.
Kathy Van Stone
Irrelevant to the question.
DJClayworth
+4  A: 

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: http://stackoverflow.com/questions/2723397/java-generics-what-is-pecs

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

Pyrolistical
+3  A: 

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
Marco
+4  A: 

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
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 <B>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
I see your point. However, with the second signature of min I could have written `B b = Scratchpad.<C>min(coll)` and it would have compiled just as happily (or so I think).
Marco
But you are just forcing this error to occur. Can you give a real world example why you'll need to force it to `<B>`?
Pyrolistical
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
@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<C>, there would be a compile-time error since you cannot implement the same interface twice with different arguments.
Mark Peters
@Marco: yes, exactly, since C is assignable to B. And in this case that is also the same as the implicit invocation.
Mark Peters
@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<C> 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
A: 

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