Java generics, nesting Type parameters - java

I want to create a generic method that gets a Collection<T> as parameter, does something on the elements (mapping) and returns a Collection<R>.
This isn't a problem, with the following declaration:
public <R,T> Collection<R> foo(Collection<T> c);
Now, I want to force my method to return a Collection of the same type of the parameter, so there will be no need to cast the return value to the specific collection. Something like this:
public <R, T, S extends Collection> S<R> foo(S<T> c);
Sadly enough, this doesn't compile.
Can this be done somehow? What is the right way to do this?

One way to do this if you want to use generics is to do the following:
public <R, S, CR extends Collection<R>, CS extends Collection<S>> CR foo(CS c);
The issue is binding your argument and your return to a type.

You can not tie two generics together that way. Anyway even if you can you still would need to create a new collection in foo. (You can not reuse c, that would create a poluted heap)
One way of doing it would provide a supplier for the collection that enforces the type:
public static void callFoo(){
List<String> strings = new ArrayList<>();
ArrayList<Integer> foo = foo(strings, ArrayList::new);
}
public static <R,T, S extends Collection<R>> S foo(Collection<T> ts, Supplier<S> supplier){
S s = supplier.get();
for(T t:ts){
s.add(null);
}
return s;
}

You can use the Method Overloading in Java, try to overload your data manipulation in your mapping method.

Related

Does Java wildcard-? has an unavoidable purpose or is it just a syntactic sugar? [duplicate]

