假设一个类MyClass:
public class MyClass {
private final Integer myId;
private final String myCSVListOfThings;
public MyClass(Integer myId, String myCSVListOfThings) {
this.myId = myId;
this.myCSVListOfThings = myCSVListOfThings;
}
// Getters, Setters, etc
}
这条流:
final Stream<MyClass> streamOfObjects = Stream.of(
new MyClass(1, "thing1;thing2;thing3"),
new MyClass(2, "thing2;thing3;thing4"),
new MyClass(3, "thingX;thingY;thingZ"));
我想返回myCSVListOfThings
中包含条目"thing2"
的MyClass
的每个实例。
如果我想要一份清单
List<String> filteredThings = streamOfObjects
.flatMap(o -> Arrays.stream(o.getMyCSVListOfThings().split(";")))
.filter("thing2"::equals)
.collect(Collectors.toList());
但我真正需要的是一个列表
这就是我现在拥有的:
List<MyClass> filteredClasses = streamOfObjects.filter(o -> {
Stream<String> things = Arrays.stream(o.getMyCSVListOfThings().split(";"));
return things.anyMatch(s -> s.equals("thing2"));
}).collect(Collectors.toList());
但不知怎的,这感觉不太对。除了在谓词中打开一个新的流之外,还有什么更清洁的解决方案吗?
在我看来,你有三个选择。
1) 在字符串中查找特定条目而不拆分它-仍然看起来很混乱
List<MyClass> filteredClasses = streamOfObjects
.filter(o -> o.getMyCSVListOfThings().contains(";thing2;"))
.collect(Collectors.toList());
2) 地图两次-仍然凌乱
List<MyClass> filteredClasses = streamOfObjects
.map(o -> Pair<MyClass, List<String>>.of(o, toList(o.getMyCSVListOfThings()))
.filter(pair -> pair.getRight().contains("thing2"))
.map(pair -> pair.getLeft())
.collect(Collectors.toList());
其中toList是一个将String转换为List的方法
3) 创建其他字段-我建议的方法
扩展类MyClass-向类添加字段
List<String> values;
并在构造函数中初始化它:
public MyClass(Integer myId, String myCSVListOfThings) {
this.myId = myId;
this.myCSVListOfThings = myCSVListOfThings;
this.values = toList(myCSVListOfThings);
}
然后在溪流中简单地:
List<MyClass> filteredClasses = streamOfObjects
.filter(o -> o.getValues().contains("thing2"))
.collect(Collectors.toList());
当然,如果需要,可以在第一次getValues方法调用期间以延迟模式初始化字段值。
一种解决方案是使用避免拆分和流操作的模式匹配:
Pattern p=Pattern.compile("(^|;)thing2($|;)");
List<MyClass> filteredClasses = streamOfObjects
.filter(o -> p.matcher(o.getMyCSVListOfThings()).find())
.collect(Collectors.toList());
由于参数为字符串。split定义为正则表达式模式,上面的模式与在split的结果中查找匹配项具有相同的语义;您正在两个边界之间查找单词thing2,第一个是行的开头或分号,第二个是行的结尾或分号。
除此之外,在谓词中使用另一个流操作也没有错。但是有一些方法可以改进它。如果省略保存流的过时局部变量,lambda表达式会变得更简洁。通常,您应该避免将流实例保存在局部变量中,因为直接链接操作将减少尝试多次使用流的风险。其次,您可以使用Pattern类对分割操作的结果元素进行流式处理,而无需首先将它们全部收集到一个数组中:
Pattern p=Pattern.compile(";");
List<MyClass> filteredClasses = streamOfObjects
.filter(o -> p.splitAsStream(o.getMyCSVListOfThings()).anyMatch("thing2"::equals))
.collect(Collectors.toList());
或
Pattern p=Pattern.compile(";");
List<MyClass> filteredClasses = streamOfObjects
.filter(o -> p.splitAsStream(o.getMyCSVListOfThings()).anyMatch(s->s.equals("thing2")))
.collect(Collectors.toList());
请注意,您还可以将原始代码重写为
List<MyClass> filteredClasses = listOfObjects.stream()
.filter(o -> Arrays.asList(o.getMyCSVListOfThings().split(";")).contains("thing2"))
.collect(Collectors.toList());
现在,谓词中的操作不是Stream而是Collection操作,但这不会改变语义或代码的正确性......
首先,我建议您向MyClass添加额外的方法,以便您可以像这样转换代码:
List<MyClass> filteredClasses = streamOfObjects
.filter(o -> o.containsThing("thing2"))
.collect(Collectors.toList());
现在您可以根据输入数据实现此方法:拆分为Stream
,拆分为Set
,甚至搜索substring
(如果可能并且有意义),如果需要,缓存结果。
你们对这个类的用法了解得更多,所以你们可以做出正确的选择。
问题内容: 使用Java Stream时,映射后有时会出现空值。当前,当这些值需要省略时,我使用: 对于更实用的样式,可以快速编写一个小的辅助方法: 这样您就可以使用方法引用了: 我找不到这样的jdk方法,即使我怀疑它们中已经包含了一种。这里有其他方法吗?还是他们出于某种原因忽略了这一点? 问题答案: 您可以从Java8 SDK 使用Objects :: nonNull :
注意:我实际上不确定为什么这种情况首先需要监听器,因为我甚至不想经常监听,而是在调用方法时得到结果。
我有一个带有键的HashMap,值是字符串。我想通过以字符串“locationid”开头的键值过滤HashMap,并将键中的值返回到字符串数组列表中。HashMap的填充方式如下: 我需要arraylist中的ORG_Id值。 我找不到可以将值放入字符串列表的位置。编译错误是它不识别values()方法。 更新还尝试将筛选后的Hashmap放入另一个Hashmap中,如下所示: 但得到的编译错误是
我希望,如果我选择“mammals”,动物选择选项只显示值为1的选项data-animal_class。 我知道如何获得哺乳动物值,但我不知道如何使用过滤器 这是我的代码:
我的spring boot应用程序配置为Reactive。但是我的REST APIendpoint配置为返回ResponseEntity而不使用Mono或flux。 我想实现过滤器,这将检查每个endpoint的传入头。旧的Servlet过滤器当然不起作用,新的WebFilter对webflux和其他过滤器也不起作用。
我写了示例代码,但它不起作用。还观察到2个选项卡只有1个窗口句柄。如何再次切换到父页签?