Javaの関数型プログラミングライブラリVavrについて
はじめに
今取り組んでいるプロジェクトで久々にJavaのコードを書いていたらVavrというライブラリを使っているのを見つけました。 使ったことがないライブラリだったのですが、面白かったので少し調べてみました。 興味が続く限りネタにしてみたいと思います。
Vavrとは
ドキュメントによると次のデータ型や制御機能を提供することでJavaでの関数型プログラミングを実現します。
- データ型
- ScalaのIterable相当のコレクション(イミュータブルで永続的なデータ構造)
- Stream
- Tuple
- Function(arity 0-8の関数オブジェクト。合成したり、リフティングやカリー化もサポートしている)
- モナド
- Option
- Try
- Lazy
- Either
- Future
- Validation
- パターンマッチ
ちなみに公式ページには以下のように説明されています。
Vavr core is a functional library for Java. It helps to reduce the amount of code and to increase the robustness. A first step towards functional programming is to start thinking in immutable values. Vavr provides immutable collections and the necessary functions and control structures to operate on these values. The results are beautiful and just work.
すごい!便利そう!!
どうやって使ったらいいのか?
とても便利そうですが、コレクション、ストリーム、Option(Optional)、FutureについてはJavaの標準ライブラリに類似したAPIがあるし、互換性や、将来の変更を考えるとVavrをコンポーネントの公開APIのシグネチャに使うには不安があります。
どのように使うのか検討するために標準ライブラリや他のライブラリでの類似の実装を比較してみようと思います。
各ライブラリでのOptionの比較
手始めによく使うOptionの比較をしてみます。
プロジェクトで使っているライブラリから3つの実装をピックアップしました。
- guava (
com.google.common.base.Optional<T>
) - vavr (
io.vavr.control.Option<T>
) - java標準ライブラリ(
java.util.Optional<T>
)
以下ではguavaとvavrの特徴を整理しています。
com.google.common.base.Optional
guavaのOptionalはJDK8でOptionalが導入される以前から存在していました。 その経緯からか、ドキュメントには下記のように標準ライブラリとの比較が書かれています。
- This class is serializable; java.util.Optional is not.
- java.util.Optional has the additional methods ifPresent, filter, flatMap, and orElseThrow.
- java.util offers the primitive-specialized versions OptionalInt, OptionalLong and OptionalDouble, the use of which is recommended; Guava does not have these.
個人的には次の差異が気になりました。
transform
(map
相当)のnullの扱い- 関数がnullを返すと例外をスローする、標準ライブラリはemptyを返す
filter
,flatMap
がない- これはどう考えても欲しい
toSet
が便利かもしれない- 値があるときはその値を含むセット、ないときは空のセットを返す
- 有効な値がないときに空のコレクションを使うパターンで使えるがOptionalをそのまま使うから要らない気もする・・・
presentInstances(Iterable<Optional>)
- 引数の
Iterable<Optional>
のうち値が存在するものだけを返す - 便利そうだけど(ドキュメントにも書かれてい通り)コレクションに
filter
があれば要らない
- 引数の
ドキュメントには次のように標準ライブラリ使ってね、という記載があるので、新たに書き始めるコードでは使わないほうが良さそうです。
There are no plans to deprecate this class in the foreseeable future. However, we do gently recommend that you prefer the new, standard Java class whenever possible.
io.vavr.control.Option
ドキュメントでは下記のように紹介されています
- 具象型として
Some
,None
が定義されている(他の実装では公開されている型はOptionalだけで、具象クラスはパッケージプライベートか、そもそもOptional自体が具象クラスになっている) map
の引数の関数がnull
を返すときemptyに変換されずnullを保持する
特に後者について、設計の背景がVarvrブログ「The agonizing death of an astronaut」やこちらの記事「Why java.util.Optional is broken」で説明されています。
一旦まとめ
さて、ここまでで次のことがわかりました。
- 値がない場合の
map
の振る舞いが3つのライブラリで異なる - 標準ライブラリの
Optional#map
の「nullをemptyに置き換えてしまう挙動」を問題視する意見がある
このmapの問題について検討しないと、どのような場合に使える/問題があるのかはっきりしません。 今回は長くなってきたのでここまでにして、改めてこの問題についてまとめたいと思います。