I'm trying to use java.util.Function object as an input to a library class.
Function<? extends MyEntity, List> mapper;
public MyLibraryClass(Function<? extends MyEntity,List> mapper) {
...
}
public void aMethod(ClassExtendsMyEntity e) {
mapper.apply(e);
}
The line mapper.apply(e) doesn't compile.
If I change to use ? super instead of ? extends, then the fail will be in the client using this library in the following code:
Function<ClassExtendsMyEntity, List> mapper = e -> e.getListObjects();
new MyLibraryClass(mapper);
Can anyone help explain why getting this issue and if there is a way to get this working?
Function<? extends MyEntity,List> mapper;
This does not say "any subclass of MyEntity can be passed to mapper". It says "there exists some subclass of MyEntity that can be passed to mapper". It might be ClassExtendsMyEntity, it might be MyEntity itself, or it might be some crazy class that you've never even heard of.
Function<T, S> provides one function: S apply(T arg). Since your argument type is ? extends MyEntity, the only valid argument you can pass to mapper.apply is a value which is of every subtype of MyEntity at once, and there is no value that satisfies that condition.
Put more technically, the first argument of Function<T, S> is, in principle, contravariant, so using the covariant ? extends T annotation makes little sense on it.
Depending on what you want, there are two solutions. If your function works for any MyEntity, then you should simply write Function<MyEntity, List> and forgo the generics/wildcards altogether. On the other hand, if you want MyLibraryClass to support only one subtype, but a subtype that you know about, then you need to make that a generic argument to MyLibraryClass.
public class MyLibraryClass<T extends MyEntity> {
Function<? super T, List> mapper;
public MyLibraryClass(Function<? super T, List> mapper) {
...
}
public void aMethod(T e) {
mapper.apply(e);
}
}
Again, the first type argument of Function is, in principle, contravariant, so we should use ? super T to bound it by our type argument T. That means that if I have a MyLibraryClass<ClassExtendsMyEntity>, the function inside that might be a Function<ClassExtendsMyEntity, List>, or a Function<MyEntity, List>, or a Function<Object, List>, since all of those support ClassExtendsMyEntity arguments. For more on the reasoning behind that, see What is PECS.
The declaration Function<? extends MyEntity,List> mapper means:
mapper expects an argument of some type X which is a subtype of MyEntity. The problem is, it doesn't tell what type it is.
And therefore the compiler can't verify if your call passing an instance of type ClassExtendsMyEntity is valid. After all X might be SomeOtherClassExtendingMyEntity.
In order to fix this just make the function type Function<MyEntity,List>
Related
Assume I have a class and a method such as this:
class MyClass<T> {
void doStuff(Wrapper<T> wrapper) {
//impl.
}
}
Generic bounds of the parameter "wrapper" can be modified to Wrapper<? extends T> to make the method accept subtypes of T, and Wrapper<? super T> to accept super types. However, is there a way to modify MyClass such that it accepts both sub and super types of T (not any type), and there is only one method name? (there can be overloads)
I could simply go with Wrapper<?> of course, but "accept anything" is not the same as "accept something that's in the class hierarchy for T". I could also make 2 separate methods, one with <? super T> and one with <? extends T>, but then these methods would need different names, since the signature is the same after erasure.
Note: Please consider this a question out of curiosity.
You could try the following
<S extends T> void doStuff(Wrapper<? super S> wrapper)
but would need to double check this satisfies your requirements.
question about Wildcard
Example:Student extends Person
Person person = new Person();
Student student = new Student();
List<? super Student> list = new ArrayList<>();
list.add(student); // success
list.add(person); // compile error
List<? extends Person> list2 = new ArrayList<>();
list2.add(person); // compile error
list2.add(student);// compile error
I have read the answer below a question "capture#1-of ? extends Object is not applicable"
You are using generic wildcard. You cannot perform add operation as class type is not determinate. You cannot add/put anything(except null) -- Aniket Thakur
Official doc:The wildcard is never used as a type argument for a generic method invocation, a generic class instance creation, or a supertype
But why could list.add(student) compile successfully ?
Design of java.util.function.Function
public interface Function<T, R>{
//...
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
}
Why before is designed to Function<? super V, ? extends T> rather than Function<V,T> when the type of return is Function<V,R> and type of the input is V ? (It still can pass compile and use flexibly)
To understand these questions, you have to understand how generics work with subtyping (which is explicitly denoted in Java using the extends keyword). Andreas mentioned the PECS rules, which are their representations in Java.
First of all, I want to point out that the codes above can be corrected by a simple cast
ArrayList<? super Student> list = new ArrayList<>();
list.add(new Student());
ArrayList<Person> a = (ArrayList<Person>) list; // a covariance
a.add(new Person());
And compiles & runs well (rather than raising any exceptions)
The reason is simple, when we have a consumer (which takes some objects and consume them, such as the add method), we expect it to take objects of type no more than(superclasses) the type T we specified, because the process of consuming needs possibly any member(variables, methods etc.) of the type it wants, and we want to ensure that type T satisfy all the members the consumer requires.
On the contrary, a producer, which produces objects for us (like the get method), has to supply objects of type no less than the specified type T so that we can access any member that T has on the object produced.
These two are closely related to subtyping forms called covariance and contravariance
As for the second question, you can refer to the implementation of Consumer<T> as well (which is somewhat simpler):
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
the reason why we need this ? super T is that: when we are combining two Consumers using the method andThen, suppose that the former Consumer takes an object of type T, we expect the later to take a object of type no more than T so it would not try to access any member that T doesn't have.
Therefore, rather than simply writing Consumer<T> after but Consumer<? super T> after, we allow the former consumer (of type T) to be combined with a consumer that takes an object not exactly of type T, but maybe smaller then T, by the convenience of covariance. That makes the following codes sound:
Consumer<Student> stu = (student) -> {};
Consumer<Person> per = (person) -> {};
stu.andThen(per);
The compose method of type Function also applies, by the same consideration.
IMO This is probably the most complex concept in vanilla Java. So let's break this down a bit. I'll start with your second question.
Function<T, R> takes an instance t of type T and returns an instance r of type R. With inheritance that means that you could supply an instance foo of type Foo if Foo extends T and similarly return bar of type Bar if Bar extends R.
As a library maintainer who wants to write a flexible generic method, it's hard, and actually impossible, to know in advance all the classes which might be used with this method which extend T and R. So how are we going to write a method that handles them? Further, the fact that these instances have types which extend the base class is none of our concern.
This is where the wildcard comes in. During the method call we say that you can use any class which meets the envelope of the required class. For the method in question, we have two different wildcards using upper and lower bounded generic type parameters:
public interface Function<T, R>{
default <V> Function<V, R> compose(Function<? super V, ? extends T> before)
Lets now say that we want to take advantage of this method... for the example lets define some basic classes:
class Animal{}
class Dog extends Animal{}
class Fruit{}
class Apple extends Fruit{}
class Fish{}
class Tuna extends Fish{}
Imagine our function and transformation is defined as below:
Function<Animal, Apple> base = ...;
Function<Fish, Animal> transformation = ...;
We can combine these functions using compose to create a new function:
Function<Fish, Apple> composed = base.compose(transformation);
This is all fine and dandy, but now imagine that in the desired output function we actually only want to use Tuna as the input. If we did not use the lower-bounded ? super V as the input type parameter for the Function we pass to compose then we would get a compiler error:
default <V> Function<V, R> compose(Function<V, ? extends T> before)
...
Function<Tuna, Apple> composed = base.compose(transformation);
> Incompatible types:
> Found: Function<Fish, Apple>, required: Function<Tuna, Apple>
This happens because the return type for the call to compose specifies V as Tuna while transformation on the other hand specifies its "V" as Fish. So now when we try to pass transformation to compose the compiler requires transformation to accept a Tuna as its V and of course Tuna does not identically match Fish.
On the other hand, the original version of the code (? super V) allows us to treat V as a lower bound (i.e. it allows "contravariance" vs. "invariance" over V). Instead of encountering a mismatch between Tuna and Fish the compiler is able to successfully apply the lower bound check ? super V which evaluates to Fish super Tuna, which is true since Tuna extends Fish.
For the other case, imagine our call is defined as:
Function<Animal, Apple> base = ...;
Function<Fish, Dog> transformation = ...;
Function<Fish, Apple> composed = base.compose(transformation);
If we did not have the wildcard ? extends T then we would get another error:
default <V> Function<V, R> compose(Function<? super V, T> before)
Function<Fish, Apple> composed = base.compose(transformation);
// error converting transformation from
// Function<Fish, Dog> to Function<Fish, Animal>
The wildcard ? extends T allows this to work as T is resolved to Animal and the wildcard resolves to Dog, which can satisfy the constraint Dog extends Animal.
For your first question; these bounds really only work in the context of a method call. During the course of the method, the wildcard will be resolved to an actual type, just as ? super V was resolved to Fish and ? extends T was resolved to Dog. Without the information from the generic signature, we would have no way for the compiler to know what class can be used on the type's methods, and therefore none are allowed.
(For the purposes of this post, lets set aside java.util.Observable)
I was experimenting around with generics, and then wildcard types. The aim was to create a type-generic observable cache with deltas provided to the observers. Where this starts to go off the rails is I wanted to allow more generic observers to be used than the one specified in the Observable, e.g. Observer<Object> or some other common superclass.
I've since concluded that this is overly complex for my use case, but the problem itself continues to bother me since I clearly don't understand how to use type wildcarding properly.
So if we start with a simple observer interface:
public interface Observer<T> {
public void notifyChange(ChangeHolder<T> change);
}
And the associated ChangeHolder, in a full implementation this would be more complex, providing lists of added / updated / deleted objects, but this is sufficient to demonstrate the issue
public interface ChangeHolder<T> {
T getChange();
}
So with the Observer defined, I tried to implement the Observable abstract class:
public abstract class Observable<T> {
private Set<Observer<? super T>> observers = new HashSet<>();
public void addObserver(Observer<? super T> obs){
observers.add(obs);
}
public void change(ChangeHolder<T> changes){
for(Observer<? super T> obs : observers){
obs.notifyChange(changes);
}
}
}
And with that I could define some object caches, by declaring something like class TreeCache extends ObservableCache<Tree>, (From this point on I'll use Tree as an example class to be used as a T, assume it to be a simple POJO extending only from Object) and pass ChangeHolder<Tree> objects to TreeCache.change() when necessary. Unfortunately the compiler disagrees:
The method notifyChange(ChangeHolder<capture#2-of ? super T>) in the type Observer<capture#2-of ? super T> is not applicable for the arguments (ChangeHolder<T>)
Which is where my understanding ends.
Without the ChangeHolder class (if my notifyChange method just took a plain T instead) it works just fine since it's perfectly legal to pass a Tree to Observer.notifyChange(Object).
I inferred that I should be able to do the same with the ChangeHolder - ChangeHolder<T> should satisfy notifyChange(ChangeHolder<? super T>) in the same way that T satisfies notifyChange(? super T) but clearly I am misunderstanding something?
There is no wildcard in the signature notifyChange(ChangeHolder<T> change). Therefore the generic type of the passed argument must exactly match the generic type of the Observer instance.
Observer<? super T> means an Observer of some unknown type that is a supertype of T. Since the generic type of obs may not exactly match the generic type of changes, the notifyChange method is not applicable.
There are two possible fixes:
Change the signature to notifyChange(ChangeHolder<? extends T> change) so that the method works for subtypes.
Get rid of the wildcards everywhere, so that you have just <T> instead.
I prefer solution 1, as it is a good idea for signatures to be as general as possible.
I want to define a method that defines its types like this:
List<R> toList(JsArray<T> array)
such that T is bounded such that it is both:
T extends SomeClass, and
T extends R
I've tried things like this, to no avail:
<R, T extends R & SomeClass> List<R> toList(JsArray<T> array)
(For the curious, this is to be able to use GWT Overlay Types with Interfaces)
How about this?
<T extends SomeClass> List<? super T> toList(JsArray<T> array)
EDIT:
I think I see your use case. From comments, you want to specify the return type so you don't have an unchecked cast.
But you don't actually pass anything in to tell the method what to create. Since I could always call toList() with R = T, the only thing you could do that always works (for all R super T) is to return a List<T>, which makes the R parameter unnecessary... but that's not what you want.
You have to pass something in to tell the method what kind of object to instantiate. Usually we could to that like:
<R, T extends SomeClass> List<R> toList(JsArray<T> array, Class<R> cls)
and call it like
toList(arrayIHave, WhatIWant.class)
Now this will work, but you will complain that it has error conditions, because the "T extends R" constraint isn't captured. But really, even if you add the constraint in, you'll still have error conditions.
I can use an arbitrary interface for R by making a T that extends SomeClass and implements R. There is no way you can meaningfully instantiate an arbitrary interface, so for many R,T pairs that satisfy your constraints, you will have to return null or throw an exception or something.
No doubt there is some rule that dictates which R you will return, but there is no way to even think about specifying generic constraints that capture that rule, so there will be an unchecked conversion somewhere. If you use a signature like this, at least you can put it inside the method instead of having warnings or annotations everywhere you use it.
I fear this does not work.
The correct syntax would be
<R, T extends R & SomeClass> List<R> toList(JsArray<T> array)
But this will give you the following error message
Cannot specify any additional bound SomeClass when first bound is a type parameter
I do not see how you could make it work to enforce both constraints.
<D extends com.j256.ormlite.dao.Dao<T,?>,T> D getDao(Class<T> clazz)
I am not able to understand above statement
getDao(Class clazz) returns D
D having following constraints
D extends com.j256.ormlite.dao.Dao<T,?>
and extra ,T i am not able to understand.
Could you please explain it ?
This method has two type parameters, D and T, with D having an additional extends constraint, depending on T. Don't get confused by this <T,?>,T syntax; the ,T does not belong to the constraint, but is the second parameter, telling Java that T is not the name of a concrete class.
If you add a space or swap the parameters, it will be clearer. Here's a similar, but somewhat simpler example. These method signatures are all equivalent:
<D extends List<T>,T> D createListOf(Class<T> clazz) // your version
<D extends List<T>, T> D createListOf(Class<T> clazz) // extra space
<T, D extends List<T>> D createListOf(Class<T> clazz) // different order
Keep in mind that, even though it may seem apparent that T is another type parameter, this is not clear to Java. There could be an actual class named T, so we have to be explicit that T is a type parameter.
class T { ... } // this T is not what I want!
Conversely, type parameters are not restricted to single characters. You could also have a type parameter called Foo, or even String, if you want to utterly confuse your co-workers. Maybe that makes clear why the declaration of all type parameters using <...> is necessary.
// just a deterrent example; don't do this! String as parameter, not class
<String, Foo extends List<String>> Foo createListOf(Class<String> clazz)
This method will:
Return an object of type D
Where D is or extends com.j256.ormlite.dao.Dao, parametrized with an object of type T or extending/implementing T and an unknown type parameter
If given as argument a class of type T
It uses a lot of generic abstraction, which is not surprising given it delivers a DAO (Data Access Object).