在Java 8中是否有更好的方法来实现以下目标?
String regex = "^SACHI";
for (String temp : personalNames ) {
if (temp.matches(regex)){
personalNames.remove(temp);
}
}
答案 0 :(得分:8)
您可以使用
personalNames.removeIf(Pattern.compile("^SACHI").asPredicate());
您也可以使用更简单的
personalNames.removeIf(s -> s.matches("^SACHI"));
,但对于最坏情况下的每个元素,它都会在后台执行Pattern.compile("^SACHI")
。请注意,由Pattern
创建的compile
是不可变的,可以共享,因此,您也只能创建一次,例如
static final Pattern REMOVAL_PATTERN = Pattern.compile("^SACHI");
并像使用它
personalNames.removeIf(REMOVAL_PATTERN.asPredicate());
asPredicate()
使用find()
而不是matches()
,但是由于您的模式具有^
锚点,因此没有区别。在JDK 11中添加了使用asMatchPredicate()
获取谓词的方法matches()
。
如果只想在开头匹配文字字符串,也可以使用
personalNames.removeIf(s -> s.startsWith("SACHI"));
没有regex初始化开销。
答案 1 :(得分:3)
从现有容器中添加和/或删除元素与函数式编程的概念不太吻合。此外,这种行为在并行和并发环境中不是线程安全的。使线程安全也需要更多的努力。因此,作为一种良好的工程实践,将无Stef Lambda优先于有状态Lambda。您只需使用过滤器运算符就可以获取匹配的名称。看起来就是这样。
private static final Pattern PATTERN = Pattern.compile("^SACHI");
List<String> validNames = personalNames.stream()
.filter(PATTERN.asPredicate())
.collect(Collectors.toList());
答案 2 :(得分:2)
这取决于您需要修改现有列表,还是只需要获取不包含元素的列表。 在第一种情况下,您可以使用流过滤不匹配的对象并将其从列表中删除
personalNames.removeAll(
personalNames
.stream()
.filter(x -> !x.matches(regex))
.collect(Collectors.toList())
);
在其他情况下,您可以仅返回仅包含匹配对象的新列表
final List<String> matchingElements = personalNames.stream()
.filter(x -> x.matches(regex))
.collect(Collectors.toList());
此代码
for (String temp : personalNames ) {
if (temp.matches(regex)){
personalNames.remove(temp);
}
}
会抛出
java.util.ConcurrentModificationException
答案 3 :(得分:1)
您可以通过errorProneNames
提取filtering
并从迭代personalNames
的{{1}}中删除相应的错误名称:
forEach
答案 4 :(得分:1)
它们等效:
for (String temp : personalNames ) {
if (temp.matches(regex)){
personalNames.remove(temp);
}
}
和
personalNames.removeIf(name -> name.matches(regex));
答案 5 :(得分:0)
String regex = "^SACHI";
Predicate<String> f = n-> n.matches(regex);
personalNames.stream().filter(x->f.test(x))
.forEach(n-> {
personalNames.remove(n);
});
使用Predicate<T>
筛选出与String regex
不匹配的名称。
test(T t)
根据给定参数评估该谓词。