Slide 1

Slide 1 text

JavaからKotlinへの移行 -KotlinからJavaを使う: プラットフォーム型編- 2017-06-29 Kotlin勉強会@Sansan 長澤太郎 @ngsw_taro

Slide 2

Slide 2 text

6月15日 第1回 CA.kt

Slide 3

Slide 3 text

JavaからKotlinへの移行 -JavaからKotlinが呼び出される編- ● Kotlinにはstaticという概念がない ○ @JvmStaticや@JvmFieldを上手く使う ● FWのためだけに毎回openするのが面倒 ○ Springならkotlin-springコンパイラプラグインを使う ○ all-openコンパイラプラグインを使う ● デフォルトコンストラクタを提供したくない ○ no-argコンパイラプラグインを使う

Slide 4

Slide 4 text

KotlinからJavaを使う: プラットフォーム型編

Slide 5

Slide 5 text

自己紹介 ● 長澤 太郎(たろーって呼んでね) ● @ngsw_taro ● エムスリー株式会社でエンジニアやってます ● Kotlinエバンジェリスト(JetBrains黙認) ● 日本Kotlinユーザグループ代表 ● 「Kotlinスタートブック」の著者

Slide 6

Slide 6 text

Null安全 ● nullの可能性のあるものと、そうでないものを厳格に区別する ことでケアレスミスを防ぐ val a: Int = null // コンパイルエラー val b: Int? = null // OK b.toString() // コンパイルエラー if (b != null) b.toString() // OK b?.toString() // OK

Slide 7

Slide 7 text

Java(の参照型)は常にnullの可能性がある // Java Optional nullは返さないよ() { return null; }

Slide 8

Slide 8 text

Javaコードの呼び出し結果はハテナだらけ? val foo: File = File("/") val bar: File? = foo.absoluteFile val baz: File? = foo.parentFile

Slide 9

Slide 9 text

Javaコードの呼び出し結果はハテナだらけ? val foo: File = File("/") val bar: File? = foo.absoluteFile val baz: File? = foo.parentFile コンストラクタの 戻り値はNotNull getXxx()メソッドは xxxプロパティのように

Slide 10

Slide 10 text

Javaコードの呼び出し結果はハテナだらけ? val foo: File = File("/") val bar: File? = foo.absoluteFile val baz: File? = foo.parentFile 常にnullを返さないメソッドもあ るのに面倒だな

Slide 11

Slide 11 text

ハテナだらけだったら まだ「めんどくさい」で 済んだ...!

Slide 12

Slide 12 text

プラットフォーム型 ● nullかもしれないし、nullじゃないかもしれない型 ● 受ける型を省略することで、プラットフォーム型を維持 ● 例えば「File!」として表記される val baz = foo.parentFile baz.exists() //=> ぬるぽ

Slide 13

Slide 13 text

プラットフォーム型 ● nullかもしれないし、nullじゃないかもしれない型 ● 受ける型を省略することで、プラットフォーム型を維持 ● 例えば「File!」として表記される val baz = foo.parentFile baz.exists() //=> ぬるぽ File!が返される 型を省略しているので File!のまま 危険な操作であるにも関わらず普通に メンバアクセス可能 (上手く行くこともあるが、今回はぬるぽ)

Slide 14

Slide 14 text

ifでnullチェックして回避 val baz = foo.parentFile if (baz != null) baz.exists() else false

Slide 15

Slide 15 text

ifでnullチェックして回避 val baz = foo.parentFile if (baz != null) baz.exists() else false Javaと 変わらん!! ※プラットフォーム型 + nullチェックはJavaと同じだが、 Nullable + nullチェックはJavaよりも安全。nullチェックを 否定したいわけではないことに注意。

Slide 16

Slide 16 text

安全呼び出しで回避 val baz = foo.parentFile baz?.exists() まぁ安全

Slide 17

Slide 17 text

だったらNullableとして明示すりゃあいい val baz: File? = foo.parentFile // あとはご自由に ● とにかく安全! ● プラットフォーム型の存在意義とは ● 結局ハテナだらけで面倒問題に戻る →注意深くコーディングして、うっかり死ぬよりマシ

Slide 18

Slide 18 text

NotNullとして明示すると...? val baz: File = foo.parentFile // 上手くいけば、あとはご自由に

Slide 19

Slide 19 text

NotNullとして明示すると...? val baz: File = foo.parentFile // 上手くいけば、あとはご自由に nullでない参照が返されればOK。 以後、NotNullとして扱える

Slide 20

Slide 20 text

NotNullとして明示すると...? val baz: File = foo.parentFile // 上手くいけば、あとはご自由に nullでない参照が返されればOK。 以後、NotNullとして扱える nullが返されるとクラッシュ! IllegalArgumentException

Slide 21

Slide 21 text

結論: プラットフォーム型は厄介 ● プラットフォーム型のまま扱うということはJavaの世界と同じ で、いつNPEが起きてもおかしくない状況 ● Javaコードがnullを返す可能性があるのかどうか自信が持 てない場合は、Nullableを明示するのが無難! ● Javaコードがnullを返さないことに自信がある場合には、 NotNullを明示する。なぜなら、それがnullだった場合に早 期に発見できるから。

Slide 22

Slide 22 text

Java側でNullable/NotNullを表明する ● JSR-305: @Nullable, @Nonnull ● JetBrains: @Nullable, @NotNull ● Android Support: @Nullable, @NonNull // Java class Hoge { @Nonnull static Hoge newInstance() {...} } // Kotlin val hoge = Hoge.newInstance() hoge.doSomething() NotNullとして見える