Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
【Kotlin】【Android】Null安全でぬるぽに立ち向かう
Search
masanori_msl
July 09, 2016
Programming
2
2.4k
【Kotlin】【Android】Null安全でぬるぽに立ち向かう
2016.07.09 Kansai.kt #1 用資料です。KotlinのNull安全について調べたことをまとめています。
masanori_msl
July 09, 2016
Tweet
Share
More Decks by masanori_msl
See All by masanori_msl
WPFで印刷しよう!
masui_masanori
1
840
Programming ASP.NETCore を推したい話
masui_masanori
0
210
C#erがTypeScriptでフロントエンドに挑戦している話
masui_masanori
0
210
ASP.NET CoreやTypeScriptの力を借りてレガシー寄りの環境に立ち向かいたかった話
masui_masanori
1
180
やっぱりわからんTaskの話
masui_masanori
0
100
AzurePipelinesでコンティニュアスにインテグレーションしたい
masui_masanori
0
1.4k
Razorに触れてみた
masui_masanori
0
64
ASP.NET Coreに入門した話
masui_masanori
0
250
Compare Java's 'var' with C#'s 'var'.
masui_masanori
0
1.3k
Other Decks in Programming
See All in Programming
Итераторы в Go 1.23: зачем они нужны, как использовать, и насколько они быстрые?
lamodatech
0
1k
PHPUnitしか使ってこなかった 一般PHPerがPestに乗り換えた実録
mashirou1234
0
340
生成AIでGitHubソースコード取得して仕様書を作成
shukob
0
540
オニオンアーキテクチャを使って、 Unityと.NETでコードを共有する
soi013
0
110
【re:Growth 2024】 Aurora DSQL をちゃんと話します!
maroon1st
0
810
Amazon S3 NYJavaSIG 2024-12-12
sullis
0
110
暇に任せてProxmoxコンソール 作ってみました
karugamo
2
740
快速入門可觀測性
blueswen
0
420
バグを見つけた?それAppleに直してもらおう!
uetyo
0
190
Beyond ORM
77web
9
1.3k
Внедряем бюджетирование, или Как сделать хорошо?
lamodatech
0
440
良いユニットテストを書こう
mototakatsu
9
3.2k
Featured
See All Featured
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
32
2.7k
The Art of Programming - Codeland 2020
erikaheidi
53
13k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
132
33k
Side Projects
sachag
452
42k
Mobile First: as difficult as doing things right
swwweet
222
9k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
656
59k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
44
6.9k
Raft: Consensus for Rubyists
vanstee
137
6.7k
GraphQLとの向き合い方2022年版
quramy
44
13k
The Pragmatic Product Professional
lauravandoore
32
6.3k
How STYLIGHT went responsive
nonsquared
96
5.2k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
111
49k
Transcript
【Kotlin】【Android】 Null安全でぬるぽに立ち向かう 2016.07.09 @Kansai.kt
Who? Twitter: @masanori_msl vaguely: http://mslgt.hatenablog.com/ SearchWakayamaToilet: https://play.google.com/store/apps/details? id=jp.searchwakayamatoilet Name: Masui
Masanori
はじめに Kotlinのいいところ
はじめに Null安全
はじめに Kotlinを使えば、 ぬるぽ(NullPointerException)に サヨナラできる ∩( ・ω・)∩ばんじゃーい
はじめに 本当に?
はじめに 調べてみた
Null許容(Nullable) Kotlinでは、変数をNullにすることが可能か そうでないかが区別される。 var nullableText: String? = null ▪Null許容型(Nullable Type)
▪非Null許容型(Non-Null Type) var notNullableText: String = null // ※コンパイルエラー
Null許容(Nullable) 非Null許容型の変数に、Null許容型の変数を代入 するには、後者がNullでないことを保証する必要 がある。 var nullableText: String? = "Not null"
var notNullableText: String = nullableText!! // OK ※ ではこれは...? var nullableText: String? = null var notNullableText: String = nullableText!!
Null許容(Nullable) KotlinNullPointerExceptionが発生する
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 }
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 ※ }
Null許容(Nullable) Javaのコード上ではNull許容型・非Null許容型の 制限が強制されない。 MainActivity.kt NotNullClass.java - 省略 - public String
getText(){ return null; // 実行可能 } - 省略 - val notNullableClass = NotNullableClass() val notNullableText: String = notNullableClass.getText() }
Null許容(Nullable) IllegalArgumentExceptionが発生する Java側からKotlinのメソッドを呼ぶときの引数 (非Null許容)にNullを渡そうとする場合は、 @NonNullと同じく警告は表示されるが実行自体 は可能。
Kotlinのいいところ? Kotlinを使うだけで、 ぬるぽにサヨナラできる
Kotlinのいいところ? Kotlinを使うだけで、 ぬるぽにサヨナラできる
Kotlinのいいところ Kotlinを使うと、 ぬるぽを発生させない設計が しやすくなる
Kotlinのいいところ ΩΩΩ < ナ、 ナンダッテー!!
Kotlinに力を借りて、 ぬるぽに立ち向かう ここから本題
Sample SearchWakayamaToilet https://github.com/masanori840816/SearchWakayamaToilet
ぬるぽを無くすには? ぬるぽが嫌なら、 コードからNullを 無くしてしまえばいいじゃない
非Null許容型にする Nullにならないことを保証できる変数は、Nullを 許容しないことでコードをシンプルにできる。 class MainActivity : AppCompatActivity() { var notNullableText:
String = "" // Nullを代入しない override fun onCreate(savedInstanceState: Bundle?) { - 省略 - var length = NotNullableText.length // Nullチェックが不要 } } 引数にも適用可能だが、特にコールバックで呼ば れた時に本当にNullが渡されないか確認が必要。
lateinit Nullにならないことは確実だが、宣言時に値が入 れられない変数ではlateinitを使う。 class MainActivity : AppCompatActivity() { lateinit var
notNullableClass: NotNullableClass // 後で初期化 override fun onCreate(savedInstanceState: Bundle?) { - 省略 - // 宣言時に値が入れられない場合も非Null許容型にできる notNullableClass = NotNullableClass() } }
非Null許容型にする 例えばMVCにおけるControllerなど、 Nullにできない変数も非Null許容型にする。 プログラム全体が動作しなくなる変数がNullの場 合は、下手に延命するよりエラーなどでアプリを 終了させる方が良い、ということ。
Null許容型を使う コールバックメソッドの引数など、 全部非Null許容型にするのは難しい。 ↓ Null許容型を安全に使いたい
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チェック
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にできる場合
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
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
Nullチェック 一度値を入れた後は値を変更しない変数 メソッドに引数として渡される値 ※引数は全てImmutable 使いどころ
?演算子 Null ” 許容型の変数では、 ?.”を使うことで安全にア クセスできる。 class MainActivity : AppCompatActivity()
{ override fun onCreate(savedInstanceState: Bundle?) { - 省略 - val nullableText: String? = “Not null” // nullableTextならNullが // それ以外はnullableText.lengthの値が入る var length = nullableText?.length } }
?演算子 ”?.”を使ったチェーンメソッド class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState:
Bundle?) { - 省略 - val nullableText: String? = “Not null” // nullableText、lengthのどちらかがNullならNullが入る var lengthText = nullableText?.length?.toString() } }
疑問 この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 実行速度に違いはある?
疑問 調べてみた
計測 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を使って計測
計測 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おしまい") }
計測 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おしまい") }
結果 Code1 24ms Code2 24ms [検証環境] Android Studio ver. 2.1.2
[端末] Nexus 9 (Emulator) [OS] Android N
結果 • “if(x != null)”でチェックする場合も?演算子を使 う場合も、少なくとも今回の検証ではほぼ差が 見られなかった。 • 状況に合わせてよりシンプルに書ける方を選択 するのが良さそう。
Elvis演算子 class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?)
{ - 省略 - var nullableText: String? = null // nullableTextがNull ” の場合のみ ?:”の右の値を代入する nullableText = nullableText?: “Null ” でした // 今回はローカル変数なので、もう一度nullableTextに // Nullチェック不要を入れるまではNullチェック不要 } } ”?:”を使うことで、変数がNullの場合のみ値を代入 できる。
Elvis演算子 class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?)
{ - 省略 - var nullableText: String? = null // 変数がNullなら以降の処理をスキップ nullableText?: return - 省略 - } } ”?:”を使うと変数がNullの場合はreturnする、とい うことも可能。
まとめ • Kotlinはぬるぽを無くしてくれるわけではない。 • ぬるぽを無くすにはコールバックの引数などア プリの動きをより詳しく把握する必要がある。 • Kotlinの豊富な機能でハッピーな開発ライフを!
参考 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
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
Enjoy Kotlin Life :)