38
7

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.

kotlinで本物のヌルポを出す方法

Posted at

kotlinで本物のヌルポを出す方法

kotlinではnull安全ですからヌルポとは出会えません。でも、kotlinのnull安全機構においてクラッシュするケースがあります。 !! 演算子で明示的にクラッシュケースを書いた場合です。このクラッシュはヌルポでは無いのでしょうか?実はドキュメントには、 ヌルポが欲しければ !! 演算子で得られるよ と書かれています。確かめてみましょう。

fun f(): Int? {
    return null
}

fun example1() {
	val a = f()
    val x = a!! + 3 // ここで例外が飛ぶ
    println(x)
}

Exception in thread "main" kotlin.KotlinNullPointerException

一見ヌルポが生まれたように見えます。しかしよく見てください。kotlin.KotlinNullPointerException と書かれています。これはkotlin由来の偽物のヌルポです。やはり本物のヌルポといえば java.lang.NullPointerException でしょう。

もちろん、Java連携を使えば本物のヌルポを得ることができます。Javaといえばヌルポですから当然です。では、混じり気の無い純粋なKotlinによって、本物のヌルポを得ることはできるのでしょうか。実は最近その方法を知ったのでご紹介します。

class Alpha {
    init {
        f()
    }
    
    fun f() {
       	val x: Int = a.length // ここで例外が飛ぶ
    }
    
    val a: String = "nya"
}

fun example2() {
    Alpha()
}

Exception in thread "main" java.lang.NullPointerException

どうですか、これが純粋なKotlinから産まれた本物のヌルポです。ヌルポが飛ぶというのに、コンパイラエラーも出ないし、 !! 演算子を書くような明示的な記述もありません。非ヌル安全だ。最悪だ。

解説

kotlinのクラス定義において、プロパティの初期化と init の実行は、上から順に実行されるようです。さっきのコードは、下記のように定義順をひっくり返すとクラッシュしなくなります。

class Alpha {
    val a: String = "nya"
    
    init {
        f()
    }
    
    fun f() {
       	val x: Int = a.length
    }
}

また、コンストラクタはプロパティ初期化の後に実行されるので、この問題は起こりません。

class Alpha {
    constructor() {
        f()
    }
    
    fun f() {
       	val x: Int = a.length
    }
       
    val a: String = "nya"
}

というわけで、 init の取扱には気をつけましょう。

38
7
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
38
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?