In Chapter 8 of Generic Types from Core Java Volume I Edition 10,
NOTE: Another common use for supertype bounds is an argument type of a functional interface. For example, the Collection interface has a method
default boolean removeIf(Predicate<? super E> filter)The method removes all elements that fulfill the given predicate. For example, if you hate employees with odd hash codes, you can remove them like this:
ArrayList<Employee> staff = . . .; Predicate<Object> oddHashCode = obj -> obj.hashCode() %2 != 0; staff.removeIf(oddHashCode);You want to be able to pass a
Predicate<Object>, not just aPredicate<Employee>. The super wildcard makes that possible.
I met some problems when trying to understand this, so <? super E> means that filter could point to any predicate type that can be superclass of Employee or Employee itself.
The text above mentioned we could pass a Predicate<Object> to Predicate<? super E>.
But what if Predicate<? super E> points to Predicate<Employee>, can Predicate<Object> be passed to Predicate<Employee>?
Did I misunderstand something?
Your understanding is correct. For example, a function that takes
Predicate<? super Employee>(as in yourArrayList<Employee>example) can also accept aPredicate<Object>likeObjects::nonNull. Conceptually, this makes sense for the following reason: "We (the class) take aPredicatethat operates on us, or on any of the (transitive) superclasses of ourself, because we have an is-a relationship with those superclasses." That is to say, a function that takes anyObjectand returns abooleanis equivalently applicable toEmployeebecauseEmployeeis-aObject, and so it is valid to apply this function toEmployee. The derived class is not the exact same as the base class, but the predicate (logical test) still applies to the derived class, because it makes sense to talk about the derived class as-a base class.Let's go through an example:
Employeescould be derived fromPerson. IfPersoncan be tested with aPredicate<Person>calledhasJob, then it is logically sound to be able to testEmployeesforhasJobas well. The ability of that function to takePredicate<? super Employee>instead of justPredicate<Employee>is required to maintain the ability of the function to take a logically sound predicate. On the other hand, if you only expect forEmployees to be tested for some property, you might accept only aPredicate<Employee>instead, because that corresponds to the logical soundness of onlyEmployeeand its derived classes possessing the ability to be tested for that property.To be 100% clear about what is going on here:
Predicate<? super Employee>acceptsPredicatethattestsEmployeeand any superclass ofEmployee, includingObjectPredicate<Employee>acceptsPredicatethattestsEmployeeand any subclass ofEmployee, which excludesObjectGiven this class hierarchy:
SalariedEmployee is-a Employee is-a Person, here's what happens (P is shorthand forPredicate):Note that
Accept/Rejectdenote the types that can be fed into thePredicate, not the actual result of thePredicate.