0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

KotlinAdvent Calendar 2017

Day 13

KotlinのNullSafetyで悶々としていた話

Last updated at Posted at 2017-12-12

はじめに

  • 当記事は下記の環境にて動作を確認しています。
  1. Android Studio 3.0
  2. Kotlin 1.1.51
  3. compileSdkVersion 25,及び26
  • 当記事はKotlin Advent Calendar 2017の14日目の記事です。
  • Javaしか書いたことない人でもわかりやすいように書いた…つもりです。

Null Safetyとは

すでに「Null Safety?知ってるよ!」な方は飛ばしてください。

KotlinはJavaと違い基本的にnullは使用できません。
というのも、基本的にオブジェクトがnon nullableだからです。
例えば、下記のコードはエラーになります。

test.kt
val sampleStr: String  = "Kotlin"
println(sampleStr)
sampleStr = null

image.png

では、nullを使用したい場合はどうすればいいのでしょうか?
答えは下記のコードの通りです。

test.kt
var sampleStr: String?  = "Kotlin"
println(sampleStr)
sampleStr = null
println(sampleStr)

image.png

String?型はString型とはまったく異なるクラスです。
これは下記のコードによって確かめることができます。

test.kt
val sampleStr1: String   = "Kotlin"
var sampleStr2: String?  = null
println(sampleStr1 is Any)
println(sampleStr2 is Any)

image.png

Anyについては、
JavaプログラマがKotlinでつまづきがちなところ
が詳しいです。


ホントにNull Safetyなの?

Kotlinではnullableかどうかが型ではっきりとわかるということがわかりました。
では、コンパイルされるときにnullableかどうかがはっきりわかるので、
これでもうNullPointerExceptionとはお別れですね!うーんスッキリ!

…というわけにも行きませんでした。
下記コードをご覧ください。

extension.kt
fun <T : View> View.bindView(@IdRes id: Int): Lazy<T> = lazy {
    findViewById(id) as T
}
SampleView.kt
class SampleView : FrameLayout{
    constructor(context: Context?) : super(context)

    constructor(context: Context?,
                attrs: AttributeSet?) : super(context, attrs)

    constructor(context: Context?,
                attrs: AttributeSet?,
                defStyleAttr: Int) : super(context, attrs, defStyleAttr)

    constructor(context: Context?,
                attrs: AttributeSet?,
                defStyleAttr: Int,
                defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)

    private val profileImageView: ImageView by bindView(R.id.profile_image_view)
    private val titleTextView   : TextView  by bindView(R.id.title_text_view)
    private val userNameTextView: TextView  by bindView(R.id.user_name_text_view)

    // (以下略)

なんと、上記コードはコンパイルを通ってしまいます。
何が問題かというと…。

image.png

実はfindViewByIdはnullableです。
的確にIDを指定していれば問題ないのですが、間違った値を入れてしまうと…。

image.png

あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛!(絶叫)
ということになります。

ホントはNull Safetyじゃないの?

本記事では、ここからどのようにNullPointerExceptionを起こせるか実験しつつ記載しようと思ったのですが、
実は2017年11月10日現在、既にAndroid SDK側で対応されておりました。

AndroidOのfindViewByIdの仕様変更

アドベントカレンダー2017、明日はkamedon39さんです。


参考URL

JavaプログラマがKotlinでつまづきがちなところ

AndroidOのfindViewByIdの仕様変更

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?