While studying up on Java8 Streams, I came across the following code snippet:
Predicate<? super String> predicate = s -> s.startsWith("g");
Since the generic parameter is a lower bound, I figured this would not compile. The way I see it, if an Object is a supertype to a String, then passing in an Object type should break it, since Object does not have a startsWith() function. However, I was surprised to see it work without any problems.
Further yet, when I tweaked the predicate to take an upper bound:
<? extends String>,
it would not compile.
I thought I understood the meaning of upper and lower bounds, but obviously, I am missing something. Can anyone help explain why the lower bound works with this lambda?
Lambda argument type is exact, it cannot be ? super or ? extends. This is covered by JLS 15.27.3. Type of a Lambda Expression. It introduces the ground target type concept (which is basically the lambda type). Among other things it's stated that:
If T is a wildcard-parameterized functional interface type and the lambda expression is implicitly typed, then the ground target type is the non-wildcard parameterization (§9.9) of T.
Emphasis mine. So essentially when you write
Predicate<? super String> predicate = s -> s.startsWith("g");
Your lambda type is Predicate<String>. It's the same as:
Predicate<? super String> predicate = (Predicate<String>)(s -> s.startsWith("g"));
Or even
Predicate<String> pred = (Predicate<String>)(s -> s.startsWith("g"));
Predicate<? super String> predicate = pred;
Given the fact that lambdas type arguments are concrete, after that normal type conversion rules apply: Predicate<String> is a Predicate<? super String>, or Predicate<? extends String>. So both Predicate<? super String> and Predicate<? extends String> should compile. And both actually work for me on javac 8u25, 8u45, 8u71 as well as ecj 3.11.1.
I just tested it, the assignment itself compiles. What changes is whether you can actually call predicate.test().
Let's take a step back and use a placeholder GenericClass<T> for explanation. For type arguments, Foo extends Bar and Bar extends Baz.
Extends:
When you declare a GenericClass<? extends Bar>, you are saying "I don't know what its generic type argument actually is, but it's a subclass of Bar." The actual instance will always have a non-wildcard type argument, but in this part of the code you don't know what the value of it is. Now consider what that means for method invocations.
You know what you've actually got is either a GenericClass<Foo> or a GenericClass<Bar>. Consider a method that returns T. In the former case, its return type is Foo. In the latter, Bar. Either way, it's a subtype of Bar and is safe to assign to a Bar variable.
Consider a method that has a T parameter. If it's a GenericClass<Foo>, then passing it a Bar is an error - Bar is not a subtype of Foo.
So, with an upper bound you can use generic return values, but not generic method parameters.
Super:
When you declare a GenericClass<? super Bar>, you are saying "I don't know what its generic type argument actually is, but it's a superclass of Bar." Now consider what that means for method invocations.
You know what you've actually got is either a GenericClass<Bar> or a GenericClass<Baz>. Consider a method that returns T. In the former case, it returns Bar. In the latter, Baz. If it returns a Baz, then assigning that value to a Bar variable is an error. You don't know which it is, so you can't safely assume anything here.
Consider a method that has a T parameter. If it's a GenericClass<Bar>, then passing it a Bar is legal. If it's a GenericClass<Baz>, then passing it a Bar is still legal because Bar is a subtype of Baz.
So, with a lower bound you can use generic method parameters, but not generic return values.
In summary: <? extends T> means you can use generic return values but not parameters. <? super T> means you can use generic parameters but not return values. Predicate.test() has a generic parameter, so you need super.
Another thing to consider: The bounds stated by a wildcard are about the actual type argument of the object. Their consequences on the types that you can use with that object are the opposite. An upper bound wildcard (extends) is a lower bound on the types of variables you can assign return values to. A lower bound wildcard (super) is an upper bound on the types you can pass in as parameters. predicate.test(new Object()) will not compile because, with a lower bound of String, it will only accept subclasses of String.
More explanations: Guidelines for Wildcard Use.
Related
I have to perform and() on my business objects that implement Predicate<MoneyOperation>.
Code where problem occurs is the line with and() call:
Predicate<? super MoneyOperation> predicate =
new MoneyOperationDateWithRadioButtonsPredicate(newv,
thisDayRdBtn.getValue(), date);
filteredData.setPredicate(filteredData.getPredicate().and(predicate));
Error:
The method and(Predicate<? super capture#14-of ? super MoneyOperation>)
in the type Predicate<capture#14-of ? super MoneyOperation> is not applicable
for the arguments (Predicate<capture#15-of ? super MoneyOperation>)
Although when I pass predicate to setPredicate() without calling and() compiler does not raise any errors.
MoneyOperationDateWithRadioButtonsPredicate class:
public class MoneyOperationDateWithRadioButtonsPredicate extends MoneyOperationFieldPredicate<LocalDate> { ... }
MoneyOperationFieldPredicate class:
public abstract class MoneyOperationFieldPredicate<T> implements Predicate<MoneyOperation> { ... }
The problem here are the captures. Let's just see what those constrains mean:
Predicate<? super MoneyOperation> is a predicate that can take a MoneyOperation or maybe it's super class and returns a boolean.
This means it can be a Predicate<Object> that takes an Object and returns a boolean.
Now there is a potential problem:
Let's assume that MoneyOperation extends GenericOperation and implements SomeInterface.
The first Predicate<? super MoneyOperation> might in fact be a Predicate<GenericOperation> and the second Predicate<? super MoneyOperation> a Predicate<SomeInterface>. (The Java compiler can't tell)
Passing a MoneyOperation to both of them is fine, but combining them would require restricting it's type to Predicate<MoneyOperation>. While this would be fine for Predicate, it might not be for other cases.
And that's why Java doesn't allow this.
Use Predicate<MoneyOperation> if you know it is one.
It's just a limitation of the type system, because Java doesn't use the fact that Predicate has no producer methods (in the sense of PECS) to handle the type differently.
Consider two List<? super Integer> instances: you can't do list1.addAll(list2), for the same reason that you can't do predicate1.and(predicate2) here: that is guarding against the fact that list1 might be a List<Integer>, whereas list2 is a List<Object>: you shouldn't add Objects to a list that you expect only to contain Integers.
That is an actual problem for Lists, because List has producer methods (e.g. List.get(int)), i.e. methods that are meant to give you instances of a particular type. Predicate only has consumer methods (one, to be exact, Predicate.test<T>), so there is no situation in which a Predicate would give you an object of an unexpected type.
However, the compiler does not consider whether a class has no producer methods (or no consumer methods): it assumes both are present (indeed, they could be present on subclasses), and so it prevents you from doing this. Annoying, maybe, but that's how it is.
The easiest way is to construct a lambda to explicitly test the two predicates:
setPredicate(a -> predicate1.test(a) && predicate2.test(b))
You may be able to use this one weird trick:
setPredicate(Stream.of(predicate1, predicate2).map(a -> a).reduce(Predicate::and))
But I have never quite been satisfied whether that works by specification, or by quirk of implementation.
Many Java Stream interface methods use lower bounded wildcard in parameters
for example
Stream<T> filter(Predicate<? super T> pred)
and
void forEach(Consumer<? super T> action)
What is the advantage of using Predicate<? super T> over Predicate<T> here?
I understand, with Predicate<? super T> as parameter, Predicate object of T and super types can be passed into the method but i can't think of a situation where a Predicate of super type needed over the specific type?
For example if i have a Stream<Integer> i can pass Predicate<Integer>, Predicate<Number>, and Predicate<Object> objects as arguments to its filter method but why would anyone pass a Predicate<Object> over Predicate<Integer>? What is the advantage of using <? super T> here?
I assume you are aware of the PECS pattern, which is useful to adhere to when designing an API, even if no actual use case jumps into your eye. When we look at the final state of Java 8 and typical use cases, it’s tempting to think that this was not needed anymore. Not only do lambda expressions and method references infer the target type even when actually using a more general type, the improved type inference applies to method invocations as well. E.g.
Stream.of("a", "b", "c").filter(Predicate.isEqual("b"));
would require the filter(Predicate<? super T>) declaration with a pre-Java 8 compiler, as it would infer Predicate<Object> for the expression Predicate.isEqual("b"). But with Java 8, it would also work with Predicate<T> as parameter type, as the target type is used for nested method invocations as well.
We may consider that the development of the Stream API and the new Java language version/ compiler implementation happened at the same time, so there might have been a practical reason to use the PECS pattern at the beginning, while there never was a reason not to use that pattern. It still raises the flexibility when it comes to reusing existing predicate, function or consumer instances and even if that might not be much common, it doesn’t hurt.
Note that while, e.g. Stream.of(10, 12.5).filter(n -> n.doubleValue() >= 10), works, because the predicate may get an inferred non-denotable type suitable to process the Stream’s element type “#1 extends Number & Comparable<#1>”, you can not declare a variable of that type. If you want to store the predicate in a variable, you have to use, e.g.
Predicate<Number> name = n -> n.doubleValue()>=10;
Stream.of(10, 12.5).filter(name);
which only works, if filter has been declared as filter(Predicate<? super T> predicate).
Or you enforce a different element type for the Stream,
Predicate<Number> name = n -> n.doubleValue()>=10;
Stream.<Number>of(10, 12.5).filter(name);
which already demonstrates how omitting the ? super at the filter declaration may cause more verbosity on the caller’s side. Also, enforcing a more general element type may not be an option if the more specific type is needed in a later pipeline stage.
While existing function implementations are rare, there are some, e.g.
Stream.Builder<Number> b = Stream.builder();
IntStream.range(0, 10).boxed().forEach(b);
LongStream.range(0, 10).boxed().forEach(b);
Stream<Number> s = b.build();
wouldn’t work without the ? super in the forEach(Consumer<? super T> action) declaration.
A case you may encounter more often, is to have an existing Comparator implementation which you might want to pass to a sorted method of a Stream with a more specific element type, e.g,
Stream.of("FOO", "bar", "Baz")
.sorted(Collator.getInstance())
.forEachOrdered(System.out::println);
wouldn’t work without the ? super in the sorted(Comparator<? super T> comparator) declaration.
Consider the following code sample:
#SafeVarargs
public static <U> Object[] sortedCopy(Comparator<? super U> comparator, U... values) {
U[] copy = Arrays.copyOf(values, values.length);
Arrays.sort(copy, comparator);
return copy; //copy is implicitly cast to Object[] -> no heap pollution
}
public static <U> Object[] sortedCopy(U... values) {
return sortedCopy(Comparator.naturalOrder(), values); //why does this compile???
}
I would have expected the compiler to reject the line in sortedCopy(U...), with the following reasoning:
The return type of Comparator.naturalOrder() is Comparator<T>, where T is a generic type parameter of this method that must fulfill the constraint T extends Comparable<? super T>. Since the method does not accept any arguments, and its invocation in the above code does not explicitly specify a type for T (like Comparator.<U>naturalOrder(), which would not compile because U does not extend Comparable), T has to be inferred another way. The only way I can see to infer T is by the method signature of sortedCopy(Comparator<? super U>, U...). The compiler knows the type of values and can thus infer U, and in turn can also infer bounds for T, namely the bounded wildcard ? super U. But then, the compiler should realize that any ? super U can never meet the requirement for T specified by Comparator.naturalOrder(), which is T extends Comparable<? super T>, because U itself does not extend Comparable<? super U>, so any supertype of U cannot either.
What confuses me is that the compiler does generate an error when I change the signature from sortedCopy(U...) to sortedCopy(U[]). I suppose this has to do with the fact that, in the second case, U is present at runtime as the type of the array, whereas in the first case, it is not. But I still don't understand why that would make the method call in question valid, because:
As I understand it, a varargs parameter of a generic type is converted to an Object[] if the values passed to the method as vararg arguments are of a generic and therefore non-reifiable type, which, if I understand correctly, is the case in the above code because U from sortedCopy(U...) is non-reifiable. But even then, why does the compiler not realize that Object does not extend Comparable<? super Object>?
The previous argument talks about runtime types. However, we're still pre-compilation, so speculations about runtime-types should not even be relevant in this context, because, while U might not be present anymore at runtime, the compiler still knows it and should be able to check whether the equality constraints are fulfilled, regardless of whether the method parameter is an array or a vararg.
So why does the line in question from the above code sample still compile?
Beside that, I would also be grateful for feedback in case the #SafeVarargs annotation of the method sortedCopy(Comparator<? super U>, U...) is inappropriate. I believe it is, but I'm not confident about it.
Varargs can be a bit sneaky. What I'm seeing in my IDE is that it's regarding sortedCopy(U... values) as being a recursive method, meaning that it's not selecting the overloaded argument with a Comparator as its first argument.
If you change this from varargs to array parameters, and pass in an int[], you'd get the compilation failures that you would expect.
Error:(12, 16) no suitable method found for sortedCopy(java.util.Comparator<T>,U[])
method Foo.<U>sortedCopy(java.util.Comparator<? super U>,U[]) is not applicable
(inferred type does not conform to upper bound(s)
inferred: U
upper bound(s): java.lang.Comparable<? super U>,U,java.lang.Object)
method Foo.<U>sortedCopy(U[]) is not applicable
(cannot infer type-variable(s) U
(actual and formal argument lists differ in length))
Error:(18, 47) no suitable method found for sortedCopy(java.util.Comparator<T>,int[])
method Foo.<U>sortedCopy(java.util.Comparator<? super U>,U[]) is not applicable
(inference variable U has incompatible bounds
equality constraints: int
upper bounds: java.lang.Object)
method Foo.<U>sortedCopy(U[]) is not applicable
(cannot infer type-variable(s) U
(actual and formal argument lists differ in length))
If you pass in an Integer[], or if you pass in only the vararg form, you get only the first error.
There are rules around picking the most specific method available to the lexer. Specifically, you're getting burned by this rule:
A type S is more specific than a type T for any expression if S <: T.
In more detail:
The subtypes of a type T are all types U such that T is a supertype of U, and the null type.
From this, we infer that, because the generic is not well-bound, it is accepting a Comparable as part of your vararg. This is why my IDE picks it up as a recursive method, and why when I run it I get a StackOverflowError.
This issue actually goes away if you properly bound the generic to <U extends Comparable<U>> to ensure that it doesn't pick up anything you can't realistically sort on...
public static <U extends Comparable<U>> Object[] sortedCopy(Comparator<? super U> comparator, U... values) {
U[] copy = Arrays.copyOf(values, values.length);
Arrays.sort(copy, comparator);
return copy;
}
public static <U extends Comparable<U>> Object[] sortedCopy(U... values) {
return sortedCopy(Comparator.naturalOrder(), values);
}
...with the caveat that you might now have heap pollution, and it'd be simpler and more concise to introduce a fixed-arity method instead.
it would seem to me the function is calling itself in the scenario that cocerns to you.
in the second method, you can replace U with Object and everything fits there, since it is a varargs.
I understand that one reason Lower-bounded wildcards exist is so that a collection is not immutable when adding new elements.
E.g.
List<? extends Number> obj = new ArrayList<>();//Now this list is immutable
obj.add(new Integer(5));//Does not compile
List<? super Number> objTwo = new ArrayList<>();//This list is mutable
objTwo.add(new Integer(5));//Compiles
The following does not compile because I tried to get the long value of numbers.
Q1: What methods would I be able to use? Only Objects methods?:
public void testLowerBounds(List<? super Number> numbers){
if (!numbers.isEmpty()){
System.out.println(numbers.get(0).longValue());//Does not compile
}
}
How my question came about:
I am currently learning about streams and the book specifies the following stream method:
Optional<T> min(Comparator<? super T> comparator)
And implements it as follows:
Stream<String> s = Stream.of("monkey", "ape", "bonobo");
Optional<String> min = s.min((s1, s2) -> s1.length()—s2.length());
Q2: How is the comparator allowed to use string methods when is used?
If I had to answer Q2: I would say that optional is specifying "You have to pass me an implementation of Comparator that has a generic type "String" or something that implements "String". Would I be correct in saying this?
Looking forward to your response.
First of all, you should not confuse wildcard type parameters with mutability. Having a wildcard in a List’s element type does not prevent modifications, it only imposes a few practical restrictions to what you can do with the list.
Having a list declared like List<? extends Number> implies that the referenced list has an actual element type of Number or a subclass of Number, e.g. it could be a List<Integer> or List<Double>. So you can’t add an arbitrary Number instance as you can’t know whether it is compatible to the actual element type.
But you can still add null, as the null reference is known to be compatible with all reference types. Further, you can always remove elements from a list, e.g. call remove or clear without problems. You can also call methods like Collections.swap(list, index1, index2), which is interesting as it wouldn’t be legal to call list.set(index1, list.get(index2)) due to formal rules regarding wildcard types, but passing the list to another method that might use a non-wildcard type variable to represent the list’s element type works. It’s obviously correct, as it only sets elements stemming from the same list, which must be compatible.
Likewise, if you have a Comparator<Number>, you can call Collections.sort(list, comparator), as a comparator which can handle arbitrary numbers, will be able to handle whatever numbers are actually stored in the list.
To sum it up, having ? extends in a collection’s element type does not prevent modifications.
As said, you can’t insert arbitrary new elements into a list whose actual element type might be an unknown subclass of the bound, like with List<? extends Number>. But you are guaranteed to get a Number instance when retrieving an element, as every instance of subtype of Number is also an instance of Number. When you declare a List<? super Number>, its actual element type might be Number or a super type of Number, e.g. Object or Serializable. You can insert arbitrary Number instances, as you know it will be compatible to whatever actual element type the list has, as it is a super type of number. When you retrieve an instance, you only know that it is an instance of Object, as that’s the super type of all instances. To compare with the ? extends case, having a ? super declaration does not prevent reading, it only imposes some practical limitations. And likewise, you can still pass it to Collections.swap, because, regardless of how little we known about the actual type, inserting what we just retrieved from the same list, works.
In your second question, you are confusing the sides. You are now not looking at the implementation of min, but at the caller. The declaration of min(Comparator<? super T> c) allows the caller to pass any comparator being parameterized with T or a super type of T. So when you have a Stream<String>, it is valid to pass a Comparator<String> to the min method, which is exactly, what you are implementing via the (s1, s2) -> s1.length()—s2.length() lambda expression (though, I’d prefer Comparator.comparingInt(String::length)).
Within the implementation of min, there is indeed no knowledge about what either, T or the actual type argument of the Comparator, is. But it’s sufficient to know that any stream element that is of type T can be passed to the comparator’s compare method, which might expect T or a super type of T.
Code:
List<? extends Integer> ints= new ArrayList<Integer>();
ints.add(new SomeType());
I'm trying to reason why we cant add to ints formally. Please check the correctness.
Compiler always matched question mark to anonymous type CAP#n, where n is the ordinal number of wildcard declaration in the source code. From the fact that this wildrcard with extends implies that compiler internally assigned CAP#1 (in that case) just to anonymous type of null. But i'm not sure in this reason. Consider
List<? super Integer> ints= new ArrayList<Integer>();
ints.add(new Object());//error
In this case we have that compiler internally creates a new anonymous type, who marked CAP#2, such that only instance of all Integer's supertype is "instance of" CAP#2.
Question Do I understand the principle of wildcard's working correct now?
Let's try to look at the presented problem in different view, from java.util.List
public interface List<E> extends Collection<E> {
*
*
boolean add(E e);
*
*
}
When you specify List<? extends Integer>, the argument for add() becomes '? extends Integer'. From that description, the compiler cannot know which specific sub type of Integer is required there, so it won't accept any type of Integer.
The usage of List<? super Integer> tells to compiler that the it's possible to add to the list everything that is super type of Integer, addition of other types will violate static type safety.
You can thus begin to think of subtypes and supertypes bounds in terms of how you can "write" (pass into a method) to a generic type, and "read" (return from a method) from generic type.
Basically your technical description is right but I think that my explanation is more reasonable from static type safety point of view.
Hope it helps you.
Let's ignore the fact that Integer is final for purposes of this discussion.
When you give a variable the type of List< ? extends Integer >, the compiler does not allow you to call any method of List which has the generic type parameter as an argument to a method. These parameters are in what is known as contravariant position, and if the compiler would allow you to do what you are trying to do, Java's type system would be even more unsound than it already is. All the compiler knows is that the element type of the List is some unknown subtype of Integer, internally called CAP#1. Now attempting to call add( CAP#1, int ) with anything at all as first parameter will fail. The only exception is null, simply because unlike any other value in Java, null is a member of every reference type, so it must be a member of CAP#1. Note that the compiler will allow you to call any method of a List< ? extends Integer > that has no generic type inputs but possibly produces generic type outputs.
Contrary to the answer given by #Maxim Kirilov, when you give a variable the type of List< ? super Integer >, the compiler does not allow you to add any supertype of Integer. All it knows is that the unknown type is some supertype of Integer, internally called CAP#2, and that therefore anything which is an Integer or any subtype S of Integer can be added to the list (because no matter what CAP#2 turns out to be, S is a subtype of Integer which is a subtype of CAP#2, so add( CAP#2, int ) will accept an S in the first parameter).
By contrast, you are trying to call the method with an Object, which is not a subtype of Integer. The compiler rejects an attempt to pass an Object where a CAP#2 is required (as explained above).