If I wrote the Predicate
interface, I\'d want to encode in the interface the fact that it\'s just a function that returns a primitive boolean
, like thi
The method in Predicate<T>
returns boolean
. The method in Function<T, Boolean>
returns Boolean
. They are not the same. Although there is autoboxing, Java methods don't use wrapper classes when primitives would do. Also, there are differences like Boolean
can be null
while boolean
can't.
It's even more different in the case of Consumer<T>
. The method in Consumer<T>
has return type void
, which means it can implicitly return or return using return;
, but the method in Function<T, Void>
must return using return null;
explicitly.
There is no need for such a suspicious inheritance hierarchy. These functional interfaces are inter-changable.
Function<A,Boolean> f1=…;
Predicate<A> p1=…;
Predicate<A> p2=f1::apply;
Function<A,Boolean> f2=p1::test;
This works in both directions. So why should there be an inheritance relationship advertising one specific direction?
It is not a direct answer to your question, but for what would you be using it for?
Consider the following scenario: You want to map true/false to the list of values for which it is true respectively false.
With your code you could use:
@FunctionalInterface
interface CustomPredicate<T> extends Function<T, Boolean> {
boolean test(T value);
@Override
default Boolean apply(T t) {
return test(t);
}
}
List<String> stringList = new ArrayList<>();
stringList.add("a");
stringList.add("hg");
stringList.add("dsl");
stringList.add("sldi");
stringList.add("ilsdo");
stringList.add("jlieio");
CustomPredicate<String> customPredicate = str -> (str.length() >= 3);
Map<Boolean, List<String>> mapping = stringList.stream()
.collect(Collectors.groupingBy(customPredicate));
The following however tells me that they have definately thought about something similar, as they offer the partitioning method:
List<String> stringList = new ArrayList<>();
stringList.add("a");
stringList.add("hg");
stringList.add("dsl");
stringList.add("sldi");
stringList.add("ilsdo");
stringList.add("jlieio");
Predicate<String> predicate = str -> (str.length() >= 3);
Map<Boolean, List<String>> mapping = stringList.stream()
.collect(Collectors.partitioningBy(predicate));
Some reasons I can think about are:
apply()
method available in a Predicate
where you only expect a test()
method.CustomPredicate
contains two types of functionality. It would only add to confusion.In my opinion Function<T, R>
is just the definition of a generic function. If all FunctionalInterfaces
would implement Function
, the only abstract method would have to be named apply()
. In the context of a concrete FunctionalInterface
like FilterFile
, the abstract method boolean accept(File pathname)
is a much better name then Boolean apply(File)
.
The annotation @FunctionalInterface
already marks an interface as being intended to be usable as a FunctionalInterface
. There is no benefit having them all implement a base interface other then processing them in a generic way. I do not see when you would not care about the semantics of a FunctionalInterface
in advance to make them available to call apply
for them all.