Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

はじめに Kotlinのいいところ

Slide 4

Slide 4 text

はじめに Null安全

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

はじめに 本当に?

Slide 7

Slide 7 text

はじめに 調べてみた

Slide 8

Slide 8 text

Null許容(Nullable) Kotlinでは、変数をNullにすることが可能か そうでないかが区別される。 var nullableText: String? = null ■Null許容型(Nullable Type) ■非Null許容型(Non-Null Type) var notNullableText: String = null // ※コンパイルエラー

Slide 9

Slide 9 text

Null許容(Nullable) 非Null許容型の変数に、Null許容型の変数を代入 するには、後者がNullでないことを保証する必要 がある。 var nullableText: String? = "Not null" var notNullableText: String = nullableText!! // OK ※ ではこれは...? var nullableText: String? = null var notNullableText: String = nullableText!!

Slide 10

Slide 10 text

Null許容(Nullable) KotlinNullPointerExceptionが発生する

Slide 11

Slide 11 text

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 }

Slide 12

Slide 12 text

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 ※ }

Slide 13

Slide 13 text

Null許容(Nullable) Javaのコード上ではNull許容型・非Null許容型の 制限が強制されない。 MainActivity.kt NotNullClass.java - 省略 - public String getText(){ return null; // 実行可能 } - 省略 - val notNullableClass = NotNullableClass() val notNullableText: String = notNullableClass.getText() }

Slide 14

Slide 14 text

Null許容(Nullable) IllegalArgumentExceptionが発生する Java側からKotlinのメソッドを呼ぶときの引数 (非Null許容)にNullを渡そうとする場合は、 @NonNullと同じく警告は表示されるが実行自体 は可能。

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

非Null許容型にする Nullにならないことを保証できる変数は、Nullを 許容しないことでコードをシンプルにできる。 class MainActivity : AppCompatActivity() { var notNullableText: String = "" // Nullを代入しない override fun onCreate(savedInstanceState: Bundle?) { - 省略 - var length = NotNullableText.length // Nullチェックが不要 } } 引数にも適用可能だが、特にコールバックで呼ば れた時に本当にNullが渡されないか確認が必要。

Slide 23

Slide 23 text

lateinit Nullにならないことは確実だが、宣言時に値が入 れられない変数ではlateinitを使う。 class MainActivity : AppCompatActivity() { lateinit var notNullableClass: NotNullableClass // 後で初期化 override fun onCreate(savedInstanceState: Bundle?) { - 省略 - // 宣言時に値が入れられない場合も非Null許容型にできる notNullableClass = NotNullableClass() } }

Slide 24

Slide 24 text

非Null許容型にする 例えばMVCにおけるControllerなど、 Nullにできない変数も非Null許容型にする。 プログラム全体が動作しなくなる変数がNullの場 合は、下手に延命するよりエラーなどでアプリを 終了させる方が良い、ということ。

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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チェック

Slide 27

Slide 27 text

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にできる場合

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

Nullチェック 一度値を入れた後は値を変更しない変数 メソッドに引数として渡される値 ※引数は全てImmutable 使いどころ

Slide 31

Slide 31 text

?演算子 Null ” 許容型の変数では、 ?.”を使うことで安全にア クセスできる。 class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { - 省略 - val nullableText: String? = “Not null” // nullableTextならNullが // それ以外はnullableText.lengthの値が入る var length = nullableText?.length } }

Slide 32

Slide 32 text

?演算子 ”?.”を使ったチェーンメソッド class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { - 省略 - val nullableText: String? = “Not null” // nullableText、lengthのどちらかがNullならNullが入る var lengthText = nullableText?.length?.toString() } }

Slide 33

Slide 33 text

疑問 この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 実行速度に違いはある?

Slide 34

Slide 34 text

疑問 調べてみた

Slide 35

Slide 35 text

計測 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を使って計測

Slide 36

Slide 36 text

計測 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おしまい") }

Slide 37

Slide 37 text

計測 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おしまい") }

Slide 38

Slide 38 text

結果 Code1 24ms Code2 24ms [検証環境] Android Studio ver. 2.1.2 [端末] Nexus 9 (Emulator) [OS] Android N

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

Elvis演算子 class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { - 省略 - var nullableText: String? = null // 変数がNullなら以降の処理をスキップ nullableText?: return - 省略 - } } ”?:”を使うと変数がNullの場合はreturnする、とい うことも可能。

Slide 42

Slide 42 text

まとめ ● Kotlinはぬるぽを無くしてくれるわけではない。 ● ぬるぽを無くすにはコールバックの引数などア プリの動きをより詳しく把握する必要がある。 ● Kotlinの豊富な機能でハッピーな開発ライフを!

Slide 43

Slide 43 text

参考 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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

Enjoy Kotlin Life :)