如何在Java函数中适当地组合谓词和函数?

时间:2017-04-14 16:02:16

标签: java lambda java-8 method-reference functional-interface

目的是创建一个可在流过滤器中使用的新谓词:

myCollectionOfElement
.stream()
.filter(
    MyStaticHelperClass.compose(MyStaticHelperClass.getSubElement1OfTheElement(),MyStaticHelperClass.getPredicate1OnSubElement1()))
.sorted(MyStaticHelperClass.getOtherSubElement().reversed())
.limit(10)
.collect(Collectors.toList())

getSubElement1OfTheElement()返回Function<E,S>(E包含S属性) getPredicate1OnSubElement1()返回Predicate<S>

我使用静态函数来公开方法引用和函数。 我这样做是因为在 Velocity模板中调用了流,并且此上下文不支持lambda语法和方法引用我不想为所有可能的组合创建静态函数,所以我真的希望它们是可组合的

例如,我在此处不希望有静态getPredicate1OnElementThatCheckProperty1OnTheSubElement1(),因为我可以撰写getSubElement1OfTheElement()getPredicate1OnSubElement1()

所以我需要一个撰写函数:

// returns a new Predicate constructed by applying Predicate predicate on the result of Function function
public static <E,S> Predicate<E> compose(Function<E,S> function, Predicate<S> predicate)

// most intuitive : lambda
return value -> predicate.test(function.apply(value));

// with method references
return function.andThen(predicate::test)::apply;
// predicate.compose is not available because Predicate interface doesn't extends Function interface

受到Is there a convenience method to create a Predicate that tests if a field equals a given value?

的启发
// step by step with variables
Function <S,Boolean> predicateFunction = predicate::test;
// a kind of @FunctionalInterface implicit "conversion" ? Predicate -> Function.
// is that safe ?

Function <E,Boolean> composed = function.andThen(predicateFunction::apply);
return composed::apply;

编辑:

它被称为演员上下文:https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html

// the implementation of my compose can also be this ugly one-liner :
return ((Function <S,Boolean>)predicate::test).compose(function)::apply;

因此,我们无法实现一个带有任何功能接口的通用组合函数(在我的案例中是Function和Predicate),因为抽象方法的名称因每个接口而异(在我的情况下测试和应用)。
我很好。

总而言之,我真正需要的是两个静态函数,一个将谓词转换为函数而另一个函数相反。每个谓词都将用作函数,最后的操作将组合函数转换为谓词,以便与过滤函数的参数类型匹配。

public static <S> Function<S,Boolean> predicateToFunction(Predicate<S> predicate){
    return predicate::test;
}
public static <S> Predicate<S> functionToPredicate(Function<S,Boolean> function){
    return function::apply;
}

这是正确的吗? 如果是这样,是否有兴趣释放函数签名中的边界?

2 个答案:

答案 0 :(得分:5)

我回答自己的问题。

使用lambda:

value -> predicate.test(function.apply(value));

或者如果你真的想/必须写一个撰写函数,签名必须是:

public static <E,S> Predicate<E> compose(Function<E,S> function, Predicate<? super S> predicate)

答案 1 :(得分:0)

我认为最好的方法是使用Predicate提供的布尔组合方法:andornot。例如,

private Predicate<String> startsWith(String prefix) {
    return s -> s.startsWith(prefix);
}

private Predicate<String> endsWith(String suffix) {
    return s -> s.endsWith(suffix);
}

Stream.of("Foo","Fuz","Doo","Fo")
    .filter(startsWith("F").and(endsWith("o")))
    .forEach(System.out::println);