问题
With the functional interfaces introduced in Java 8, you can easily chain different expressions into one new expression, illustrated by the code snippet below.
public class PredicateChaining {
public static void main(String[] args) {
// verbose, but standard JDK functionality only
Predicate<String> allUpperCase = StringUtils::isAllUpperCase;
Predicate<String> longerThan5 = s -> s.length() > 5;
if (allUpperCase.and(longerThan5).test("PREDICATE")) {
System.out.println("'PREDICATE' is a uppercase text, longer than 5.");
}
// compact, but with utility method ('chain' in this case)
if (chain(StringUtils::isAllLowerCase).and(s -> s.length() < 5).test("test")) {
System.out.println("'test' is a lowercase text, shorter than 5.");
}
}
public static <T> Predicate<T> chain(Predicate<T> test) {
return test;
}
}
In this case 2 String Predicates are chained into one new Predicate. This works fine when you have at least one handle (i.e. variable) to invoke the chaining method (in this case 'and') on. However, if the expressions you want to chain are represented as a lambda or method reference, you need to translate one of them explicitly to a variable, which makes it very verbose. When the compiler is unable to determine the exact type, you have to resort to this kind of construction. But in most cases, this is simply verbose overhead I'd like to avoid.
In this example, I have written the utility method 'chain' myself. But I can create one for the other functional interfaces (Function, Consumer, Supplier, BiConsumer, ...) as well.
Instead of creating my own utility class with these methods (which I would probably copy-paste to every project I work on), I want to know whether such a class exists in the JDK or in some library?
On the other hand, if such a class does not exist and I shouldn't be creating one myself, I would like to hear why.
回答1:
There is no sense in creating Predicate
instances to use them in a follow-up if
statement.
Predicate
instances are normally used for passing a condition to a method. In this case, you may study the particular API to find out whether such a chaining is possible using natural constructs.
E.g. when passing Predicate
s to a stream you may simply make two or more filter
calls:
stringStream.filter(StringUtils::isAllUpperCase).filter(s->s.length()>5). …
(and you may similarly chain Function
s using multiple map
calls)
and other APIs may have similar methods.
But after all, if you have two conditions which you want to combine and neither is already a Predicate
instance, the straight forward solution is to just combine the expressions:
stringStream.filter(s -> isAllUpperCase(s) && s.length()>5). …
or as stand-alone creation:
Predicate<String> allUpperCaseAndLongerThan5 = s -> isAllUpperCase(s) && s.length()>5;
note that you can use a static import
for the utility method here which allows an even more compact expression.
Using Predicate.and
and Predicate.or
is only useful if you already have a Predicate
instance and want to augment its logic. But in this case you also have an instance on which you can invoke and
or or
without problems.
来源:https://stackoverflow.com/questions/28605500/utility-class-to-bootstrap-lambda-expressions-or-method-references-for-method-ch