如何在Java流上应用多个过滤器?
我必须通过一个映射过滤对象集合,该映射保存对象字段名和字段值的键值对。我正在尝试按流()应用所有筛选器。筛选器() 这些对象实际上是JSON,因此映射包含其变量的名称以及它们必须包含的值,以便被接受,但出于简单的原因,并且由于与问题无关,我编写了一个简单的Testclass来模拟该行为:如何在Java流上应用多个过滤器?,java,java-stream,Java,Java Stream,我必须通过一个映射过滤对象集合,该映射保存对象字段名和字段值的键值对。我正在尝试按流()应用所有筛选器。筛选器() 这些对象实际上是JSON,因此映射包含其变量的名称以及它们必须包含的值,以便被接受,但出于简单的原因,并且由于与问题无关,我编写了一个简单的Testclass来模拟该行为: public class TestObject { private int property1; private int property2; private int property3;
public class TestObject {
private int property1;
private int property2;
private int property3;
public TestObject(int property1, int property2, int property3) {
this.property1 = property1;
this.property2 = property2;
this.property3 = property3;
}
public int getProperty(int key) {
switch(key) {
case 1: return property1;
case 2: return property2;
default: return property3;
}
}
}
到目前为止,我所尝试的:
public static void main(String[] args) {
List<TestObject> list = new ArrayList<>();
Map<Integer, Integer> filterMap = new HashMap<>();
list.add(new TestObject(1, 2, 3));
list.add(new TestObject(1, 2, 4));
list.add(new TestObject(1, 4, 3));
filterMap.put(3, 3); //Filter property3 == 3
filterMap.put(2, 2); //Filter property2 == 2
//Does not apply the result
filterMap.forEach((key, value) -> list.stream()
.filter(testObject -> testObject.getProperty(key) == value)
.collect(Collectors.toList())
);
/* Gives error: boolean can not be converted to void
list = list.stream()
.filter(testObject -> filterMap.forEach((key, value) -> testObject.getProperty(key) == value))
.collect(Collectors.toList()
);
*/
//Printing result
list.forEach(obj -> System.out.println(obj.getProperty(1) + " " + obj.getProperty(2) + " " + obj.getProperty(3)));
}
编辑:
Sweeper在他的回答中很好地总结了我的问题,所以这里再次澄清一下(可能是未来的读者):我想保留满足所有过滤器的所有对象。我想您想保留满足映射指定的所有条件的所有
测试对象
这将完成以下工作:
List<TestObject> newList = list.stream()
.filter(x ->
filterMap.entrySet().stream()
.allMatch(y ->
x.getProperty(y.getKey()) == y.getValue()
)
)
.collect(Collectors.toList());
List newList=List.stream()
.过滤器(x->
filterMap.entrySet().stream()
.allMatch(y->
x、 getProperty(y.getKey())==y.getValue()
)
)
.collect(Collectors.toList());
翻译成“英语”
filter
通过保留所有元素x
来过滤列表list
:
filterMap
的所有键值对y
必须满足:
x.getProperty(y.getKey())==y.getValue()
(我不认为我能很好地让这篇文章更具可读性……)如果你想要一个更具可读性的解决方案,我推荐Jeroen Steenbeeke的答案。要对流应用数量可变的过滤步骤(只有在运行时才知道),你可以使用一个循环来添加过滤步骤
Stream<TestObject> stream = list.stream();
for (Predicate<TestObject> predicate: allPredicates) {
stream = stream.filter(predicate);
}
list = stream.collect(Collectors.toList());
Stream=list.Stream();
for(谓词:所有谓词){
stream=stream.filter(谓词);
}
list=stream.collect(Collectors.toList());
它与过滤器无关。实际上,过滤器永远不会按照您的代码工作。看
//Does not apply the result
filterMap.forEach((key, value) -> list.stream()
.filter(testObject -> testObject.getProperty(key) == value)
.collect(Collectors.toList())
);
列表已筛选,但此处未更改任何内容。未删除任何元素,也未更改任何对象地址。尝试removeIf
// Does not apply the result
filterMap.forEach((key, value) -> list.removeIf(testObject -> testObject.getProperty(key) != value));
输出为
1 2 3
一种更通用的方法是创建一个多过滤器(谓词
),该过滤器使用谓词和(…)
或谓词或(…)
连接。这适用于任何使用谓词
——首先是流
和可选
由于结果是一个谓词
本身,因此可以继续使用谓词和(…)
或谓词。或(…)
或再次使用多谓词
构建更复杂的谓词
class MultiPredicate {
public static <T> Predicate<T> matchingAll(Collection<Predicate<T>> predicates) {
Predicate<T> multiPredicate = to -> true;
for (Predicate<T> predicate : predicates) {
multiPredicate = multiPredicate.and(predicate);
}
return multiPredicate;
}
@SafeVarargs
public static <T> Predicate<T> matchingAll(Predicate<T> first, Predicate<T>... other) {
if (other == null || other.length == 0) {
return first;
}
Predicate<T> multiPredicate = first;
for (Predicate<T> predicate : other) {
multiPredicate = multiPredicate.and(predicate);
}
return multiPredicate;
}
public static <T> Predicate<T> matchingAny(Collection<Predicate<T>> predicates) {
Predicate<T> multiPredicate = to -> false;
for (Predicate<T> predicate : predicates) {
multiPredicate = multiPredicate.or(predicate);
}
return multiPredicate;
}
@SafeVarargs
public static <T> Predicate<T> matchingAny(Predicate<T> first, Predicate<T>... other) {
if (other == null || other.length == 0) {
return first;
}
Predicate<T> multiPredicate = first;
for (Predicate<T> predicate : other) {
multiPredicate = multiPredicate.or(predicate);
}
return multiPredicate;
}
}
如果我们使用MultiPredicate.matchingAny(…)
结果是:
(1|2|3)
(1|2|3)
(1|2|4)
(1|4|3)
请更具体地说,你希望得到什么结果我读你的答案没有问题,我真的很喜欢,非常感谢!)您不应该使用==
来比较整数
s。@MichaelgetProperty
返回一个原语int
,因此右侧将被解锁,对吗?@Sweeper一般来说,您的代码比Jeroen Steenbeeke的效率更高(性能更好)s@user_3380739一如既往,这样的性能预测是有风险的——这当然取决于是否有更多的过滤器或更多的对象需要测试。这种方法为列表中的每个条目创建一个流
——实例,每个过滤器创建一个实例。profile可能很有趣。那么.filter()是什么呢?
(1|2|3)
(1|2|3)
(1|2|4)
(1|4|3)