Koptional - Kotlin版本的简约Optional类型

711 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

What's Optional?

Optional是一个容器对象, 用于包含非空对象. Optional对象不包含值时表示的是null. 与检测null值相反, 该对象有不同的工具方法用于促进代码来处理"可用"和"不可用"的值. OptionalJava 8 中首次引入, 且与 Guava 中的Optional相似.

Java Optional API

Optional的工具方法有:

  • static <T> Optional<T> empty(): 提供空的Optional实例.
  • static <T> Optional<T> of(T value): 提供包含非null值的Optional实例.
  • static <T> Optional<T> ofNullable(T value): value为非null时, 作用等同于of(T value), 而valuenull时, 作用等同于empty().

更多请查看

What's Koptional

Koptional是Kotlin版本的简约Optional类型.

Kotlin本身并不需要Optional类型, 因为它有强空安全系统, 该系统事实上终止了这种封装的需求. 然而有一些Java API和库, 像RxJava 2RxJava 3, 并不接受null值, Kotlin语言层面的可空性对此无能为力.

在许多场景下, 可以通过sealed class来表示空值. 然而在一些简单的场景下, 比如在RxJava流中传递String?, Optional是更方便的解决方案.

Koptional的目的是为了使用和适配Kotlin的空安全更加地方便, 由此引起:

  • 只有2个函数: toOptional()toNullable().
    • 模拟了类似于toInt()toBoolean()的函数.
  • SomeNone被声明为顶级类型.
    • 不需要写Optional.SomeOptional.None.
  • 没有map()getOrElse()filter()等函数.
    • 使用toNullable()和Kotlin标准库函数, 如let, takeIf等.

Usage

创建

val some = Some(value)
val none = None // It's an object!

转化

// T? → Optional<T>
// If value is null — you'll get None, otherwise you'll get Some(value).
val o = value.toOptional()

// Optional<T> → T?
// If optional is None — you'll get null, otherwise you'll get non-null T value.
val t = optional.toNullable()

充分利用Kotlin的特性

回退到None (类似于java.util.Optional.getOrElse()函数)

val f = optional.toNullable() ?: "fallback"

智能类型转换

when (optional) {
    is Some -> println(optional.value)
    is None -> println("Nope!")
}

解构

// If Optional is None — you'll get null, otherwise you'll get non-null T value.
val (value) = optional

与Java的交互访问

使用静态方法Optional.toOptional()T类型实例封闭进Optional<T>.

RxJava扩展

val values = Observable.just(Some("a"), None, Some("b"))

// Filter Some values.
values
    .filterSome()
    .test()
    .assertValues("a", "b")

// Filter None values.
values
    .filterNone()
    .test()
    .assertValues(Unit) // filterNone() maps None to Unit.

Reactor扩展

val values = Flux.just(Some("a"), None, Some("b"))

// Filter Some values.
values.filterSome()

// Filter None values.
values.filterNone()