Java generics - special case of extended and super usage - java

Is there any conceptual difference between these two methods?
public static <T> void add1(final Collection<T> drivers, final Collection<? super T> persons) {
persons.addAll(drivers);
}
and
public static <T> void add2(final Collection<? extends T> drivers, final Collection<T> persons) {
persons.addAll(drivers);
}
The following main method compiles without any warnings and executes without any runtime-exceptions. And the result is the expected one - 4.
public static void main(String[] args) {
final Person person1 = new Person();
final Person person2 = new Person();
final Collection<Person> persons = new ArrayList<>();
persons.add(person1);
persons.add(person2);
final Driver driver1 = new Driver();
final Collection<Driver> drivers = new ArrayList<>();
drivers.add(driver1);
add1(drivers, persons);
add2(drivers, persons);
System.out.println(persons.size());
}
I am aware of PECS principle, and since persons in the first method is a consumer, super should be use, respectively - extends should be used for drivers in the second method. But is there any gotchas? Any difference that I may miss? If not, which one of the versions is preferred, and why?

The difference is in the type that is inferred for T: in add1 it is the component type of the first collection (Driver), in add2 it's the component type of the second collection (Person).
In this case T is not used in the method body, so there's no visible difference.

If A is a supertype of B, then B extends A, so there is no difference between the two versions.
Note that you can also use both super and extends:
public static <T> void add3(final Collection<? extends T> drivers, final Collection<? super T> persons) {
persons.addAll(drivers);
}

Related

Java Generics bounded wild card usages before the return type of a method

In the class below, in method m1, is there really any use of mentioning K extends Runnablebefore the method return type? I cannot return anything other than Collection<K> anyways. And if I want to return any subclass of Runnable I would have specified the method like,
static <T> Collection<? extends Runnable> m1(ArrayList<T> l)
Does the K extends Runnable before the method return type have any significance at all? I get no compilation error for this code either
public class MainClass {
public static void main(String[] args) {
ArrayList<Thread> l = new ArrayList<>();
l.add(new Thread());
l.add(new Thread());
m1(l);
}
static <T, K extends Runnable> Collection<K> m1(ArrayList<T> l) {
ArrayList<K> r = new ArrayList<>();
return r;
}
}
By having the parameter K, you can let the caller decide what kind of collection it wants back:
public class Test {
static <T, K extends Runnable> Collection<K> m1(ArrayList<T> l) {
ArrayList<K> r = new ArrayList<>();
return r;
}
static void callingIt(){
ArrayList<?> list = new ArrayList<>();
Collection<Thread> threads = m1(list);
Collection<Runnable> runnables = m1(list);
Collection<MyTask> special = m1(list);
}
class MyTask extends Thread{}
}
If you only had Collection<? extends Runnable> then the caller cannot get back a Collection<Thread>.
But unless the K is connected to something else, I cannot see how this would work except for empty result lists (because as soon as you want to add something to r, you will have to make sure it is an instance of K).
You can see this pattern being used in Collections.emptyList:
public static final List EMPTY_LIST = new EmptyList<>();
public static final <T> List<T> emptyList() {
return (List<T>) EMPTY_LIST;
}
The method returns the same thing as the field, but because it is a method, the caller can use it to produce generically typed lists of any type (whereas the field cannot be flexible like this).
There is an unchecked cast in there (with a warning), but since the list is empty, we (unlike the compiler) know it is safe.

Explanation of the Collections.max signature

