iOS/iPhone/iPad/watchOS/tvOS/MacOSX/Android プログラミング, Objective-C, Cocoa, Swiftなど
Javaでは結果を関数の戻る値で、エラー情報は例外で、だったが、Androidは例外を勧めていないことは以前から感じていた。Kotlinでは、例外は復旧できない致命的な状況で利用とし、既存のJavaモジュールが投げてくる例外を包み込みResult型があったりしている。
自分でKotlinでプログラミングする際、あえて例外を利用する必要はないと思うので、どんなやり方が合うのか調べてみて辿り着いたコードを紹介する。参考にしたのは、ここ。
AndroidはActivityやFragmentが再生成されるということから、ActivityやFragmentのメンバー変数でModelを持たないだとか、再生成されてもModelが破棄されない。ModelはActivityやFragmentをメンバー変数で持っていると再生されると破棄されたものにアクセスしてしまう問題がある。それの解決策としてJetpackのViewModelやLiveDataがあるのだが、LiveDataではエラーを例外で渡せない。結果とエラー情報がLiveDataとなっているのが扱いやすいということがあるので、結果とエラー情報を持つ型を用意することにした。
sealed class FindUserResult {
data class Found(val user: User) : FindUserResult()
data class NotFound(val name: String) : FindUserResult()
}
Swiftだとenumを利用すればだが、Kotlinのenum classは状態を定数で持つだけ。その代わり、sealed classを使えば値を持てる。そして、サブクラスを用意することによって、状態を持てる。
上の例では、FindUserResultのサブクラスがFoundとNotFoundになっていて 、プライマリコンストラクタでそれぞれのプロパティのuserとnameを宣言している。
この型を戻り値にした関数がこれ。
fun findUserByName(name: String): FindUserResult {
....
if (見つかった) return FindUserResult.Found(user)
else return FindUserResult.NotFound(name)
}
成功したらFoundを返している。失敗の場合はNotFoundを返している。処理の結果や、エラー情報はコンストラクタのパラメータで設定している。
この戻り値を受け取った側のコードがこれ。
val result = findUserByName("bitz")
when (result) {
is FindUserResult.Found -> println("find ${result.user}")
is FindUserResult.NotFound ->println("find ${result.name}")
}
型で成功か失敗が分かり、プロパティで結果やエラー情報が取れる。