I've actually got this working from this example:
static <K,V extends Comparable<? super V>>
List<Entry<K, V>> entriesSortedByValues(Map<K,V> map) {
List<Entry<K,V>> sortedEntries = new ArrayList<Entry<K,V>>(map.entrySet());
Collections.sort(sortedEntries,
new Comparator<Entry<K,V>>() {
#Override
public int compare(Entry<K,V> e1, Entry<K,V> e2) {
return e2.getValue().compareTo(e1.getValue());
}
}
);
return sortedEntries;
}
I found it on this site; here.
Now, I have implemented this code and it does work. I understand what's happening, for the most part. The only part of the code I don't fully understand is within the method header, specifically:
static <K,V extends Comparable<? super V>>
If anybody could explain this part of the code to me, I'd be very grateful. Specifically why I should use super in this context.
I'm fairly new to Java so trying to get a good understanding of using different techniques rather than just throwing them into my code without really understanding what's happening.
Note: I would have commented on the original answer but I can only leave comments if I have a reputation over 50. I hope I'm not breaking any rules by posting like this!
This line is making the method generic. You can have a generic type in either the class header or in the method declaration. In this case, the method declaration.
static <K,V extends Comparable<? super V>>
declares a generic type K that is unbounded. This means it can be any subclass of type Object. Then it declares a second type, V, that MUST implement the Comparable interface. The Comparable implementation is also typed, and the method adds a bound to that, stating that the Comparable class should be able to compare to anything of a supertype of generic type V.
Extra Reading
Have a look into Java Generics
The idea is that V is comparable to at least other Vs, but may be comparable to other types as well -- that is, comparable to anything of a supertype of V.
Related
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>
I understand upper bound clearly, but don't fully understand lower bound. As for example I have this code:
public class Main<T> {
private T t;
public Main(T t) {
this.t = t;
}
private static class Base {}
public static void main(String[] args) {
Main<? super Base> main = new Main<>(new StringBuilder());
System.out.println(main.t.getClass());
}
}
Why there is no error during compile despite of StringBuilder isn't super class of Base. As I thought it would be illegal to provide type which is irrelevant (I know that it's impossible to assign non child class to t after type inference). Also it works with collections, does it means that collection could possibly store no child, no super class of Base? Please do not link me to PECS questions, I have read them a lot.
Edit: I saw it a little late that #markspace's answer is nearly the same and was posted before this. I am only retaining this here due different styles of explanation, that is all.
This should be due to the diamond operator <> due to which automatic inference happens based on the most possible route, in this case the constructor parameter.
I could not locate the official description of the diamond operator, but various sources describe it to the effect - the Java compiler does a type inference when given the diamond operator feature determines the most suitable constructor declaration that matches the invocation.
If you change your declaration to GenericsSuper<? super Base> main = new GenericsSuper<StringBuilder>(new StringBuilder()) you will get your expected error.
Without this explicit declaration, <> leads to <Object> due to the super restriction, and consequently anything is allowed, because:
The code in GenericsSuper has no problem with StringBuilder. It just wants T.
Base has a common super with StringBuilder in Object.
I'm going to add this as an actual answer.
I think <T> here is Object, which is a legal super type of both Base and StringBuilder. The way you are doing this / thinking about this is flawed, basically. Check out the answer to this question (ignore the duplicate text for PECS):
Difference between <? super T> and <? extends T> in Java
Notice the examples that the accepted answer gives, especially the one with <Object>:
List<? super Integer> foo3 = new ArrayList<Integer>(); // Integer is a "superclass" of Integer (in this context)
List<? super Integer> foo3 = new ArrayList<Number>(); // Number is a superclass of Integer
List<? super Integer> foo3 = new ArrayList<Object>(); // Object is a superclass of Integer
Since you're allowing the diamond operator to "figure out" the type of T, it "figures out" that Object works and uses that. Untested, but check if this also compiles:
Main<? super Base> main = new Main<Object>(new StringBuilder());
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;
I have a question about this method from java.util.Collections:
public class Collections {
public static <T> void copy(List<? super T> dest, List<? extends T> src) {
for (int i=0; i<src.size();i++)
dest.set(i,src.get(i));
}
}
I understand how <? super T> works, however, I don't understand why the first parameter is List<? super T> instead of List<T>. I think it's useless in this situation.
Using List<T> should work as well, shouldn't it?
Could you give me some examples to understand it if possible, please?
Thanks.
No, it makes sense. For example, consider this situation:
T is InputStream
dest is a List<Object>
src is a List<FileInputStream>
That works absolutely fine. Of course, you could make T either Object or FileInputStream in this situation - but imagine you were calling this from a method with a signature of:
public void doSomething(List<? super InputStream> streams) {
// I want to use copy in here for some reason
}
You don't know it's a List<InputStream> - only that it's a List<? super InputStream>. If the dest parameter in copy were just List<T>, we'd be stuck... but with the way it is written, we're fine.
It also makes sense in terms of what we require from the destination list - we just need to be able to set values of T within it. Likewise all we require of the source list is that we can get values of T from it. <? super T> and <? extends T> express those requirements well.
If you break it down in why the List is being used it will be a bit more clear.
When a method intends to populate a list, you could restrict it to use a specific type T, however often you might want to be less restrictive.
For example, lets say you have a method populateWithStudents(List<Student> list)
And you have Student extend Person
This means that you can't use that method with a List<Person> to fill it with Student objects, even though Student extends Person.
So if on the other hand we would like to allow that we change it to populateWithStudents(List<? super Student> list). This way we're saying that as long as we can fit a Student in the list, no matter if it is a list of Student objects, or a list of any of its superclasses, it is allowed.
This is not just when populating obviously, but this example helps understand the concept.
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.