I was reading an article on Java Generics when I stumbled on this method signature:
static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll);
The part that I don't get is why we need to have
Collection<? extends T> coll
wouldn't
Collection<T> coll
do as well?
Could someone please explain why the following signature is not adequate?
static <T extends Object & Comparable<? super T>> T max(Collection<T> coll);
Thanks in advance for your replies. This keeps puzzling me for quite some time now..
Gábor is correct. The wildcard allows the static type of the returned object to differ from the declared parameter type of the collection you input. For example, given these classes:
interface S extends Comparable<S> {}
class A implements S {
#Override
public int compareTo(final #NotNull S o) {
return 0;
}
}
class B implements S {
#Override
public int compareTo(final #NotNull S o) {
return 0;
}
}
And this class:
class Test {
#Nullable
static <T extends Comparable<? super T>> T extendsMax(
Collection<? extends T> coll) {
return null;
}
#Nullable
static <T extends Comparable<? super T>> T max(Collection<T> coll) {
return null;
}
}
Observe what calls compile and what calls do not:
public static void main(String[] args) {
final Collection<S> sColl = new ArrayList<>();
final Collection<A> aColl = new ArrayList<>();
final Collection<B> bColl = new ArrayList<>();
final S s1 = Test.<S> extendsMax(sColl); // compiles, T = S, <? extends T> = S
final S s2 = Test.<S> extendsMax(aColl); // compiles, T = S, <? extends T> = A
final S s3 = Test.<S> extendsMax(bColl); // compiles, T = S, <? extends T> = B
final A a1 = Test.<A> extendsMax(aColl); // compiles, T = A
final B b1 = Test.<B> extendsMax(bColl); // compiles, T = B
final S s4 = Test.<S> max(sColl); // compiles, T = S
final S s5 = Test.<S> max(aColl); // does not compile, T = S, T != A
final S s6 = Test.<S> max(bColl); // does not compile, T = S, T != B
final S s7 = Test.max(aColl); // compiles, but because T = A, and A
// can be assigned to S
}
So the wildcard allows for some flexibility. While you can omit the wildcard (and to be honest, I can't think of a place off the top of my head where the wildcard is required), there is a reason it is there.
Tom is also incorrect. You can add null to collections with a wildcard (if the collection supports add() in the first place):
List<? extends Number> list = new ArrayList<>();
list.add(null); // compiles, and should execute just fine
And because add(), remove(), and most other mutators in the Collection interface are optional operations, it wouldn't be safe to mutate the collection anyways through those methods if the parameter is just declared as a Collection. In addition, it's generally possible to use iterator().remove() or something of the sort to remove elements from collections regardless of whether they were declared with a wildcard, especially for the ones already included in the Java Collections Framework.
So while a wildcard does limit what you can do with a collection, it should not be used as a way to prevent changes to a collection.

Why producer in Collections.max() is a bounded wildcard? [duplicate]

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?
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.
One benefit of the ? is that it prohibits additions of items to the Collection
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)
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
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.

Method to take `T extends Iterable` and return T<E>?

How do I write a method that takes a parameter of some type T which is an instance of Iterable, as well as a parameter of Class<E>, and return T<E>?
public static <...> ... checkedCast(T iterable, Class<E> clazz) {
// Check elements and throw ClassCastException if invalid
#SupressWarning("checked")
... cast = (...)iterable;
return cast;
}
I want to use it like this:
// This should compile
ArrayList<?> a = ...;
ArrayList<String> b = checkedCast(a, String.class);
// So should this
HashSet<Number> c = ...;
Set<Integer> d = checkedCast(c, Integer.class);
// This shouldn't compile
b = checkedCast(a, Integer.class);
// This shouldn't compile
b = checkedCast(c, Integer.class);
// This should throw ClassCastException
checkedCast(a, Integer.class);
I know I can do this using overrides, but this requires me to write an override for every type:
public static <T> Iterable<T> checkedCast(Iterable<?> iterable, Class<T> clazz) {...}
public static <T> List<T> checkedCast(List<?> list, Class<T> clazz) {...}
public static <T> ArrayList<T> checkedCast(ArrayList<?> list, Class<T> clazz) {...}
public static <T> Set<T> checkedCast(Set<?> set, Class<T> clazz) {...}
One of the weaknesses of the Java type system's Generics extension is that how we think about types in the singular doesn't scale to how we think of types in the plural.
In short, Collections of a generic type cannot be safely cast, ever. Build a new list, pull out each type and check it individually, and the return the new list. If you disregard this warning, I'll direct someone to do something like
List<Customer> customers = new ArrayList<>();
customers.add(new Customer(...));
List<Object> customerObjects = checkCast(customers, Object.class);
customerObjects.add(new Order(...));
You have been warned.
See if this works for you. But, people can help you better if you can describe in more detail why you need such a method.
public static
<InputElement, OutputElement extends InputElement,
InputContainer extends Iterable<InputElement>,
OutputContainer extends Iterable<OutputElement>>
OutputContainer checkedCast(InputContainer iterable,
Class<OutputElement> clazz) {
#SuppressWarnings("unchecked")
OutputContainer output = (OutputContainer) iterable;
return output;
}
This works/matches your requirements - except for throwing a ClassCastException (if you really want that behaviour, you can include it in the checkedCast method yourself):
import java.util.*;
public class CheckedCast {
public static <GenB, GenA extends GenB, CollA extends List<GenA>> List<GenB> checkedCast(CollA iterable, Class<GenB> clazz){
return (List<GenB>)iterable;
}
public static <GenB, GenA extends GenB, CollA extends Set<GenA>> Set<GenB> checkedCast(CollA iterable, Class<GenB> clazz){
return (Set<GenB>)iterable;
}
static class One {}
static class Two extends One {}
static class Three {}
public static void main(String[] args) {
ArrayList<Two> test1 = new ArrayList<Two>();
List<One> test2 = checkedCast(test1, One.class);
// Shouldn't compile...
ArrayList<One> aa = checkedCast(test2, One.class); // output is ArrayList
List<Two> bb = checkedCast(test2, Three.class); // Three is not superClass of Two
ArrayList cc = checkedCast(new HashSet(), Integer.class); // Set cannot become List
ArrayList<One> dd = checkedCast(new LinkedList<One>(), One.class); // ArrayList is not superClass of List
}
}
Updated to match new requirement: ArrayList xs = checkedCast(new HashSet(), Integer.class) - shouldn't compile
Update: updated to assert returned Collection generic type extends input Collection's generic type.

