使用Java Lambdas就像C ++一样 - 函数指针?

时间:2017-05-11 22:03:01

标签: java lambda java-8 function-pointers

我对lambdas和Java8一般都很陌生,所以如果这是一个简单的问题我会道歉。

我目前有一个课程,我想在这个决赛中进行一些错综复杂的匹配,有一堆getter:

public final class Foo {
  public String getName();
  public Type getType();
  public List<Bar> getBarList();
  ....
}

我写了一个小帮手类来匹配:

public class MatchParameter<T> {
  boolean expectMatch = true;
  T valueToCheck;

  public MatchParameter(T value, boolean shouldMatch) {
    this.expectMatch = shouldMatch;
    this.valueToCheck = value;
  }

  public boolean matches(Predicate<T> matcher) {
    return matcher.test(valueToCheck) == expectMatch;
  }
}

然后,我有一个地方可以创建各种MatchParameters,例如检查名称或检查List<Bar>是否包含特定的Bar

MatchParameter<String> nameParam = new MatchParameter(inputName, shouldMatch);
MatchParameter<Bar> barParam = new MatchParameter(inputBar, shouldMatch);
....

我目前卡住了记住每个MatchParameter正在寻找的东西。最终我的支票代码如下:

if(nameParam.matches(name -> currentFoo.getName().matches(name)) {
  ...
}
if(barParam.matches(bar -> currentFoo.getBarList().contains(bar)) {
  ...
}
...

在每种情况下,谓词传递的是一个lambda,它有一些currentFoo.<accessorFns>的迭代,最终取一个类型T,并返回一个布尔值。我真正想要做的是将访问者的逻辑移动到MatchParameter的创建。

有没有办法可以指定一个我可以在构建时传入的函数指针?我希望它是某种可运行的(Foo,T)

在C ++中,我添加了一个本地函数指针,它将两个输入FooT带到MatchParameter的局部变量:

 bool (*checkFn)(Foo f, T input);

然后我可以为每个实例化创建一个匿名函数,并将我的MatchParameter matches实现更新为:

public boolean matches(Foo f) {
  return checkFn(f, valueToCheck) == expectMatch;
}

我的实例化是:

MatchParameter<String> nameParam = new MatchParameter<>(
  inputName, 
  shouldMatch, 
  (Foo f, String input) -> boolean { return f.getName().matches(input); }
);

在Java中是否有相同的方法来实现这一目标?

2 个答案:

答案 0 :(得分:2)

如果你的函数应该总是返回一个布尔值,那么你可以将BiPredicate传递给构造函数:

public class MatchParameter<T> {
    boolean expectMatch = true;

    T valueToCheck;

    BiPredicate<Foo, T> predicate;

    public MatchParameter(T value, boolean shouldMatch, BiPredicate<Foo, T> function) {
        this.expectMatch = shouldMatch;
        this.valueToCheck = value;
        this.predicate = predicate;
    }

    public boolean matches(Predicate<T> matcher) {
        return matcher.test(valueToCheck) == expectMatch;
    }
}

然后,您可以按如下方式实例化对象:

MatchParameter<String> nameParam = new MatchParameter<>(inputName, shouldMatch,
    (foo, input) -> f.getName().matches(input)
);

最后,您可以创建一个函数来测试BiPredicateFoo对象:

public boolean matches(Foo f) {
    return predicate.test(f, valueToCheck) == expectMatch;
}

答案 1 :(得分:1)

我认为MatchParameter类没有意义,因为不需要封装给定的输入值和条件。相反,我只是根据需要匹配给定输入值的Predicate<Foo>某些属性的条件创建Foo。这可以通过接收:

的静态方法来实现

此静态方法的返回值为Predicate<Foo>。这是代码:

public static <T, U, V> Predicate<T> matchesFor(
    Function<T, U> extractor,
    BiPredicate<U, V> condition,
    V inputValue,
    boolean shouldMatch) {

    return t -> condition.test(extractor.apply(t), inputValue) == shouldMatch;
}

// A handy overload
public static <T, U, V> Predicate<T> matchesFor(
    Function<T, U> extractor,
    BiPredicate<U, V> condition,
    V inputValue) {

    return matchesFor(extractor, condition, inputValue, true);
}

然后,无论您在何处创建匹配器,请改用matchesFor方法:

Predicate<Foo> nameMatcher = matchesFor(
    Foo::getName,    // if Foo's name
    String::matches, // matches
    SOME_REGEX);     // this specific input regex

Predicate<Foo> barsMatcher = matchesFor(
    Foo::getBarList, // if Foo's Bar list
    List::contains,  // contains
    SOME_BAR);       // this specific input Bar

最后,在你的循环中,只需使用上面创建的谓词:

if (nameMatcher.test(currentFoo)) {
    // ...
}

if (barsMatcher.test(currentFoo)) {
    // ...
}