Rav*_*avi 15 java java-8 java-stream
我需要log/sysoutJava Streams中的过滤值.我能够log/sysout使用非过滤值的peek()方法.但是,有人可以让我知道如何记录过滤值?
例如,假设我有一个Person像这样的对象列表:
List<Person> persons = Arrays.asList(new Person("John"), new Person("Paul"));
Run Code Online (Sandbox Code Playgroud)
我想过滤掉那些不是"约翰"的人如下:
persons.stream().filter(p -> !"John".equals(p.getName())).collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)
但是,我必须记录被过滤的"约翰"人的详细信息.有人可以帮助我实现这个目标吗?
Grz*_*rek 15
如果要将其与Stream API集成,除了手动引入日志记录之外,没有什么可以做的.最安全的方法是在filter()方法本身中引入日志记录:
List<Person> filtered = persons.stream()
.filter(p -> {
if (!"John".equals(p.getName())) {
return true;
} else {
System.out.println(p.getName());
return false;
}})
.collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)
请记住,对Stream API引入副作用是阴暗的,您需要了解自己在做什么.
您还可以构建一个通用的包装器解决方案:
private static <T> Predicate<T> andLogFilteredOutValues(Predicate<T> predicate) {
return value -> {
if (predicate.test(value)) {
return true;
} else {
System.out.println(value);
return false;
}
};
}
Run Code Online (Sandbox Code Playgroud)
然后简单地说:
List<Person> persons = Arrays.asList(new Person("John"), new Person("Paul"));
List<Person> filtered = persons.stream()
.filter(andLogFilteredOutValues(p -> !"John".equals(p.getName())))
.collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)
......甚至可以自定义动作:
private static <T> Predicate<T> andLogFilteredOutValues(Predicate<T> predicate, Consumer<T> action) {
Objects.requireNonNull(predicate);
Objects.requireNonNull(action);
return value -> {
if (predicate.test(value)) {
return true;
} else {
action.accept(value);
return false;
}
};
}
Run Code Online (Sandbox Code Playgroud)
然后:
List<Person> filtered = persons.stream()
.filter(andLogFilteredOutValues(p -> !"John".equals(p.getName()), System.out::println))
.collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)
Hol*_*ger 14
你可以用
Map<Boolean,List<Person>> map = persons.stream()
.collect(Collectors.partitioningBy(p -> "John".equals(p.getName())));
System.out.println("filtered: " + map.get(true));
List<Person> result = map.get(false);
Run Code Online (Sandbox Code Playgroud)
或者,如果您更喜欢单一陈述形式:
List<Person> result = persons.stream()
.collect(Collectors.collectingAndThen(
Collectors.partitioningBy(p -> "John".equals(p.getName())),
map -> {
System.out.println("filtered: " + map.get(true));
return map.get(false);
}));
Run Code Online (Sandbox Code Playgroud)
由于无法对匹配同一流上相反过滤器的元素执行终端操作,因此最好的选择可能只是使用使用者中的条件peek。
这样避免了两次遍历流/集合。
List<Person> persons = Arrays.asList(new Person("John"), new Person("Paul"));
//A consumer that only logs "John" persons
Consumer<Person> logger = p -> {
if ("John".equals(p.getName())) //condition in consumer
System.out.println("> " + p.getName());
};
Run Code Online (Sandbox Code Playgroud)
然后,我们可以将该消费者传递给peek,仅在此之后过滤最终操作:
List<Person> nonJohns = persons.stream()
.peek(logger)
.filter(p -> !"John".equals(p.getName()))
.collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)