try-catchからrunCatchingに_移行した話.pdf

Ef3f8e0806816bdcd19ff2a1b813bd24?s=47 yuki anzai
August 24, 2019

 try-catchからrunCatchingに_移行した話.pdf

Ef3f8e0806816bdcd19ff2a1b813bd24?s=128

yuki anzai

August 24, 2019
Tweet

Transcript

  1. try-catchからrunCatchingに 移行した話 安齋祐紀 (@off2white)

  2. 自己紹介 安齋祐紀(あんざいゆうき) Twitter: @off2white 株式会社 ディー・エヌ・エー(DeNA) - 次世代タクシー配車サービス「 MOV」 -

    Androidアプリ開発担当 - プロジェクト管理とコーディングの割合 = 50:50 (気持ちは) 最近の悩み いまだに運営さんが採択時に 人を間違えていなかったのか心配
  3. None
  4. 背景 個人的エラーハンドリング の変遷

  5. その1
 むやみに例外を使わなくなった

  6. ClassA ClassB ClassC Exception New ClassD 誰が Catch する? NewException

    Not For Me Exception ?
  7. ClassA ClassB ClassC sealed class New ClassD I Like sealed

    class sealed class
  8. ViewModel Repository Api Exception New DB ただし現実的にはこんな感じ sealed class Exception

  9. その2
 Crashlyticsの発達によって 細かくExceptionをCatchする必要が なくなった

  10. 蘇る悪夢 try {
 response = apiRequest.execute() 
 dao.save(response.toEntity())
 
 }

    catch (e: IOException) {
 errorCode += “01”
 throw NetworkException(errorCode) 
 
 } catch (e: SQLException) {
 errorCode += “03”
 throw GeneralException(errorCode) 
 
 } catch (e: Throwable) {
 errorCode += “04”
 throw SystemException(errorCode) 
 
 }

  11. その3
 Rx -> Coroutineへの移行

  12. Rx では success と error 時の処理を 分けて記載できた repository.fetchData()
 
 .subscribeBy

    (
 onNext = { livedata.postValue(it)},
 
 onError = { Timber.e(it) }
 )
 実 行 系 正 常 系 異 常 系
  13. もっと良いエラーハンドリングの書き方はないのか


  14. runCatching (Kotlin 1.3)


  15. runCatching {
 apiRequest.execute()
 } 
 
 or 
 
 apiRequest.execute()


    .runCatching {
 dao.save(it.toEntity())
 } 
 こんな感じで書く
  16. 
 runCatchingは Resultクラスを返却する

  17. 成功結果と例外を カプセル化してくれる

  18. val result = runCatching {
 apiRequest.execute()
 }
 
 if (result.isFailure)

    {
 Timber.e(
 result.exceptionOrNull()
 )
 return
 }
 処理結果を受け取って 返却してくれる
  19. runCatching {
 apiRequest.execute()
 }.onSuccess {
 dao.save(it.toEntity())
 }.onFailure {
 Timber.e(it)
 }


    成功処理と失敗処理を 分けて記載できる 実 行 系 正 常 系 異 常 系
  20. runCatching {
 apiRequest.execute()
 }.mapCatching {
 dao.save(it.toEntity())
 }.onSucess {
 …
 }.onFailure

    {
 ...
 }
 map 時も Catch できる
  21. runCatching {
 apiRequest.execute()
 }.recoverCatching {
 Response.default()
 }
 例外処理のリカバリ処 理も綺麗にかける

  22. 
 これは是非使うべき!!!

  23. 結論
 案外不評


  24. try {
 res = apiClient.execute()
 dao.save(res.toEntity())
 }
 catch (e: Exception)

    {
 Timber.e(e)
 } 
 正常パスと 例外処理で 別れている方が 好みの人もいる 正 常 パ ス 例 外 処 理 理由その1

  25. val a: Int? = 
 try { parseInt(input) } catch

    (e: Exception) 
 { null }
 Kotlin の try-catch は式 として書けるので それで十分説 理由その2

  26. val a: Int? = 
 try { parseInt(input) } catch

    (e: Exception) 
 { null }
 finally { ... }
 try-catch なら finally で 明示的に書ける (runCatching ではできない ) 理由その3

  27. return runCatching {
 …
 }
 Result 型は return できない 理由その4


  28. fun function() : Int {
 runCatching {
 "5".toInt()
 }.onSuccess {


    return@function it
 }.onFailure {
 return@function 0
 }
 // ここにreturnが必要
 }
 a ‘return’ expression required in a function with a block body 理由その5

  29. (;Ծ﹏Ծ)ぐぬぬ


  30. runCatching {
 runFunction()
 }.onSuccess {
 dispatch(Action.Success)
 }.onFailure {
 dispatch(Action.Failure)
 }


    現状は return しない ところで そっと使っている ActionCreator の dispatch とか ViewModel の LiveData.postValue とか
  31. Resultクラスの
 KEEPでの議論が面白いので
 ぜひ読んでね!