Ant*_*sev 14 java regex collections java-8 java-stream
最近我更改了JDK 8的版本而不是我的项目中的7个,现在我使用Java 8附带的新功能覆盖了一些代码片段.
final Matcher mtr = Pattern.compile(regex).matcher(input);
HashSet<String> set = new HashSet<String>() {{
    while (mtr.find()) add(mtr.group().toLowerCase());
}};
我如何使用Stream API编写此代码?
Mar*_*nik 26
Matcher如果重用JDK提供的,基于A 的spliterator实现可以非常简单Spliterators.AbstractSpliterator:
public class MatcherSpliterator extends AbstractSpliterator<String[]>
{
  private final Matcher m;
  public MatcherSpliterator(Matcher m) {
    super(Long.MAX_VALUE, ORDERED | NONNULL | IMMUTABLE);
    this.m = m;
  }
  @Override public boolean tryAdvance(Consumer<? super String[]> action) {
    if (!m.find()) return false;
    final String[] groups = new String[m.groupCount()+1];
    for (int i = 0; i <= m.groupCount(); i++) groups[i] = m.group(i);
    action.accept(groups);
    return true;
  }
}
请注意,spliterator提供所有匹配器组,而不仅仅是完全匹配.另请注意,此spliterator支持并行性,因为它AbstractSpliterator实现了拆分策略.
通常,您将使用便利流工厂:
public static Stream<String[]> matcherStream(Matcher m) {
  return StreamSupport.stream(new MatcherSpliterator(m), false);
}
这为您简明地编写各种复杂的面向正则表达式逻辑提供了强大的基础,例如:
private static final Pattern emailRegex = Pattern.compile("([^,]+?)@([^,]+)");
public static void main(String[] args) {
  final String emails = "kid@gmail.com, stray@yahoo.com, miks@tijuana.com";
  System.out.println("User has e-mail accounts on these domains: " +
      matcherStream(emailRegex.matcher(emails))
      .map(gs->gs[2])
      .collect(joining(", ")));
}
哪个打印
User has e-mail accounts on these domains: gmail.com, yahoo.com, tijuana.com
为了完整起见,您的代码将被重写为
Set<String> set = matcherStream(mtr).map(gs->gs[0].toLowerCase()).collect(toSet());
Marko的回答演示了如何使用a将匹配项添加到流中Spliterator.干得好,给那个男人一个大+1!说真的,在你考虑提出这个问题之前,请确保你提出他的答案,因为这个完全是他的.
我只有一小部分要添加到Marko的答案中,而不是将匹配表示为字符串数组(每个数组元素代表一个匹配组),匹配更好地表示为一个MatchResult为此发明的类型目的.因此结果将是一个Stream<MatchResult>而不是Stream<String[]>.代码也变得更简单了.该tryAdvance代码将是
    if (m.find()) {
        action.accept(m.toMatchResult());
        return true;
    } else {
        return false;
    }
map他的电子邮件匹配示例中的调用将更改为
    .map(mr -> mr.group(2))
并且OP的例子将被重写为
Set<String> set = matcherStream(mtr)
                      .map(mr -> mr.group(0).toLowerCase())
                      .collect(toSet());
使用MatchResult提供了更多的灵活性,因为它还提供了字符串中匹配组的偏移量,这对某些应用程序非常有用.
我不认为你可以把它变成Stream没有写自己的Spliterator,但是,我不知道你为什么要这样做.
Matcher.find()是Matcher对象的状态更改操作,因此在并行流中运行每个find()会产生不一致的结果.串行运行流将没有Java 7等效的更好的性能,并且将更难理解.
| 归档时间: | 
 | 
| 查看次数: | 6202 次 | 
| 最近记录: |