Collect HashSet / Java 8 / Regex Pattern / Stream API

collections, java, java-8, java-stream, regex

Solution

A `Matcher`-based spliterator implementation can be quite simple if you reuse the JDK-provided `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;
  }
}

Note that the spliterator provides all matcher groups, not just the full match. Also note that this spliterator supports parallelism because `AbstractSpliterator` implements a splitting policy.

Typically you will use a convenience stream factory:

public static Stream<String[]> matcherStream(Matcher m) {
  return StreamSupport.stream(new MatcherSpliterator(m), false);
}

This gives you a powerful basis to concisely write all kinds of complex regex-oriented logic, for example:

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(", ")));
}

Which prints

User has e-mail accounts on these domains: gmail.com, yahoo.com, tijuana.com

For completeness, your code will be rewritten as

Set<String> set = matcherStream(mtr).map(gs->gs[0].toLowerCase()).collect(toSet());

Problem

Recently I change version of the JDK 8 instead 7 of my project and now I overwrite some code snippets using new features that came with Java 8. ``` final Matcher mtr = Pattern.compile(regex).matcher(input); HashSet<String> set = new HashSet<String>() {{ while (mtr.find()) add(mtr.group().toLowerCase()); }}; ``` How I can write this code using Stream API ?

Original source