'Who implements the "other methods" in a Functional Interface - and where?
The "other methods" for Consumer and BiConsumer<T,U> and BiFunction<T,U,R> is andThen().
The "other methods" for Function<T,R> UnaryOperator are compose(), andThen(), identity().
The "other methods" for BinaryOperator<T,T> are andThen(), maxBy(), minBy().
The "other methods" for Predicate is and(), or(), negate(), isEqual().
The "other methods" for BiPredicate<T, U> is and(), or(), negate().
Since a Functional Interface is passed to an implementing method by a lambda expression, who will implement these other methods - and where?
Update: What I was trying to point out; what if the semantics of the "other methods" are not trivial or straightforward as in the example in the comments below? Consider the Predicate Functional Interface. If I pass in a lambda expression to an implementing method, but the and(), or(), negate() are not straightforward. Then the default implementation will not cover it. I suppose we would have to handroll our own custom Functional Interface that extends the original one and implements all the "other methods"?
Update: For Functional interfaces like BiFunction which has an andThen() other method, does this mean we would have to inherit from this interface and create a new one with a default method andThen()?
Solution 1:[1]
Well, I got the feeling you are missing something here.
Let's consider the Predicate interface. I stripped it down with the elements not relevant to the question.
interface Predicate<T> {
boolean test(T t);
default Predicate<T> negate() {
return (t) -> !test(t);
}
}
This is a functional interface: it has exactly one abstract method. The authors of this interface also added a method which they named negate. Its implementation returns a new Predicate which returns the exact opposite result when its test method is called. They added this method because they thought it would be useful.
As you can see, the negate method is default, and has a method body. Methods which have a body, are never abstract.
Since a Functional Interface is passed to an implementing method by a lambda expression
and
If I pass in a lambda expression to an implementing method
Not sure what you mean here, but I think it's poorly worded. A lambda expression can only be used where a functional interface is expected. So a lambda expression is the implementation of the only abstract method of a functional interface. The "other" methods are not relevant to this story so far.
Say, I want to create a Predicate which tests if a string is equal to "Hello". A typical implementation may look like this:
str -> str.equals("Hello")
This is (roughly) equivalent to this:
class PredicateImpl implements Predicate<String> {
@Override
public boolean test(String t) {
return t.equals("Hello");
}
public Predicate<String> negate() {
return new Predicate<String> {
@Override
public boolean test(String t) {
return !PredicateImpl.this.test(t);
}
};
}
}
As you can see, negate() returns a new Predicate which captures the predicate on which the method is called, and when its test method is called, it is deferred to the captured Predicate, and returns the resulting boolean inversed.
A lambda expression never implements a default method, as these are not abstract. So negate is not overridden in any way at all.
Of course, this doesn't stop us from creating our own functional interface in order to tamper with the semantics of negate.
public interface MyPredicate<T> extends Predicate<T> {
@Override
public default MyPredicate<T> negate() {
return t -> true; // Say what?! That's not a negation!
}
}
Now let's first see the "normal" predicate in action:
String s = "Hello";
Predicate<String> stringIsHello = t -> t.equals("Hello");
Predicate<String> stringIsNotHello = stringIsHello.negate();
System.out.println(stringIsHello.test(s));
System.out.println(stringIsNotHello.test(s));
Outputs, as expected:
true
false
Now let's use our custom predicate instead:
String s = "Hello";
MyPredicate<String> p1 = t -> t.equals("Hello");
MyPredicate<String> p2 = p1.negate();
System.out.println(p1.test(s));
System.out.println(p2.test(s));
Output:
true
true
Now does negate in our MyPredicate what you expect it to do? Absolutely not. Does the compiler prevent you from actually doing it? No, it cannot and it will not.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
