我对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 ++中,我添加了一个本地函数指针,它将两个输入Foo
和T
带到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中是否有相同的方法来实现这一目标?
答案 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)
);
最后,您可以创建一个函数来测试BiPredicate
到Foo
对象:
public boolean matches(Foo f) {
return predicate.test(f, valueToCheck) == expectMatch;
}
答案 1 :(得分:1)
我认为MatchParameter
类没有意义,因为不需要封装给定的输入值和条件。相反,我只是根据需要匹配给定输入值的Predicate<Foo>
某些属性的条件创建Foo
。这可以通过接收:
Function<Foo, U>
BiPredicate<U, V>
接收提取的属性(类型U
)和输入值(类型V
)以进行检查此静态方法的返回值为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)) {
// ...
}