Easy way to create an implementation of java.util.stream.Stream

Motivation

A typical idiom for processing a regular expression-matched substring using java.regex.Matcher is:

Pattern pattern = Pattern.compile("(cola)+");
Matcher matcher = pattern.matcher("cola, cola, I love cola.");
while (mather.find()) {
  // do something with the current match.
  System.err.println(matcher.group());
}

If you just want to do read-only processing for the matched part, you should be able to write it as stream processing. Like this.

Matcher matcher = pattern.matcher("cola, cola, I love cola.");
matcher.forEach(h -> System.err.println(h.group()); //h is something that represents a match (needs to be defined)

It was good to think that it could be realized by creating an implementation of java.util.stream.Stream that wraps Matcher, but it is difficult to implement because there are too many interfaces and methods. https://docs.oracle.com/javase/jp/9/docs/api/java/util/stream/Stream.html Is there an easy way to implement Stream?

Addendum: Solution for Matcher

The original article listed the general solutions below, but for Matcher you can get the complete answer by usingMatcher # results ()from Java 9. The implementation of this method implements exactly what I wrote above.

Pattern pattern = Pattern.compile("(cola)+");
pattern.matcher("cola, cola, I love cola.").results()
    .forEach(x -> System.err.println(x.group()));

NOTE: Thank you to @ saka1029 for pointing this out. Please refer to the following for the general method of iterating something other than Matcher.

Common solution

As a result of a little research, it was found that the following can be written by combining StreamSupport # stream and Spliterators # spliteratorUnknownSize. As you can see, this method can be applied not only to Matcher but also to the implementation of java.util.Iterator. That's why it's so versatile that I'll make a note of it. [Addition: I understand that this example alone is longer and more complicated than the original code :-)]

RegExTest.java


import java.util.Iterator;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

/**
 * 
 */
public class RegExTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) throws Exception {
		
		final Pattern pattern = Pattern.compile("(cola)+");

		final Stream<Matcher> s = StreamSupport.stream(
			Spliterators.spliteratorUnknownSize(
				new Iterator<Matcher>() {
					final Matcher matcher = pattern.matcher("cola, cola, I love cola.");
					@Override
					public boolean hasNext() {
						return matcher.find();
					}
					@Override
					public Matcher next() {
						return matcher;
					}
				},
				Spliterator.NONNULL | Spliterator.IMMUTABLE),
			false);
		
		//You can now use it in the same way as the example at the beginning!
		s.forEach(m -> System.err.println(m.group()));
	}

}

Addendum: How to avoid implementing java.util.Iterator

@ saka1029 pointed out again, the method Stream # iterate provided by Java9 of java.util.stream.Stream. Using api / java / util / stream / Stream.html # iterate (T, java.util.function.Predicate, java.util.function.UnaryOperator)), it is beautiful without implementing ʻIterator` as shown below. I learned that I can write in. Thank you, @ saka1029. I'm glad that Java9 provided this new way of writing, because there would have been many people other than me who wished I could write it like this.

final Pattern pattern = Pattern.compile("(cola)+");
Stream.iterate(pattern.matcher("cola, cola, I love cola."), m -> m.find(), m -> m)
    .forEach(m -> System.out.println(m.group()));

Recommended Posts

Easy way to create an implementation of java.util.stream.Stream
Easy way to create JSP custom tags
Easy way to create an original logo for your application (easy with your smartphone)
Mandels to create an image of the Mandelbrot set
How to create an application
Easy to create Processing library
Easy implementation of Android file browsing
[Rails] Easy way to check columns
Easy way to create a mapping class when using the API
An easy way to cache method calls with Ruby's native extensions
Easy way to set iOS app icon
How to blur an image (super easy)
Java implementation to create and solve mazes
Convert an array of strings to numbers
[Apache Camel] Easy output of throughput to log
Summary of how to create JSF self-made tags
[Rails] Implementation of "notify notification in some way"
Create assert_equal to make it easy to write tests
Super easy way to use enum with JSP
Rails6.0 ~ How to create an eco-friendly development environment
How to create an oleore certificate (SSL certificate, self-signed certificate)
[No need for Gem! !! HTML & CSS only] Easy way for beginners to create drop-down menus
Implementation of GKAccessPoint