SQLをJavaアプリ側で動的に組み立てる処理を書いていて、StringJoinerがなかなか便利だな、と感じました。
これまでは引数が一つのコンストラクタを使い、愚直にaddしていく使い道しか知らなかったのですが、引数3つのコンストラクタさんとmerge
メソッドさんつよつよ。Stream
の`collect(Collectors.joining("")と同じでは
わたしが今までしていた単純な使い方
StringJoiner sj = new StringJoiner(",");
sj.add("a");
sj.add("b");
sj.add("c");
assertThat(sj.toString(), is("a,b,c");
てな具合で、文字列をくっつけることができますね。
ループでくっつけるようなことをすると、末尾の","に関して制御をしなければならないので、それに比べたら楽だしわかりやすい。
Streamで書き直すと以下のような感じ。
Stream.of("a", "b", "c").collect(Collectors.joining(","));
こっちの方が断然シンプルだ。
ただ、引数の数が多いとか、パターンに応じて値を変えたりなど複雑になってくると、Collectionと関数型インターフェース、map
とfilter
でなどを組みあわせて実現しないと可読性が下がりますね。
コンストラクタにprefixとsuffix的なのを渡せる
StringJoiner sj = new StringJoiner(",", "[", "]");
sj.add("a");
sj.add("b");
sj.add("c");
assertThat(sj.toString(), is("[a,b,c]");
わー便利。
当然、空文字指定も可能なので
StringJoiner sj = new StringJoiner(",", "SELECT ", "");
sj.add("column1");
sj.add("column2");
assertThat(sj.toString(), is("SELECT column1,column2");
このようなこともできます。すごい。
mergeメソッドでくっつける
merge
メソッドは二つのStringJoinerを合成します。
合成するといっても、引数で渡したStringJoinerをprefix、suffixを無視してtoString()したものを呼び出した側に一つの要素として使いするイメージです。
同じ区切り文字だと複数回add
を行ったのと同じ結果になります。
StringJoiner sj1 = new StringJoiner(" ");
sj1.add("table_name");
sj1.add("on");
StringJoiner sj2 = new StringJoiner(" AND ");
sj2.add("column1 = column2");
sj2.add("column3 = column4");
sj2.add("column5 = column6");
assertThat(sj1.merge(sj2).toString(), is("table_name on column1 = column2 AND column3 = column4 AND column5 = column6"));
先述の通り、引数で渡した側のprefix、suffixは無視されるのでそこは注意ですね。
StringJoiner sj1 = new StringJoiner(",", "[" , "]");
sj1.add("hoge");
sj1.add("moge");
StringJoiner sj2 = new StringJoiner(":", "<", ">");
sj2.add("foo");
sj2.add("bar");
sj2.add("baz");
StringJoiner merged = sj1.merge(sj2);
merged.add("the end");
assertThat(merged.toString(), is("[hoge,moge,foo:bar:baz,the end]"));