给出以下字符串列表:
List<String> progLangs = Arrays.asList("c#", "java", "python", "scala");
Run Code Online (Sandbox Code Playgroud)
和一个应该匹配4个字母的小写字符串的正则表达式模式.
Pattern p = Pattern.compile("[a-z]{4}");
Run Code Online (Sandbox Code Playgroud)
现在我想找到progLangs适合Pattern的元素p.
用旧方式做到这一点:
for (String lang : progLangs) {
if (p.matcher(lang).matches()) {
System.out.println(lang);
}
}
Run Code Online (Sandbox Code Playgroud)
我得到了预期的结果:
java
Run Code Online (Sandbox Code Playgroud)
但是当我尝试使用Java 8流实现相同的功能并使用Pattern.asPredicate将模式转换为谓词时:
progLangs.stream()
.filter(p.asPredicate())
.forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)
结果是:
java
python
scala
Run Code Online (Sandbox Code Playgroud)
为什么会这样?看起来Patter.asPredicate产生一个接受部分匹配的谓词.Pattern API中的等价物是什么?该文件只是说:
创建可用于匹配字符串的谓词.
我希望它是典型的,Pattern.matcher(String).matches()但它是另一回事......如何解释这种不一致?
Jon*_*han 12
他们没有做同样的事情 - 谓词使用find而不是matches.等效的"旧代码"方式是:
for (String lang : progLangs) {
if (p.matcher(lang).find()) {
System.out.println(lang);
}
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,我会使用自己的谓词:
progLangs.stream()
.filter(s -> p.matcher(s).matches())
.forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)
但文档似乎确实有误导性.
使用JDK/11,您可以使用新的Pattern.asMatchPredicateAPI 以单行方式完成您最初尝试做的事情:
progLangs.stream()
.filter(p.asMatchPredicate()) // the matches predicate
.forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)
以下是相同内容的 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();
}
Run Code Online (Sandbox Code Playgroud)