Javaのstreamで嵌る
IntStream
とStream<T>
インターフェースに親子関係がない
java.lang.AutoCloseable java.util.stream.BaseStream<T,S> java.util.stream.DoubleStream java.util.stream.IntStream java.util.stream.LongStream java.util.stream.Stream<T>
そのために(?)、IntSteram
に3つの引数をもつreduce
がない。これに気がつかず、相当時間を無駄にした。
順次および並列の集約操作をサポートするプリミティブint値要素のシーケンスです。これは、Streamに対してintプリミティブ特殊化を行ったものです。
とドキュメントにはあるが、特殊化といっても型だけ特殊化されているのではない。
多分、このようなクラス階層になっているのは、IntStream
はInteger
ではなくint
だからなんだろうけど。
Stream
インターフェースの2つの引数を持つreduce
と3つの引数を持つreduce
で2番目のパラメータ部分の型が異なる。
2引数
reduce(T identity, BinaryOperator
accumulator)
3引数
reduce(U identity, BiFunction; < U,? super T,U > accumulator, BinaryOperator < U > combiner)
2引数の場合、BinaryOperator
の型がT
なので、accumlator
の型はStream
の型と同じ必要がある。
また、実際のコーディングでは、3引数のcombiner
のコーディングが定型的になる(と思うので)冗長になる。
intelliJで型推論が微妙にずれている
3引数reduce
でパラメータの3番目が間違っているのに、2番目のエラーがでる。javacでは3番目のパラメータのコンパイルエラーになる。
単位元?
T reduce(T identity, BinaryOperator
accumulator) 指定された単位元の値と結合的な累積関数を使ってこのストリームの要素に対してリダクションを実行し、リデュースされた値を返します。これは、次の操作に相当します。
足し算の単位元は0だけど、0でなくても動作する。
int r = Stream.of(1,2,3).reduce(10, (x,y) -> x + y); System.out.println(r); // 16
サンプル
Snake case
とCamel case
の返還をstream
やラムダで書くといい感じになるかなと思ったのですが、そうでもないですね。
private static String toCamel(String str) { return Arrays.stream(str.split("_")) .map(x -> x.substring(0,1).toUpperCase() + x.substring(1).toLowerCase()) .collect(Collectors.joining()); } private static String toSnake(String in) { String out = in.codePoints() .mapToObj(c -> (char)c) // IntStream to Stream<Character> .reduce("" , (acc, v) -> acc + (Character.isLowerCase(v) ? v : "_" + Character.toLowerCase(v)) , (s1, s2) -> s1 + s2 ); return out; }
もっと簡潔にかけるのなら教えて下さい。
感想
Java
のstream
は、慣れてないだけかもしれないが、難しい。というか面倒。
reduce
は可読性が上がらなさそう。結局2変数の関数を作らないといけないこともあるので。
stream
処理を考えた時には、reduce
を使わない範囲で使うと良いのではないか。
reduce
使うくらいならfor
でループして処理するのが良さそう。