Generics: how to enforce restrictions between keys and values in a Map

The problem: I've a Function Object interface defined in a class:
public static interface FunctionObject<T> {
void process(T object);
}
I need it generic because I'd like to use T methods in the process implementations.
Then, in other generic class, I've a Map where I have classes as keys and function objects as values:
Map<Class<T>, FunctionObject<T>> map;
But I also want the map to accept subtype classes and function objects of supertypes OF THE KEY TYPE, so I did this:
Map<Class<? extends T>, FunctionObject<? super T>> map; //not what I need
The basic idea is to be able to use the map as follows:
//if T were Number, this should be legal
map.put(Class<Integer>, new FunctionObject<Integer>(){...});
map.put(Class<Float>, new FunctionObject<Number>(){...});
map.put(Class<Double>, new FunctionObject<Object>(){...});
As I want to enforce the FunctionObject has the type of the class key or a supertype, what I really would like to define is this:
Map<Class<E extends T>, FunctionObject<? super E>>> map;
How can I achieve the desired effect? Is a typesafe heterogenous container the only option? What would the Map generic types look like to allow populating it from a reference?
Parametrized container, seems to work just fine:
public class MyMap<T>
{
interface FunctionObject<X> {}
private Map<Class<? extends T>, FunctionObject<Object>> map = new HashMap<>();
#SuppressWarnings("unchecked")
public <E extends T> void put(Class<E> c, FunctionObject<? super E> f)
{
map.put(c, (FunctionObject<Object>) f);
}
public <E extends T> FunctionObject<Object> get(Class<E> c)
{
return map.get(c);
}
public static void Main(String[] args)
{
MyMap<Number> map = new MyMap<>();
map.put(Integer.class, new FunctionObject<Integer>() {});
map.put(Float.class, new FunctionObject<Number>() {});
map.put(Double.class, new FunctionObject<Object>() {});
}
}
Edited to comply to the question. Sadly there is no way to avoid the downcasting to object.
Edit added get().
You can do this with encapsulation, assuming you only use the map through the method which check this on a per entry basis.
The following add method avoids the need to double up on the type as well.
public class Main {
interface FunctionObject<T> { }
private final Map<Class, FunctionObject> map = new LinkedHashMap<Class, FunctionObject>();
public <T> void add(FunctionObject<T> functionObject) {
Class<T> tClass = null;
for (Type iType : functionObject.getClass().getGenericInterfaces()) {
ParameterizedType pt = (ParameterizedType) iType;
if (!pt.getRawType().equals(FunctionObject.class)) continue;
Type t = pt.getActualTypeArguments()[0];
tClass = (Class<T>) t;
break;
}
map.put(tClass, functionObject);
}
public <T> void put(Class<T> tClass, FunctionObject<T> functionObject) {
map.put(tClass, functionObject);
}
public <T> FunctionObject<T> get(Class<T> tClass) {
return map.get(tClass);
}
public static void main(String... args) throws IOException {
Main m = new Main();
m.add(new FunctionObject<Integer>() {
});
FunctionObject<Integer> foi = m.get(Integer.class);
System.out.println(foi.getClass().getGenericInterfaces()[0]);
}
}
prints
Main.Main$FunctionObject<java.lang.Integer>
You can use #SuppressWarnings("unchecked") if you want to disable the warning.
The point is; there is no way to describe the constraint you have in the field declaration, you can achieve the same result if you use accessor methods which do the check on a per entry basis. You can add runtime checks as well if you need to ensure raw types are correct.

Categories