Java Type Wildcarding - java

(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.

Related

Java Function interface with bounded wildcard

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>

How to grok bounded wildcards in Java?

In the wikipedia article about co- and contravariance there is an example use case and then an explanatory sentence describing what the type declaration means. I find this extremely useful. After reading the explanation a few times, I feel that I understand what it says.
<T extends Comparable<? super T>> T max(Collection<T> coll);
The bounded wildcard ? super T conveys the information that max calls only contravariant methods from the Comparable interface.
Can somebody explain in a similar language, what the type declaration on the of the andThen() function in the java.util.function.Consumer #FunctionalInterface means:
public interface Consumer<T> {
void accept(T t);
default Consumer<T> andThen(Consumer<? super T> after) {
e.g.
The bounded wildcard ? super T conveys the information that andThen .... ?
And I have a secondary question: How can I find out myself, what such a type declaration means? E.g. in first example above from the java.util.Collections util class: How are the type bounds of a class - T - able to convey information about what the methods of T are doing? Can anybody point me to the relevant paragraphs in the Java language specification for this?
Possible answer to the first question:
public interface Consumer<T> {
void accept(T t);
default Consumer<T> andThen(Consumer<? super T> after) {
The bounded wildcard ? super T conveys the information that andThen takes Consumers of T or supertypes of T, aka. contravariant Consumers, as arguments.
Possible answer to the secondary question: https://stackoverflow.com/a/2501513
Basically - completely independent of generics (!) - method return return types are inherently "covariant" (assumed to be "producers") in the Java language. If overriding a method in a child class, you can always declare a more specific return type.
Method arguments are of course also "covariant" - you can only pass more specific objects than the method signature specifies. But on subclasses, although the method is technically not overriden for non-parametric arguments - adhering to the Liskov_substitution_principle - it often makes sense to declare "contravariant" argument types in child classes, which - if the name and other arguments are equal - "overloads" the methods in the parent class. "Static" (reference-type-governed) method dispatch will then ensure that the (less specific) child method is called wins. Method arguments are assumed to be "consumed" and then PECS applies. Anyhow, for generic parameters, bridge methods are generated and it is all a bit more hairy. But we will get there.

Difference between List<T> and List<? extends T> [duplicate]

Given the following example (using JUnit with Hamcrest matchers):
Map<String, Class<? extends Serializable>> expected = null;
Map<String, Class<java.util.Date>> result = null;
assertThat(result, is(expected));
This does not compile with the JUnit assertThat method signature of:
public static <T> void assertThat(T actual, Matcher<T> matcher)
The compiler error message is:
Error:Error:line (102)cannot find symbol method
assertThat(java.util.Map<java.lang.String,java.lang.Class<java.util.Date>>,
org.hamcrest.Matcher<java.util.Map<java.lang.String,java.lang.Class
<? extends java.io.Serializable>>>)
However, if I change the assertThat method signature to:
public static <T> void assertThat(T result, Matcher<? extends T> matcher)
Then the compilation works.
So three questions:
Why exactly doesn't the current version compile? Although I vaguely understand the covariance issues here, I certainly couldn't explain it if I had to.
Is there any downside in changing the assertThat method to Matcher<? extends T>? Are there other cases that would break if you did that?
Is there any point to the genericizing of the assertThat method in JUnit? The Matcher class doesn't seem to require it, since JUnit calls the matches method, which is not typed with any generic, and just looks like an attempt to force a type safety which doesn't do anything, as the Matcher will just not in fact match, and the test will fail regardless. No unsafe operations involved (or so it seems).
For reference, here is the JUnit implementation of assertThat:
public static <T> void assertThat(T actual, Matcher<T> matcher) {
assertThat("", actual, matcher);
}
public static <T> void assertThat(String reason, T actual, Matcher<T> matcher) {
if (!matcher.matches(actual)) {
Description description = new StringDescription();
description.appendText(reason);
description.appendText("\nExpected: ");
matcher.describeTo(description);
description
.appendText("\n got: ")
.appendValue(actual)
.appendText("\n");
throw new java.lang.AssertionError(description.toString());
}
}
First - I have to direct you to http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html -- she does an amazing job.
The basic idea is that you use
<T extends SomeClass>
when the actual parameter can be SomeClass or any subtype of it.
In your example,
Map<String, Class<? extends Serializable>> expected = null;
Map<String, Class<java.util.Date>> result = null;
assertThat(result, is(expected));
You're saying that expected can contain Class objects that represent any class that implements Serializable. Your result map says it can only hold Date class objects.
When you pass in result, you're setting T to exactly Map of String to Date class objects, which doesn't match Map of String to anything that's Serializable.
One thing to check -- are you sure you want Class<Date> and not Date? A map of String to Class<Date> doesn't sound terribly useful in general (all it can hold is Date.class as values rather than instances of Date)
As for genericizing assertThat, the idea is that the method can ensure that a Matcher that fits the result type is passed in.
Thanks to everyone who answered the question, it really helped clarify things for me. In the end Scott Stanchfield's answer got the closest to how I ended up understanding it, but since I didn't understand him when he first wrote it, I am trying to restate the problem so that hopefully someone else will benefit.
I'm going to restate the question in terms of List, since it has only one generic parameter and that will make it easier to understand.
The purpose of the parametrized class (such as List<Date> or Map<K, V> as in the example) is to force a downcast and to have the compiler guarantee that this is safe (no runtime exceptions).
Consider the case of List. The essence of my question is why a method that takes a type T and a List won't accept a List of something further down the chain of inheritance than T. Consider this contrived example:
List<java.util.Date> dateList = new ArrayList<java.util.Date>();
Serializable s = new String();
addGeneric(s, dateList);
....
private <T> void addGeneric(T element, List<T> list) {
list.add(element);
}
This will not compile, because the list parameter is a list of dates, not a list of strings. Generics would not be very useful if this did compile.
The same thing applies to a Map<String, Class<? extends Serializable>> It is not the same thing as a Map<String, Class<java.util.Date>>. They are not covariant, so if I wanted to take a value from the map containing date classes and put it into the map containing serializable elements, that is fine, but a method signature that says:
private <T> void genericAdd(T value, List<T> list)
Wants to be able to do both:
T x = list.get(0);
and
list.add(value);
In this case, even though the junit method doesn't actually care about these things, the method signature requires the covariance, which it is not getting, therefore it does not compile.
On the second question,
Matcher<? extends T>
Would have the downside of really accepting anything when T is an Object, which is not the APIs intent. The intent is to statically ensure that the matcher matches the actual object, and there is no way to exclude Object from that calculation.
The answer to the third question is that nothing would be lost, in terms of unchecked functionality (there would be no unsafe typecasting within the JUnit API if this method was not genericized), but they are trying to accomplish something else - statically ensure that the two parameters are likely to match.
EDIT (after further contemplation and experience):
One of the big issues with the assertThat method signature is attempts to equate a variable T with a generic parameter of T. That doesn't work, because they are not covariant. So for example you may have a T which is a List<String> but then pass a match that the compiler works out to Matcher<ArrayList<T>>. Now if it wasn't a type parameter, things would be fine, because List and ArrayList are covariant, but since Generics, as far as the compiler is concerned require ArrayList, it can't tolerate a List for reasons that I hope are clear from the above.
It boils down to:
Class<? extends Serializable> c1 = null;
Class<java.util.Date> d1 = null;
c1 = d1; // compiles
d1 = c1; // wont compile - would require cast to Date
You can see the Class reference c1 could contain a Long instance (since the underlying object at a given time could have been List<Long>), but obviously cannot be cast to a Date since there is no guarantee that the "unknown" class was Date. It is not typsesafe, so the compiler disallows it.
However, if we introduce some other object, say List (in your example this object is Matcher), then the following becomes true:
List<Class<? extends Serializable>> l1 = null;
List<Class<java.util.Date>> l2 = null;
l1 = l2; // wont compile
l2 = l1; // wont compile
...However, if the type of the List becomes ? extends T instead of T....
List<? extends Class<? extends Serializable>> l1 = null;
List<? extends Class<java.util.Date>> l2 = null;
l1 = l2; // compiles
l2 = l1; // won't compile
I think by changing Matcher<T> to Matcher<? extends T>, you are basically introducing the scenario similar to assigning l1 = l2;
It's still very confusing having nested wildcards, but hopefully that makes sense as to why it helps to understand generics by looking at how you can assign generic references to each other. It's also further confusing since the compiler is inferring the type of T when you make the function call (you are not explicitly telling it was T is).
The reason your original code doesn't compile is that <? extends Serializable> does not mean, "any class that extends Serializable," but "some unknown but specific class that extends Serializable."
For example, given the code as written, it is perfectly valid to assign new TreeMap<String, Long.class>() to expected. If the compiler allowed the code to compile, the assertThat() would presumably break because it would expect Date objects instead of the Long objects it finds in the map.
One way for me to understand wildcards is to think that the wildcard isn't specifying the type of the possible objects that given generic reference can "have", but the type of other generic references that it is is compatible with (this may sound confusing...) As such, the first answer is very misleading in it's wording.
In other words, List<? extends Serializable> means you can assign that reference to other Lists where the type is some unknown type which is or a subclass of Serializable. DO NOT think of it in terms of A SINGLE LIST being able to hold subclasses of Serializable (because that is incorrect semantics and leads to a misunderstanding of Generics).
I know this is an old question but I want to share an example that I think explains bounded wildcards pretty well. java.util.Collections offers this method:
public static <T> void sort(List<T> list, Comparator<? super T> c) {
list.sort(c);
}
If we have a List of T, the List can, of course, contain instances of types that extend T. If the List contains Animals, the List can contain both Dogs and Cats (both Animals). Dogs have a property "woofVolume" and Cats have a property "meowVolume." While we might like to sort based upon these properties particular to subclasses of T, how can we expect this method to do that? A limitation of Comparator is that it can compare only two things of only one type (T). So, requiring simply a Comparator<T> would make this method usable. But, the creator of this method recognized that if something is a T, then it is also an instance of the superclasses of T. Therefore, he allows us to use a Comparator of T or any superclass of T, i.e. ? super T.
what if you use
Map<String, ? extends Class<? extends Serializable>> expected = null;

Java What is difference between generic method and a method object as a parameter?

What are advantage between a generic method and a method just accepts Object? How does it ensures type safety?
For example: What difference does it make when define my interface in either of the form mentioned in below code snippet?
public interface MyInterface {
public <MT> String myMethod(MT t);
}
OR
public interface MyInterface {
public String myMethod(Object t);
}
In my opinion Generic methods are advantageous only when we type bound around it.. for example type parameter should of Serializable class like. Otherwise it doesn't make sense.. looking for more insight
public interface MyInterface {
public <MT extends Serializable> String myMethod(MT t);
}
A method is usually made generic to ensure that two arguments are compatible with each other, or to return a value whose type depends on the generic type of the method.
For example,
public static <T> void sort(List<T> list, Comparator<? super T> c)
makes sure the type of the list and the type of the comparator are compatible, which wouldn't necessary be the same if the signature was
public static void sort(List list, Comparator c)
In the following example, the returned value's type depends on the generic type of the method:
public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> coll)
which allows doing:
List<Integer> intList = ...;
Integer min = Collections.min(intList);
If the method was
public static Comparable T min(Collection coll)
you would have to do
Integer min = (Integer) Collections.min(intList);
and you wouldn't have any warning from the compiler if you changed the code to
Long min = (Long) Collections.min(intList);
It can be also nice to see what it means from the compile/runtime point of view.
If you use generics, then the compiler generates the necessary code during compilation and you would't do runtime casting on your relevant objects and/or type checking.
On the other hand, if you use only the Object class as a generic type, you would probably end up having slightly less code (since the compiler wouldn't be generating anything) but you would need to take care of runtime type safety and casting by yourself.
You are partially correct. Generic method and method as a object look like same in some context but the major difference is how compiler handles both
For the object as params type conversion is done based on the typecasting basically it is being handled runtime but for the generic type compile time only it is being handled.
Compile time handling is much better than the run time one. So the generic method is good to use as compare to object as a parameter in your context
Generic method restricts the type of parameter that can be passed to the method. That brings in more cohesive code which limits the input that it can work on, and thus can be reasonably assumed to have certain features.
For e.g
public interface MyInterface {
public [MT extends BaseClass] String myMethod(MT t);
}
Here you always know that all the methods that are applicable for BaseClass are applicable to t in this method.

generic methods and wildcards

What are the differences between the following three signatures?
static <T> void foo(List<T>, Comparator<? super T>);
static <T> void bar(List<? extends T>, Comparator<T> );
static <T> void baz(List<? extends T>, Comparator<? super T>);
I know what extends and super mean in Generics. My question is whether there is a difference between foo, bar and baz. Should I make one of the parameters invariant and the other one variant in the appropriate direction, or should I make both of them variant? Does it make a difference?
PECS - Producer extends, consumer super.
To explain this "rule":
extends means the genericized object produces elements of the type. When it's a collection, it means you can only take elements from the collection, but not put them in. The comparator
super means the object consumes objects of the selected type. So you can add to the collection, but not read from it.
the lack of extends and super means you can do both for the exact type specified.
Regarding the Comparator, I don't think it makes any difference. Normally, it would be <? super T> because you the comparator consumes objects, but in all three cases you can safely invoke Collections.sort(list, comparator); (the signature of which is <? super T>)
The only difference is whether T represents the type parameter of the List, the Comparator, or something in between.
As far as the caller is concerned, the three method signatures are equivalent, i.e. whenever one of them can be used, the others can be used as well.
For the method implementation foo is probably most convenient, as it allows modifying the list without needing an additional capture conversion, which would require delegating to a helper method.
I believe that ? extends T means that the List may be generic of any type that is derived from T, whereas List<T> can only be a List of T and not any of its derived classes.

Categories

Resources