yan's Handicraft

作成したフリーソフトを公開
Home » PC/システム開発 » Archive by category 'java'

Stream インタフェースを実装して Either を作る

7月 14th, 2016 Posted in java, scala Tags: , , ,

java で開発していると、 Either クラス がほしくなることがあります。(Scala だったらな。。。と思ってしまいます)
関数型ライブラリ http://www.functionaljava.org/ や http://www.javaslang.io/ などを採用すれば、 Either クラスが実装されているのですが、 これらのライブラリを使うと、
java 標準の List 、 Set 、Stream 、Optional を捨てる覚悟がいります。

家で趣味で作る分ならともかく、仕事で参加メンバー全員にこれを強いるのはなかなか勇気がいります。

そこで、java.util.stream.Stream インタフェースを実装した Either クラスを作ることを思いつきました。

Stream は java8の標準ライブラリなので、java の List 、Stream 、Optional は問題なく使えそうです。 そして、 Either も使える。
うまくいきそうな気がします。。。

実装したクラスの配置場所

クラス設計の方針

以下、簡単ですが一応説明します

  • 抽象クラス Either 、具象クラス Either.Left 、 Either.Right を作る。

  • Either.Left が異常系で使用する値クラス。 Either.Right が、正常系に使用する想定の値クラス。

  • Either.Left は、Stream#empty() と同じようなふるまいをする。

  • Either.Right は Stream#of(value) と同じようなふるまいをする。

これから、使ってみようかなと思います。使いやすいのか否かはこれから評価します。

  • Optional も Stream インタフェースを実装した Option とか作れば、不満 も解消するかも。

java8 の OptionalとStreamに対する不満

4月 22nd, 2016 Posted in java, PC/システム開発 Tags: , ,

java8でラムダ式がサポートされて、ある程度やり易くはなったのですが これだけは何とかしてほしかったというグチです。
使っていてすごく不便に感じます

Optional#ofNullable(value) メソッド名長い

Optional#of(value) は、value にnullを渡すと例外を吐くので、使いにくい。 結果、Optional#ofNullable を多用することになるのですが、なんとも長ったらしいメソッド名です。 Optional#of を、 Optional#ofUnnableNull とかにして、 Optional#ofNullable の機能を、 Optional#of としてくれればよかったのに。

いつも、以下の変な別名メソッドつくる羽目になります。

/** {@link Optional#ofNullable(T)} のシノニム */
public static <T> Optional<T> opt(T value){
    return Optional.ofNullable(value);
}

OptionalとStreamとに共通のインタフェースがない

Stream#flatMap に渡す関数の戻り値を Optional にできないのが非常に使いづらい。 共通のインタフェースを定義して受け取れるようにしてほしかったです。 せめて、Stream#flatMap をオーバーロードした

<R> Stream<R> flatMap(Function<? super T, ? extends Optional<? extends R>> mapper);

があるだけでももうちょっと使いやすかったのに。java8に定義されているのは、

<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);

だけ。

final List<Integer> intList = Arrays.asList(new Integer[] { 1, 2, 3, 4,5 });

//これはコンパイル通る。
System.out.println(
        intList.stream().flatMap(num -> Stream.of("'"+ num +"'"))
        .collect(Collectors.toList())
                ); // ['1', '2', '3', '4', '5']

//これはコンパイルエラー。
//intList.stream().flatMap(num -> Optional.of("'"+ num +"'"));


//こんな関数が存在していたとしても、利用できない
final Function<Integer, Optional<String>> f = num -> Optional.of("'"+ num +"'");

//これはコンパイルエラー。
//intList.stream().flatMap(f);

//こんな関数を作らないといけない。イヤダ。
final Function<Integer, Stream<String>> f2 = num -> Stream.of(f.apply(num).get());

System.out.println(
        intList.stream().flatMap(f2)
        .collect(Collectors.toList())
        ); // ['1', '2', '3', '4', '5']
//Optional ==> Stream 変換するstaticユーティリティを作る羽目になる

  • Stream インタフェースを実装して Either を作る と同じようなことをすれば、Optional よりましなものになるかも。 ただ、java8 の標準の Optional があるのに、わざわざ新しく作った Optional を使うほうが使いやすくなるのかという疑問はあります。