Lightweight-Stream-APIのStreamにequalsOnlyを実装した話

Lightweight-Stream-APIとは?

Stream API from Java 8 rewritten on iterators for Java 7 and below.

Java 8から導入されたStreamのようなものをJava 7以前で使うためのLibrary

Streamについては調べればいくらでも資料はあるので詳細は割愛します

StreamだけでなくOptionalも実装されているため、AndroidでStream + Optionalを使いたい場合によいLibraryで私はよく使ってます(Kotlinの場合はそこまで必要としませんが...

github.com

Lightweight-Stream-API 特有の中間操作(intermediate operation)

Lightweight-Stream-APIのStreamには、Library特有の便利な中間操作(intermediate operation)が実装されてます

例えば、要素のうちnull以外でfilterする withoutNulls は便利ですね

Stream.of("a", null, "b")
        .withoutNulls()
        .forEach(System.out::println);
// 結果:
// a
// b

このような便利な中間操作はJava 8以降のStreamには実装されていません

Libraryだからこそさくっと便利なものが実装できるのはLightweight-Stream-APIのいいところですね

他にもLightweight-Stream-API 特有の実装はいくつかあるので気になる人は見てみてください!

独自に実装してるとはいえそこまで複雑ではなく、自分でも拡張できそうだなーと思って、今回equalsOnlyという中間操作(intermediate operation)のメソッドを実装してPull Requestを出してみました

equalsOnly - 要素のうち指定したオブジェクトと同じものだけでfilterする

どんなものを実装したのかはごちゃごちゃ説明するよりコードを見てもらうほうが早いです

流れてくる各要素をメソッドの引数で渡すobjectと同じかどうかをチェックしてfilterしてるだけです

/**
* Returns {@code Stream} with elements that is equality of {@code object} only.
* <p>
* <p>This is an intermediate operation.
*
* @param object object
* @return the new stream
*/
public Stream<T> equalsOnly(final T object) {
    return filter(new Predicate<T>() {
        @Override
        public boolean test(T value) {
            return Objects.equals(value, object);
        }
    });
}

ね?実装簡単でしょ!

んで、使い方は以下のような感じでマッチしたものだけ後続のStreamに流れる仕組みです

List<String> match = Stream.of("a", "b", "c")
        .equalsOnly("b")
        .toList();
// match -> ["b"]

どうしてequalsOnlyがほしかったのか

私がやっているプロジェクトのコードでfilterしてequalsするみたいなコードが度々出現していて「これ書くの面倒なー」と思っていたので、実装も楽だしワンチャン提案してみるかーと思った感じです

例えば雑に説明すると、以下のようにfilter内でequalsだけを条件としてる箇所がざっくり数えるだけでも30ヶ所はあるんですよねー

Stream.of("a", "b", "c")
        .filter(s -> Objects.equals(s, "b"))
        .(以降処理は続く...

これをさくっと書きたい! equalsOnlyみたいなの作ればさくっと書けるはず!と思って仕事中に実装して、提案してみた感じです

次のリリースがされたらequalsOnly使えるようになると思うので、同じようにほしかった!!という人は使ってほしい気持ち!!

Pull Requestわりと雑に出したけど案外あっさりMergeされた

とりあえず提案程度にコード書いてみたぞい!って気持ちをぶつけたかったので雑に[Proposal]って頭につけて、Pull Requestの概要にも実装したequalsOnlyの使い方だけわかるコードを書いてみた

実際のPull Requestは以下です

github.com

同僚には「それはさすがにMergeされないのではー?」って言われて、「せやな」って気持ちだったけど、朝起きてみたらMergeされてた

Javadocとテストコードをちゃんと書いておいてよかったなーという気持ち

Libraryとしてテストコード書くっぽい! + 勝手にCI回ってテストしてくれる!というのは、コントリビュートする側としてはなんか安心するので良いなーと思った

実装されたものがいい感じでテストも書いて通ってれば、ごちゃごちゃ英語で説明書かなくても通じる世界はある!みたいなとても楽観的な考えでやっていきだなーと思った次第です

とはいえ私みたいなのが量産されるのは微妙なので、英語はちゃんとできるようになりたいものです...

v1.2.0で実装したequalsOnlyが追加されてました - 2018/06/20 追記

めでたい!

Added Stream.equalsOnly operator (thanks to @operando)

github.com

Lightweight-Stream-API もっと便利になってほしい!!

無法地帯にならない程度に便利なメソッドなど増えてほしいぞ!!

私も他に便利そうなの思いついたらまたPull Request出すぞ!!