I am reading about generic methods from OracleDocGenericMethod. I am pretty confused about the comparison when it says when to use wild-card and when to use generic methods.
Quoting from the document.
interface Collection<E> {
public boolean containsAll(Collection<?> c);
public boolean addAll(Collection<? extends E> c);
}
We could have used generic methods here instead:
interface Collection<E> {
public <T> boolean containsAll(Collection<T> c);
public <T extends E> boolean addAll(Collection<T> c);
// Hey, type variables can have bounds too!
}
[…]
This tells us that the type argument is being used for polymorphism;
its only effect is to allow a variety of actual argument types to be
used at different invocation sites. If that is the case, one should
use wildcards. Wildcards are designed to support flexible subtyping,
which is what we're trying to express here.
Don't we think wild card like (Collection<? extends E> c); is also supporting kind of
polymorphism? Then why generic method usage is considered not good in this?
Continuing ahead, it states,
Generic methods allow type parameters to be used to express
dependencies among the types of one or more arguments to a method
and/or its return type. If there isn't such a dependency, a generic
method should not be used.
What does this mean?
They have presented the example
class Collections {
public static <T> void copy(List<T> dest, List<? extends T> src) {
...
}
[…]
We could have written the signature for this method another way,
without using wildcards at all:
class Collections {
public static <T, S extends T> void copy(List<T> dest, List<S> src) {
...
}
The document discourages the second declaration and promotes usage of first syntax? What's the difference between the first and second declaration? Both seems to be doing the same thing?
Can someone put light on this area.
There are certain places, where wildcards, and type parameters do the same thing. But there are also certain places, where you have to use type parameters.
If you want to enforce some relationship on the different types of method arguments, you can't do that with wildcards, you have to use type parameters.
Taking your method as example, suppose you want to ensure that the src and dest list passed to copy() method should be of same parameterized type, you can do it with type parameters like so:
public static <T extends Number> void copy(List<T> dest, List<T> src)
Here, you are ensured that both dest and src have same parameterized type for List. So, it's safe to copy elements from src to dest.
But, if you go on to change the method to use wildcard:
public static void copy(List<? extends Number> dest, List<? extends Number> src)
it won't work as expected. In 2nd case, you can pass List<Integer> and List<Float> as dest and src. So, moving elements from src to dest wouldn't be type safe anymore.
If you don't need such kind of relation, then you are free not to use type parameters at all.
Some other difference between using wildcards and type parameters are:
If you have only one parameterized type argument, then you can use wildcard, although type parameter will also work.
Type parameters support multiple bounds, wildcards don't.
Wildcards support both upper and lower bounds, type parameters just support upper bounds. So, if you want to define a method that takes a List of type Integer or it's super class, you can do:
public void print(List<? super Integer> list) // OK
but you can't use type parameter:
public <T super Integer> void print(List<T> list) // Won't compile
References:
Angelika Langer's Java Generics FAQs
Consider following example from The Java Programming by James Gosling 4th edition below where we want to merge 2 SinglyLinkQueue:
public static <T1, T2 extends T1> void merge(SinglyLinkQueue<T1> d, SinglyLinkQueue<T2> s){
// merge s element into d
}
public static <T> void merge(SinglyLinkQueue<T> d, SinglyLinkQueue<? extends T> s){
// merge s element into d
}
Both of the above methods have the same functionality. So which is preferable? Answer is 2nd one. In the author's own words :
"The general rule is to use wildcards when you can because code with wildcards
is generally more readable than code with multiple type parameters. When deciding if you need a type
variable, ask yourself if that type variable is used to relate two or more parameters, or to relate a parameter
type with the return type. If the answer is no, then a wildcard should suffice."
Note: In book only second method is given and type parameter name is S instead of 'T'. First method is not there in the book.
In your first question: It means that if there is a relation between the parameter's type and the method's return type then use a generic.
For example:
public <T> T giveMeMaximum(Collection<T> items);
public <T> Collection<T> applyFilter(Collection<T> items);
Here you are extracting some of the T following a certain criteria. If T is Long your methods will return Long and Collection<Long>; the actual return type is dependent on the parameter type, thus it is useful, and advised, to use generic types.
When this is not the case you can use wild card types:
public int count(Collection<?> items);
public boolean containsDuplicate(Collection<?> items);
In this two example whatever the type of the items in the collections the return types will be int and boolean.
In your examples:
interface Collection<E> {
public boolean containsAll(Collection<?> c);
public boolean addAll(Collection<? extends E> c);
}
those two functions will return a boolean whatever is the types of the items in the collections. In the second case it is limited to instances of a subclass of E.
Second question:
class Collections {
public static <T> void copy(List<T> dest, List<? extends T> src) {
...
}
This first code allow you to pass an heterogeneous List<? extends T> src as a parameter. This list can contain multiple elements of different classes as long as they all extends the base class T.
if you had:
interface Fruit{}
and
class Apple implements Fruit{}
class Pear implements Fruit{}
class Tomato implements Fruit{}
you could do
List<? extends Fruit> basket = new ArrayList<? extends Fruit>();
basket.add(new Apple());
basket.add(new Pear());
basket.add(new Tomato());
List<Fruit> fridge = new ArrayList<Fruit>();
Collections.copy(fridge, basket);// works
On the other hand
class Collections {
public static <T, S extends T> void copy(List<T> dest, List<S> src) {
...
}
constrain List<S> src to be of one particular class S that is a subclass of T. The list can only contain elements of one class (in this instance S) and no other class, even if they implement T too. You wouldn't be able to use my previous example but you could do:
List<Apple> basket = new ArrayList<Apple>();
basket.add(new Apple());
basket.add(new Apple());
basket.add(new Apple());
List<Fruit> fridge = new ArrayList<Fruit>();
Collections.copy(fridge, basket); /* works since the basket is defined as a List of apples and not a list of some fruits. */
Wildcard method is also generic - you could call it with some range of types.
The <T> syntax defines a type variable name. If a type variable has any use (e.g. in method implementation or as a constraint for other type), then it makes sense to name it, otherwise you could use ?, as anonymous variable. So, looks like just a short-cut.
Moreover, the ? syntax is not avoidable when you declare a field:
class NumberContainer
{
Set<? extends Number> numbers;
}
I will try and answer your question, one by one.
Don't we think wild card like (Collection<? extends E> c); is also
supporting kind of polymorphism?
No. The reason is that the bounded wildcard has no defined parameter type. It is an unknown. All it "knows" is that the "containment" is of a type E (whatever defined). So, it cannot verify and justify whether the value provided matches the bounded type.
So, it's no sensible to have polymorphic behaviours on wildcards.
The document discourages the second declaration and promotes usage of
first syntax? What's the difference between the first and second
declaration? Both seems to be doing the same thing?
The first option is better in this case as T is always bounded, and source will definitely have values (of unknowns) that subclasses T.
So, suppose that you want to copy all list of numbers, the first option will be
Collections.copy(List<Number> dest, List<? extends Number> src);
src, essentially, can accept List<Double>, List<Float>, etc. as there is an upper bound to the parameterized type found in dest.
The 2nd option will force you to bind S for every type you want to copy, like so
//For double
Collections.copy(List<Number> dest, List<Double> src); //Double extends Number.
//For int
Collections.copy(List<Number> dest, List<Integer> src); //Integer extends Number.
As S is a parameterized type that needs binding.
I hope this helps.
One other difference which is not listed here.
static <T> void fromArrayToCollection(T[] a, Collection<T> c) {
for (T o : a) {
c.add(o); // correct
}
}
But the following will result in compile time error.
static <T> void fromArrayToCollection(T[] a, Collection<?> c) {
for (T o : a) {
c.add(o); // compile time error
}
}
? means unknown
The general rule applies:
You can read from it, but not write
given simple pojo Car
class Car {
void display(){
}
}
This will compile
private static <T extends Car> void addExtractedAgain1(List<T> cars) {
T t = cars.get(1);
t.display();
cars.add(t);
}
This method won't compile
private static void addExtractedAgain2(List<? extends Car> cars) {
Car car = cars.get(1);
car.display();
cars.add(car); // will not compile
}
Another example
List<?> hi = Arrays.asList("Hi", new Exception(), 0);
hi.forEach(o -> {
o.toString() // it's ok to call Object methods and methods that don't need the contained type
});
hi.add(...) // nothing can be add here won't compile, we need to tell compiler what the data type is but we do not know
As far as I understand, there is only one use case when wildcard is strictly needed (i.e. can express something that you can not express using explicit type parameters). This is when you need to specify a lower bound.
Apart from that however wildcards serve to write more concise code, as described by the following statements in the document you mention:
Generic methods allow type parameters to be used to express
dependencies among the types of one or more arguments to a method
and/or its return type. If there isn't such a dependency, a generic
method should not be used.
[...]
Using wildcards is clearer and more concise than declaring explicit
type parameters, and should therefore be preferred whenever possible.
[...]
Wildcards also have the advantage that they can be used outside of
method signatures, as the types of fields, local variables and arrays.
Mainly -> Wildcards enforce generics at the parameter/argument level of a Non-Generic method.
Note. It can also be performed in genericMethod by default, but here instead of ? we can use T itself.
package generics;
public class DemoWildCard {
public static void main(String[] args) {
DemoWildCard obj = new DemoWildCard();
obj.display(new Person<Integer>());
obj.display(new Person<String>());
}
void display(Person<?> person) {
//allows person of Integer,String or anything
//This cannnot be done if we use T, because in that case we have to make this method itself generic
System.out.println(person);
}
}
class Person<T>{
}
SO wildcard has its specific usecases like this.

When to use generic methods and when to use wild-card?

I am reading about generic methods from OracleDocGenericMethod. I am pretty confused about the comparison when it says when to use wild-card and when to use generic methods.
Quoting from the document.
interface Collection<E> {
public boolean containsAll(Collection<?> c);
public boolean addAll(Collection<? extends E> c);
}
We could have used generic methods here instead:
interface Collection<E> {
public <T> boolean containsAll(Collection<T> c);
public <T extends E> boolean addAll(Collection<T> c);
// Hey, type variables can have bounds too!
}
[…]
This tells us that the type argument is being used for polymorphism;
its only effect is to allow a variety of actual argument types to be
used at different invocation sites. If that is the case, one should
use wildcards. Wildcards are designed to support flexible subtyping,
which is what we're trying to express here.
Don't we think wild card like (Collection<? extends E> c); is also supporting kind of
polymorphism? Then why generic method usage is considered not good in this?
Continuing ahead, it states,
Generic methods allow type parameters to be used to express
dependencies among the types of one or more arguments to a method
and/or its return type. If there isn't such a dependency, a generic
method should not be used.
What does this mean?
They have presented the example
class Collections {
public static <T> void copy(List<T> dest, List<? extends T> src) {
...
}
[…]
We could have written the signature for this method another way,
without using wildcards at all:
class Collections {
public static <T, S extends T> void copy(List<T> dest, List<S> src) {
...
}
The document discourages the second declaration and promotes usage of first syntax? What's the difference between the first and second declaration? Both seems to be doing the same thing?
Can someone put light on this area.
There are certain places, where wildcards, and type parameters do the same thing. But there are also certain places, where you have to use type parameters.
If you want to enforce some relationship on the different types of method arguments, you can't do that with wildcards, you have to use type parameters.
Taking your method as example, suppose you want to ensure that the src and dest list passed to copy() method should be of same parameterized type, you can do it with type parameters like so:
public static <T extends Number> void copy(List<T> dest, List<T> src)
Here, you are ensured that both dest and src have same parameterized type for List. So, it's safe to copy elements from src to dest.
But, if you go on to change the method to use wildcard:
public static void copy(List<? extends Number> dest, List<? extends Number> src)
it won't work as expected. In 2nd case, you can pass List<Integer> and List<Float> as dest and src. So, moving elements from src to dest wouldn't be type safe anymore.
If you don't need such kind of relation, then you are free not to use type parameters at all.
Some other difference between using wildcards and type parameters are:
If you have only one parameterized type argument, then you can use wildcard, although type parameter will also work.
Type parameters support multiple bounds, wildcards don't.
Wildcards support both upper and lower bounds, type parameters just support upper bounds. So, if you want to define a method that takes a List of type Integer or it's super class, you can do:
public void print(List<? super Integer> list) // OK
but you can't use type parameter:
public <T super Integer> void print(List<T> list) // Won't compile
References:
Angelika Langer's Java Generics FAQs
Consider following example from The Java Programming by James Gosling 4th edition below where we want to merge 2 SinglyLinkQueue:
public static <T1, T2 extends T1> void merge(SinglyLinkQueue<T1> d, SinglyLinkQueue<T2> s){
// merge s element into d
}
public static <T> void merge(SinglyLinkQueue<T> d, SinglyLinkQueue<? extends T> s){
// merge s element into d
}
Both of the above methods have the same functionality. So which is preferable? Answer is 2nd one. In the author's own words :
"The general rule is to use wildcards when you can because code with wildcards
is generally more readable than code with multiple type parameters. When deciding if you need a type
variable, ask yourself if that type variable is used to relate two or more parameters, or to relate a parameter
type with the return type. If the answer is no, then a wildcard should suffice."
Note: In book only second method is given and type parameter name is S instead of 'T'. First method is not there in the book.
In your first question: It means that if there is a relation between the parameter's type and the method's return type then use a generic.
For example:
public <T> T giveMeMaximum(Collection<T> items);
public <T> Collection<T> applyFilter(Collection<T> items);
Here you are extracting some of the T following a certain criteria. If T is Long your methods will return Long and Collection<Long>; the actual return type is dependent on the parameter type, thus it is useful, and advised, to use generic types.
When this is not the case you can use wild card types:
public int count(Collection<?> items);
public boolean containsDuplicate(Collection<?> items);
In this two example whatever the type of the items in the collections the return types will be int and boolean.
In your examples:
interface Collection<E> {
public boolean containsAll(Collection<?> c);
public boolean addAll(Collection<? extends E> c);
}
those two functions will return a boolean whatever is the types of the items in the collections. In the second case it is limited to instances of a subclass of E.
Second question:
class Collections {
public static <T> void copy(List<T> dest, List<? extends T> src) {
...
}
This first code allow you to pass an heterogeneous List<? extends T> src as a parameter. This list can contain multiple elements of different classes as long as they all extends the base class T.
if you had:
interface Fruit{}
and
class Apple implements Fruit{}
class Pear implements Fruit{}
class Tomato implements Fruit{}
you could do
List<? extends Fruit> basket = new ArrayList<? extends Fruit>();
basket.add(new Apple());
basket.add(new Pear());
basket.add(new Tomato());
List<Fruit> fridge = new ArrayList<Fruit>();
Collections.copy(fridge, basket);// works
On the other hand
class Collections {
public static <T, S extends T> void copy(List<T> dest, List<S> src) {
...
}
constrain List<S> src to be of one particular class S that is a subclass of T. The list can only contain elements of one class (in this instance S) and no other class, even if they implement T too. You wouldn't be able to use my previous example but you could do:
List<Apple> basket = new ArrayList<Apple>();
basket.add(new Apple());
basket.add(new Apple());
basket.add(new Apple());
List<Fruit> fridge = new ArrayList<Fruit>();
Collections.copy(fridge, basket); /* works since the basket is defined as a List of apples and not a list of some fruits. */
Wildcard method is also generic - you could call it with some range of types.
The <T> syntax defines a type variable name. If a type variable has any use (e.g. in method implementation or as a constraint for other type), then it makes sense to name it, otherwise you could use ?, as anonymous variable. So, looks like just a short-cut.
Moreover, the ? syntax is not avoidable when you declare a field:
class NumberContainer
{
Set<? extends Number> numbers;
}
I will try and answer your question, one by one.
Don't we think wild card like (Collection<? extends E> c); is also
supporting kind of polymorphism?
No. The reason is that the bounded wildcard has no defined parameter type. It is an unknown. All it "knows" is that the "containment" is of a type E (whatever defined). So, it cannot verify and justify whether the value provided matches the bounded type.
So, it's no sensible to have polymorphic behaviours on wildcards.
The document discourages the second declaration and promotes usage of
first syntax? What's the difference between the first and second
declaration? Both seems to be doing the same thing?
The first option is better in this case as T is always bounded, and source will definitely have values (of unknowns) that subclasses T.
So, suppose that you want to copy all list of numbers, the first option will be
Collections.copy(List<Number> dest, List<? extends Number> src);
src, essentially, can accept List<Double>, List<Float>, etc. as there is an upper bound to the parameterized type found in dest.
The 2nd option will force you to bind S for every type you want to copy, like so
//For double
Collections.copy(List<Number> dest, List<Double> src); //Double extends Number.
//For int
Collections.copy(List<Number> dest, List<Integer> src); //Integer extends Number.
As S is a parameterized type that needs binding.
I hope this helps.
One other difference which is not listed here.
static <T> void fromArrayToCollection(T[] a, Collection<T> c) {
for (T o : a) {
c.add(o); // correct
}
}
But the following will result in compile time error.
static <T> void fromArrayToCollection(T[] a, Collection<?> c) {
for (T o : a) {
c.add(o); // compile time error
}
}
? means unknown
The general rule applies:
You can read from it, but not write
given simple pojo Car
class Car {
void display(){
}
}
This will compile
private static <T extends Car> void addExtractedAgain1(List<T> cars) {
T t = cars.get(1);
t.display();
cars.add(t);
}
This method won't compile
private static void addExtractedAgain2(List<? extends Car> cars) {
Car car = cars.get(1);
car.display();
cars.add(car); // will not compile
}
Another example
List<?> hi = Arrays.asList("Hi", new Exception(), 0);
hi.forEach(o -> {
o.toString() // it's ok to call Object methods and methods that don't need the contained type
});
hi.add(...) // nothing can be add here won't compile, we need to tell compiler what the data type is but we do not know
As far as I understand, there is only one use case when wildcard is strictly needed (i.e. can express something that you can not express using explicit type parameters). This is when you need to specify a lower bound.
Apart from that however wildcards serve to write more concise code, as described by the following statements in the document you mention:
Generic methods allow type parameters to be used to express
dependencies among the types of one or more arguments to a method
and/or its return type. If there isn't such a dependency, a generic
method should not be used.
[...]
Using wildcards is clearer and more concise than declaring explicit
type parameters, and should therefore be preferred whenever possible.
[...]
Wildcards also have the advantage that they can be used outside of
method signatures, as the types of fields, local variables and arrays.
Mainly -> Wildcards enforce generics at the parameter/argument level of a Non-Generic method.
Note. It can also be performed in genericMethod by default, but here instead of ? we can use T itself.
package generics;
public class DemoWildCard {
public static void main(String[] args) {
DemoWildCard obj = new DemoWildCard();
obj.display(new Person<Integer>());
obj.display(new Person<String>());
}
void display(Person<?> person) {
//allows person of Integer,String or anything
//This cannnot be done if we use T, because in that case we have to make this method itself generic
System.out.println(person);
}
}
class Person<T>{
}
SO wildcard has its specific usecases like this.

What is a use case for a generic constructor?

Consider the following constructor for the class Foo (which for the sake of clarity is not a generic class):
public <T> Foo(T obj) { }
This is valid syntax for constructors, just like with normal generic methods.
But what is the use of this syntax? Typically generic methods provide type safety for their return type, and can benefit from type inference by the compiler. For example:
Pair<String, Integer> stringInt = Pair.of("asfd", 1234);
But a call to a constructor always returns an instance of its declaring class, so its type parameters have no effect on the return type. The constructor above could just be replaced with its erasure:
public Foo(Object obj) { }
Of course generics aren't only about type safety for return types. The constructor might just want to constrain the type of argument(s) being passed in. However, the above reasoning still applies for a bounded type parameter:
public <N extends Number> Foo(N number) { }
public Foo(Number number) { } //same thing
Even nested type parameters with bounds are handled using wildcards:
public <N extends Number, L extends List<N>> Foo(L numList) { }
public Foo(List<? extends Number> numList) { } //same thing
So what is a legitimate use case for having a generic constructor?
Here's a possible one, adapted from functional programming. Suppose we have a Stream type that has some internal state, repeatedly yielding new elements until it returns null. The outside callers don't care what the internal state type of the stream type is, so you might get something like
class Stream<E> {
<S> Stream(S initialState, StepFunction<E, S> stepFun) {
...
}
}
without the recipient having to know what the internal state type is.
One thing I can think off of the top of my head is that you can ensure that bounds are fulfilled in the same way across multiple parameters.
Take an obviously stupid and contrived but valid constructor that copies a list from a source to a target:
public <T> Foo (List<T> listA, List<T> listB) {
listA.addAll(listB);
}
Using wildcards here would quickly become pretty nasty and probably not do what you want anyway. It would also be a totally arbitrary restriction to disallow it. So it makes sense to me that the language spec allows it.
One use case that I can think of is when you want to constrain a constructor argument to more than one type. Only the generic syntax allows you to declare a constructor taking a List of Numbers that also implements RandomAccess:
public <L extends List<? extends Number> & RandomAccess> Foo(L raNumList) { }
...
Foo f1 = new Foo(new ArrayList<Integer>());
Foo f2 = new Foo(new LinkedList<Integer>()); //compiler error
You can enforce certain constraints for the constructor parameters. E.g. the following code requires two parameters which implement the interfaces InterfaceA and InterfaceB.
<T extends InterfaceA & InterfaceB > Foo(T t1, T t2) {
}
The main use is to ensure that type constraints are met between multiple parameters. Here's an example that puts a bunch of components on an assembly line in the right order:
public <T> AssemblyLine(T[] starting, List<T> components) {
T[] a = components.toArray(starting);
Arrays.sort(a);
this.conveyorBelt.add(a);
}
Here the <T> ensures that T[] and List<T> hold the same type T, and not (say), Integer[] and List<string>.

Nested Type Parameters in Java

This is an example which I made up to be a simplification of my real code, so I apologize if it is a little contrived. What I would like to do is to effectively get two type parameters out of a single nested type argument. I'm pretty sure this is impossible, but I thought I'd give it a shot.
//Not legal java code
public class Foo<C extends Collection<T>> { //where T is another type parameter
private C coll;
public Foo(C coll) {
this.coll = coll;
}
public void add(T elem){
this.coll.add(elem);
}
//UPDATED TO ADD GETTER
/**
* I may need to retrieve the collection again, or pass it
* on to another function that needs the specific C type
*/
public C getColl(){
return coll;
}
}
...
List<String> strings = new ArrayList<String>();
Foo<List<String>> foo = new Foo<List<String>>(strings);
foo.add("hello");
I know that I could do it by adding another type parameter:
public class Foo<C extends Collection<T>,T>
but then I have to add the redundant:
Foo<List<String>,String> foo = new Foo<List<String>,String>(strings);
And in my real world case, my generics can sometimes be specified in the implements clause like
public class Bar implements Baz<String>
Having to specify that second type parameter is even more painful then, because it feels like it throws the implementation details in my face. Having to say
Foo<Bar,String>
when there is a relationship between String and Bar already, just seems inelegant. I get that its Java, so that goes with the territory, but just curious if there was a solution for this.
It's not possible and I don't think it's ideal anyway because there is nothing in your existing class that requires invariance.
Foo<T,C extends Collection<T>>
could more generally be
Foo<T,C extends Collection<? super T>>
if the only reason to have T is to allow mutation of the collection.
Note, if you're concerned about having to specify two type parameters frequently, you can create a shallow subclass:
class DerivedFoo<T> extends Foo<Collection<T>,T>
and you can use factory methods to avoid having to double-specify at creation time
public static <T> Foo<Collection<T>,T> fromCollection(Collection<T> c)
You can also abstract the interface into an interface to get the benefits of concise types that you get with DerivedFoo above.
Why wouldn't you just use T as your only type parameter, as in:
public class Foo<T> { //where T is another type parameter
private Collection<T> coll;
public Foo(Collection<T> coll) {
this.coll = coll;
}
public void add(T elem){
this.coll.add(elem);
}
Prior to Java7, constructors don't do type inference, the workaround is to have a static factory method. That's no longer necessary. In Java 7 you can
Foo<List<String>,String> foo = new Foo<>(strings);
Regarding T and C, if we have 2 type parameters with constraints between them, there got to be some degree of redundancy. In your example, since one parameter C totally dictates the another parameter T, the redundancy seems unbearable. I don't see a solution.
But you probably can feel better if the type parameters are reordered
Foo<String,Bar> foo = new Foo<>(bar);
so we declare String first; then further provide a Baz<String> which is Bar

Supporting covariant type conversions in Java

The Java type system supports only invariant types. So a List<String> is not an List<Object>. A List<String> is not a List<Object> as it is not valid to insert an Integer into a List<String>. However, there are types for which such a covariant type conversion is valid.
Given the classes A, B and Producer:
class A{}
class B{}
interface Producer<T> {
T next();
}
A cast for the covariant type Producer can be defined:
class Types{
#SuppressWarnings("unchecked")
public static <T> Producer<T> cast(Producer<? extends T> producer){
return (Producer<T>) producer;
}
}
This method supports to cast from Producer<A> to Producer<Object> and prevents invalid casts like Producer<A> to Producer<B>:
Producer<Object> valid = Types.<Object> cast(new Producer<A>());
Producer<A> invalid = Types.<A> cast(new Producer<B>()); //does not compile
My problem is that I cannot perform a cast from Producer<Producer<A>> to Producer<Producer<Object>>.
Producer<Producer<A>> producerOfA = new Producer<Producer<A>>();
Producer<Producer<Object>> producerOfObjects =
Types.<Producer<Object>> cast(producerOfA); //does not compile
Is there a way to persuade the Java type system to perform such a valid type conversion without warnings in user code?
You haven't posted the code for Producer, but based on the name and your assertion that it should be covariant, perhaps wherever you currently say:
Producer<Foo>
You should instead say:
Producer<? extends Foo>
It would be nice if Java would automatically realize that a generic interface was equivalent to its wildcarded forms (Iterator and Iterable are also safely covariant, for example), but for now at least, it doesn't.
Well, you could just go via raw types and do
Producer<Producer<String>> spp = ...;
Producer<Producer<Object>> opp = (Producer<Producer<Object>>)(Producer) spp;
But it's fugly and theoretically incorrect. You should use Producer<Producer<?>> (or Producer<? extends Producer<?>>), but if you really can't, I'd advise you to make a wrapper instead.
class CovariantProducer<T> implements Producer<T> {
private final Producer<? extends T> backing;
public CovariantProducer(Producer<? extends T> backing) {
this.backing = backing;
}
#Override
public T next(){ return backing.next(); }
}
// Usage:
Producer<String> sp = ...;
Producer<Object> op = new CovariantProducer<Object>(sp);
final Producer<Producer<String>> spp = ...;
Producer<Producer<Object>> opp = new Producer<Producer<Object>>() {
#Override
public Producer<Object> next() {
return new CovariantProducer<Object>(spp.next());
}
};
Somewhat more overhead, but this way you don't have to rape the type system, and the stuff that really doesn't work doesn't look like it works, either.
Edit: You could also do a special case of your cast method:
#SuppressWarnings("unchecked")
public static <T> Producer<Producer<T>> castMetaProducer(Producer<? extends Producer<? extends T>> producer){
return (Producer<Producer<T>>) producer;
}
However, if you're gonna want to turn a Producer<Producer<Producer<String>>> into a Producer<Producer<Producer<Object>>>, you'd have to add another method for that, and so on. Since this strictly speaking is incorrect usage of the type system, it's not very strange it's inconvenient to work this way.
Java does not provide any way to specify that a generic type should be covariant (or contravariant). In your case, if I can cast from a Producer<Producer<A>>, to a Producer<Producer<A>>, then I can do this:
Producer<Producer<Object>> objProducerProducer = cast(Producer<Producer<A>>);
Producer<Object> objProducer = objProducerProducer.produce()
But of course, objProducerProducer is actually producing Producer<A> objects. Java can't cast these to Producer<Object> automatically, that's just how it goes. Your explicit cast static method works because you are requiring <? extends T>. The generics don't extend each other. I guess what you want is implicit conversions that are integrated with the generics system, which is a long leap from what we have.
Edit: to clarify, yes, in your case, it's safe to treat a Producer<A> as a Producer<Object>, but this is knowledge that's not available to the generics system.
What you implemented in you Types class isn't a cast, it's only a convenient way to hide compiler warnings (and a convenient way to fool co-workers I guess). Therefore, instead of "casting" your producer, I'd rather suggest to change the implementation of Producer to something like this (if possible):
class Producer {
<T> T produce(Class<T> cls) {
Object o;
// do something, e.g.
// o = cls.newInstance();
// perfectly type safe cast
return cls.cast(o);
}
}
Producer p = new Producer();
A a = p.produce(A.class);
Note: It might not help you with your exact problem, but maybe it points you towards the right direction.
This is something that should be handled with wildcards at use site in Java.
However you can do it explicitly with a proxy in Java.
public static <T> Iterator<T> clean(final Iterator<? extends T> orig) {
return new Iterator<T>() {
public boolean hasNext() {
return orig.hasNext();
}
public T next() {
return orig.next();
}
public void remove() {
return orig.remove();
}
};
}

Categories