Search code examples
javaregexjava-stream

Why is my while(matcher.find()) entering an infinite loop? I use it in with Streams


What I want: [”Einstein”, “ist”, “kein”, “Stein”] ⇒ {”Einstein”=2, “kein”=1, “Stein”=1} Using a Stream I want to transform a list of strings to a map finding all the "ei" instances.

My Code is stuck in an infinite loop:

public static void main(String[] args) {
  List<String> L5 = List.of("Einstein", "ist", "kein", "Stein");
  Pattern P = Pattern.compile("[Ee]i");
  Map<String, Integer> result = L5.stream().filter(S -> P.matcher(S).find()).collect(
    Collectors.toMap(i -> i, i -> {
      int count = 0;
      while (P.matcher(i).find()) {
        count++;
      }
      return count;
    })
  );
  System.out.println(result);
}

I want to count the instances of "ei" in a map (specifically using streams)


Solution

  • The problem is on line while (P.matcher(i).find()), each time the while loop checking the condition, P.matcher(i) is invoked and a new matcher instance is created to call find(), of course it return true every time, hence it becomes infinite loop.

    To solve the problem, assign P.matcher(i) to a variable first so find() is invoked on the same Matcher instance.

    ...
    Matcher matcher = P.matcher(i);
    while (true) {
        if (!matcher.find()) break;
        count++;
    }
    return count;
    ...
    

    One improvement is we can make use of Matcher.results() to get the count, as below:

    Matcher matcher = P.matcher(i);
    return (int) matcher.results().count();