Utility Class to bootstrap lambda expressions or method references for method chaining?

天大地大妈咪最大 提交于 2020-01-14 02:59:13

问题


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 Predicates 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 Functions 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!