java.util.stream.Stream の実装を手軽に作成する方法
動機
java.regex.Matcher
を使って正規表現にマッチした部分文字列を処理する典型的なイディオムは以下である.
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());
}
マッチした箇所に対する read-only な処理をするだけなら,ストリーム処理として書けるべきであろう.こんなふうに.
Matcher matcher = pattern.matcher("cola, cola, I love cola.");
matcher.forEach(h -> System.err.println(h.group()); // h はマッチした箇所を表す何か(定義する必要がある)
Matcher
をラップするjava.util.stream.Stream
の実装を作れば実現できる,と思ったのは良かったが,このインタフェース,メソッドが多すぎて実装するのが大変である.
https://docs.oracle.com/javase/jp/9/docs/api/java/util/stream/Stream.html
Stream
を簡単に実装する方法があるだろうか?
追記: Matcher
に対する解決方法
もとの記事では,下にある一般的な解決方法を挙げていたが,Matcher
に関してはJava9からMatcher#results()
を使うと完全な答えが得られる.このメソッドの実装が,まさに上で書いたやりたいことを実装してくれている.
Pattern pattern = Pattern.compile("(cola)+");
pattern.matcher("cola, cola, I love cola.").results()
.forEach(x -> System.err.println(x.group()));
NOTE: ご指摘下さった @saka1029 さん,ありがとうございました.
なお,Matcher
以外に何かを iterate したい一般的な場合の手法は以下を参照して下さい.
一般的な解決方法
少し調べた結果,StreamSupport#stream
と Spliterators#spliteratorUnknownSize
を組み合わせることにより,以下のように書けることがわかった.
この方法は,すぐわかるようにMatcher
に限らずjava.util.Iterator
の実装に帰着すれば何でも適用可能である.
というわけで,汎用性が高いのでメモしておく次第である.
【追記: この例だけを見れば元のコードより長く複雑になっている,ということは理解しております :-)】
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);
// 冒頭の例と同じ使い方ができるようになった!
s.forEach(m -> System.err.println(m.group()));
}
}
追記: java.util.Iterator
を実装せずに済む方法
@saka1029 さんに再びご指摘頂き,java.util.stream.Stream
の Java9 から提供されているメソッド Stream#iterate を使うと,以下のように Iterator
を実装せずとも綺麗に書けることを知りました.@saka1029 さん,ありがとうございます.Java9 で新しくこの書き方が提供されたということは,こんなふうに書けたらいいのになと思った人が私以外に大勢いたであろうということで,うれしいです.
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()));
Author And Source
この問題について(java.util.stream.Stream の実装を手軽に作成する方法), 我々は、より多くの情報をここで見つけました https://qiita.com/daylife/items/3c77a4d958abe3155e2a著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .