Upgrade to Pro — share decks privately, control downloads, hide ads and more …

【Kotlin】【Android】Null安全でぬるぽに立ち向かう

 【Kotlin】【Android】Null安全でぬるぽに立ち向かう

2016.07.09 Kansai.kt #1 用資料です。KotlinのNull安全について調べたことをまとめています。

50a1ae3d2f81998c69a579daeb59f055?s=128

masanori_msl

July 09, 2016
Tweet

Transcript

  1. 【Kotlin】【Android】 Null安全でぬるぽに立ち向かう 2016.07.09 @Kansai.kt

  2. Who? Twitter: @masanori_msl vaguely: http://mslgt.hatenablog.com/ SearchWakayamaToilet: https://play.google.com/store/apps/details? id=jp.searchwakayamatoilet Name: Masui

    Masanori
  3. はじめに Kotlinのいいところ

  4. はじめに Null安全

  5. はじめに Kotlinを使えば、 ぬるぽ(NullPointerException)に サヨナラできる ∩( ・ω・)∩ばんじゃーい

  6. はじめに 本当に?

  7. はじめに 調べてみた

  8. Null許容(Nullable) Kotlinでは、変数をNullにすることが可能か そうでないかが区別される。 var nullableText: String? = null ▪Null許容型(Nullable Type)

    ▪非Null許容型(Non-Null Type) var notNullableText: String = null // ※コンパイルエラー
  9. Null許容(Nullable) 非Null許容型の変数に、Null許容型の変数を代入 するには、後者がNullでないことを保証する必要 がある。 var nullableText: String? = "Not null"

    var notNullableText: String = nullableText!! // OK ※ ではこれは...? var nullableText: String? = null var notNullableText: String = nullableText!!
  10. Null許容(Nullable) KotlinNullPointerExceptionが発生する

  11. Null許容(Nullable) Kotlinではlateinitを付けることで、変数の初期化 のタイミングを変更できる。 … この変数を初期化せずに使うと ? lateinit var lateinitNotNullableText: String

    override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) var notNullableText: String = lateinitNotNullableText var length = lateinitNotNullableText.length }
  12. Null許容(Nullable) UninitializedPropertyAccessExceptionが発生 する lateinit var lateinitNotNullableText: String override fun onCreate(savedInstanceState:

    Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) var notNullableText: String = lateinitNotNullableText // NG ※ var length = lateinitNotNullableText.length // NG ※ }
  13. Null許容(Nullable) Javaのコード上ではNull許容型・非Null許容型の 制限が強制されない。 MainActivity.kt NotNullClass.java - 省略 - public String

    getText(){ return null; // 実行可能 } - 省略 - val notNullableClass = NotNullableClass() val notNullableText: String = notNullableClass.getText() }
  14. Null許容(Nullable) IllegalArgumentExceptionが発生する Java側からKotlinのメソッドを呼ぶときの引数 (非Null許容)にNullを渡そうとする場合は、 @NonNullと同じく警告は表示されるが実行自体 は可能。

  15. Kotlinのいいところ? Kotlinを使うだけで、 ぬるぽにサヨナラできる

  16. Kotlinのいいところ? Kotlinを使うだけで、 ぬるぽにサヨナラできる

  17. Kotlinのいいところ Kotlinを使うと、 ぬるぽを発生させない設計が しやすくなる

  18. Kotlinのいいところ ΩΩΩ < ナ、 ナンダッテー!!

  19. Kotlinに力を借りて、 ぬるぽに立ち向かう ここから本題

  20. Sample SearchWakayamaToilet https://github.com/masanori840816/SearchWakayamaToilet

  21. ぬるぽを無くすには? ぬるぽが嫌なら、 コードからNullを 無くしてしまえばいいじゃない

  22. 非Null許容型にする Nullにならないことを保証できる変数は、Nullを 許容しないことでコードをシンプルにできる。 class MainActivity : AppCompatActivity() { var notNullableText:

    String = "" // Nullを代入しない override fun onCreate(savedInstanceState: Bundle?) { - 省略 - var length = NotNullableText.length // Nullチェックが不要 } } 引数にも適用可能だが、特にコールバックで呼ば れた時に本当にNullが渡されないか確認が必要。
  23. lateinit Nullにならないことは確実だが、宣言時に値が入 れられない変数ではlateinitを使う。 class MainActivity : AppCompatActivity() { lateinit var

    notNullableClass: NotNullableClass // 後で初期化 override fun onCreate(savedInstanceState: Bundle?) { - 省略 - // 宣言時に値が入れられない場合も非Null許容型にできる notNullableClass = NotNullableClass() } }
  24. 非Null許容型にする 例えばMVCにおけるControllerなど、 Nullにできない変数も非Null許容型にする。 プログラム全体が動作しなくなる変数がNullの場 合は、下手に延命するよりエラーなどでアプリを 終了させる方が良い、ということ。

  25. Null許容型を使う コールバックメソッドの引数など、 全部非Null許容型にするのは難しい。 ↓          Null許容型を安全に使いたい

  26. Nullチェック class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?)

    { - 省略 - var nullableText: String? = “Not null” var length = -1 if(nullableText != null){ // Nullチェック // Nullをチェックしているので // ”!.”を使っても安全にlengthを実行可能 length = nullableText!.length } } } 通常のNullチェック
  27. Nullチェック class MainActivity : AppCompatActivity() {  val nullableText: String? =

    “Not null” override fun onCreate(savedInstanceState: Bundle?) { - 省略 - var length = -1 if(nullableText != null){ // Nullチェック // Nullで無いことが保証されるので // 非Null許容の変数と同じように扱うことが可能 length = nullableText.length } } } valを使ってimmutableにできる場合
  28. Nullチェック class MainActivity : AppCompatActivity() {  val nullableText: String? =

    “Not null” override fun onCreate(savedInstanceState: Bundle?) { - 省略 - var length = -1 if(nullableText == null){ // Nullチェック return // Nullなら以下の処理をスキップ } // 非Null許容の変数と同じように扱うことが可能 length = nullableText.length } } これもOK
  29. Nullチェック class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?)

    { - 省略 - var nullableText: String? = “Not null” var length = -1 if(nullableText != null){ // Nullチェック // Nullで無いことが保証されるので // 非Null許容の変数と同じように扱うことが可能 length = nullableText.length } } } ローカル変数ならmutableな変数でもOK
  30. Nullチェック 一度値を入れた後は値を変更しない変数 メソッドに引数として渡される値 ※引数は全てImmutable 使いどころ

  31. ?演算子 Null ” 許容型の変数では、 ?.”を使うことで安全にア クセスできる。 class MainActivity : AppCompatActivity()

    { override fun onCreate(savedInstanceState: Bundle?) { - 省略 - val nullableText: String? = “Not null” // nullableTextならNullが // それ以外はnullableText.lengthの値が入る var length = nullableText?.length } }
  32. ?演算子 ”?.”を使ったチェーンメソッド class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState:

    Bundle?) { - 省略 - val nullableText: String? = “Not null” // nullableText、lengthのどちらかがNullならNullが入る var lengthText = nullableText?.length?.toString() } }
  33. 疑問 この2つのコード、結果は同じ。 var nullableText: String? = “Not null” var nullableNum1:

    Int? = null var nullableNum2: Int? = null // Code 1 if(nullableText != null){ nullableNum1 = nullableText.length NullableNum2 = nullableText.length } // Code2 nullableNum1 = nullableText?.length nullableNum2 = nullableText?.length 実行速度に違いはある?
  34. 疑問 調べてみた

  35. 計測 class MainActivity : AppCompatActivity() { lateinit var logger: TimingLogger

    override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // ログの取得開始. logger = TimingLogger("KtTimingLogger", "Code") // getLengthOfCode1()またはgetLengthOfCode2()を実行 // 測定を終了してログ出力する. logger.dumpToLog() } android.util.TimingLoggerを使って計測
  36. 計測 fun getLengthOfCode1(){ // Code1の検証. var nullableText: String? = "not

    null" var nullableNum1: Int? = null var nullableNum2: Int? = null for(i in 0..1000000) { if (nullableText != null) { nullableNum1 = nullableText.length nullableNum2 = nullableText.length } } logger.addSplit("Code1おしまい") }
  37. 計測 fun getLengthOfCode2(){ // Code2の検証. var nullableText: String? = "not

    null" var nullableNum1: Int? = null var nullableNum2: Int? = null for(i in 0..1000000) { nullableNum1 = nullableText?.length nullableNum2 = nullableText?.length } logger.addSplit("Code2おしまい") }
  38. 結果 Code1 24ms Code2 24ms [検証環境] Android Studio ver. 2.1.2

    [端末] Nexus 9 (Emulator) [OS] Android N
  39. 結果 • “if(x != null)”でチェックする場合も?演算子を使 う場合も、少なくとも今回の検証ではほぼ差が 見られなかった。 • 状況に合わせてよりシンプルに書ける方を選択 するのが良さそう。

  40. Elvis演算子 class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?)

    { - 省略 - var nullableText: String? = null // nullableTextがNull ” の場合のみ ?:”の右の値を代入する nullableText = nullableText?: “Null ” でした // 今回はローカル変数なので、もう一度nullableTextに   // Nullチェック不要を入れるまではNullチェック不要 } } ”?:”を使うことで、変数がNullの場合のみ値を代入 できる。
  41. Elvis演算子 class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?)

    { - 省略 - var nullableText: String? = null // 変数がNullなら以降の処理をスキップ nullableText?: return - 省略 - } } ”?:”を使うと変数がNullの場合はreturnする、とい うことも可能。
  42. まとめ • Kotlinはぬるぽを無くしてくれるわけではない。 • ぬるぽを無くすにはコールバックの引数などア プリの動きをより詳しく把握する必要がある。 • Kotlinの豊富な機能でハッピーな開発ライフを!

  43. 参考 5.4 NULL 安全 - プログラミング言語Kotlin 解説 16 日目:ぬるぽとの別れ -

    Kotlin Advent Calendar 2012 (全部俺) Reference - Kotlin Programming Language 30分で覚えるKotlin 文法 - Qiita https://kotlinlang.org/docs/reference/ https://sites.google.com/site/tarokotlin/chap5/sec54 http://kotlin.hatenablog.jp/entry/2012/12/16/001635 http://qiita.com/k5n/items/cc0377b75d8537ef8a85 http://qiita.com/datsnet/items/1b868ced7c2fa8b4dcb0 処理時間の計測をAndroid で簡単に行う - Qiita
  44. Credit Google Noto Fonts  Main Page:  License: Material

    icons  Main Page:  License: https://www.google.com/get/noto/ SIL Open Font License (OFL) https://design.google.com/icons/ CC-BY License
  45. Enjoy Kotlin Life :)