给出以下字符串列表:
List<String> progLangs = Arrays.asList("c#", "java", "python", "scala");
和一个应该匹配4个字母的小写字符串的正则表达式。
Pattern p = Pattern.compile("[a-z]{4}");
现在我想找到适合模式progLangs
的{{1}}元素。
以旧的方式去做:
p
我得到了预期的结果:
for (String lang : progLangs) {
if (p.matcher(lang).matches()) {
System.out.println(lang);
}
}
但是当我尝试使用Java 8流实现相同功能并使用Pattern.asPredicate将模式转换为谓词时:
java
结果是:
progLangs.stream()
.filter(p.asPredicate())
.forEach(System.out::println);
为什么会这样?看起来Patter.asPredicate产生一个接受部分匹配的谓词。 Pattern API中的等价物是什么? documentation仅表示:
创建一个可用于匹配字符串的谓词。
我希望它是典型的java
python
scala
,但它是其他的...如何解释这种不一致?
答案 0 :(得分:11)
他们没有做同样的事情 - 谓词使用find
rather than matches
。等效的旧代码&#39;方式是:
for (String lang : progLangs) {
if (p.matcher(lang).find()) {
System.out.println(lang);
}
}
在这种情况下,我会使用自己的谓词:
progLangs.stream()
.filter(s -> p.matcher(s).matches())
.forEach(System.out::println);
文档似乎确实有误导性。
答案 1 :(得分:1)
通过JDK/11,您可以使用新的 Pattern.asMatchPredicate
API以单行代码的形式完成您最初尝试的操作:
progLangs.stream()
.filter(p.asMatchPredicate()) // the matches predicate
.forEach(System.out::println);
这是相同的javadoc读取的内容:
/**
* Creates a predicate that tests if this pattern matches a given input string.
*
* @apiNote
* This method creates a predicate that behaves as if it creates a matcher
* from the input sequence and then calls matches, for example a
* predicate of the form:
* s -> matcher(s).matches();
*
* @return The predicate which can be used for matching an input string
* against this pattern.
* @since 11
* @see Matcher#matches
*/
public Predicate<String> asMatchPredicate() {
return s -> matcher(s).matches();
}