今日はなんの日?
今日はバレンタインらしいですが、特に変わったことがないのでいつも通りの記事を書きたいと思います。
とあるコード
import java.util.Calendar;
class Chocolate {}
class Kanojo {
private Chocolate choco = new Chocolate();
Chocolate getChoco() {
return choco;
}
}
class Naotiki {
private Kanojo kanojo;
Kanojo getKanojo() {
return kanojo;
}
void eat(Chocolate choco){
System.out.println("おいし~");
}
public static void main(String[] args) {
//私のインスタンスを生成
Naotiki naotiki= new Naotiki();
Calendar calendar = Calendar.getInstance();
//バレンタインなら?
if (calendar.get(Calendar.MONTH) == Calendar.FEBRUARY && calendar.get(Calendar.DAY_OF_MONTH) == 14) {
//チョコがもらえる・・・?
Chocolate choco = naotiki.getKanojo().getChoco();
naotiki.eat(choco);
}
}
}
ふむふむ・・・
main()
が実行されると私のインスタンスが作られ、もし2/14なら私のKanojo
を取得しチョコをもらうんだな!
そして私がありがたく美味しく頂くということか・・・
完璧なコードだな。間違いない。
さて、実行してみるか。
Exception in thread "main" java.lang.NullPointerException:
Cannot invoke "Kanojo.getChoco()" because the return value of "Naotiki.getKanojo()" is null
at Naotiki.main(Valentine.java:32)
あれ・・・?
意訳
ぬるぽ
Naotiki.getKanojo()
の返り値がNullなのでKanojo.getChoco()
が実行できませんでした
あ・・・・(察し)
うわぁぁぁぁぁぁぁぁ!!!!!!(ぬるぽでクラッシュする音)
なんということでしょう。
彼女がNullの可能性を考慮しなかったが為に、2/14にぬるぽでクラッシュしてしまう悲しい私が生まれてしまったのです。
これでは一生2/14に怯えて暮らさなければなりません。
これでは良くないですね。
Kotlinを使ってNull Safetyにしてあげましょう。
import java.util.*
class Chocolate
class Kanojo {
var choco: Chocolate = Chocolate()
private set
}
class Naotiki {
var kanojo: Kanojo? = null
private set
fun eat(choco: Chocolate) {
println("おいし~")
}
}
fun main(args: Array<String>) {
//私のインスタンスを生成
val naotiki = Naotiki()
val calendar = Calendar.getInstance()
//バレンタインなら?
if (calendar[Calendar.MONTH] == Calendar.FEBRUARY && calendar[Calendar.DAY_OF_MONTH] == 14) {
//チョコがもらえる・・・?
val choco = naotiki.kanojo.choco
naotiki.eat(choco)
}
}
とりあえずKotlinに変換してみました。
初期値がないといけないので今回はNullを代入しておきます。
併せて、Kanojo
はNull許容のKanojo?
にします。
するとIntelliJくんがなにか言いたそうです。
Kanojo?
の Null 許容レシーバーでは、安全な (?.
) または非 Null アサート (!!.
) 呼び出しのみが許可されます。
なるほど、Nullかもしれないものはそのまま呼び出せないんですね。
!!.
を使うと先程と同じ結果になってしまうので安全な方の?.
を使いましょう。
fun main(args: Array<String>) {
//なおちきのインスタンスを生成
val naotiki = Naotiki()
val calendar = Calendar.getInstance()
//バレンタインなら?
if (calendar[Calendar.MONTH] == Calendar.FEBRUARY && calendar[Calendar.DAY_OF_MONTH] == 14) {
//チョコがもらえる・・・?
- val choco = naotiki.kanojo.choco
+ val choco = naotiki.kanojo?.choco
naotiki.eat(choco)
}
}
ん?
また何かIntelliJが言いたそうです。
kanojo
がNullかもしれないので?.
でアクセスしたchoco
もNullかもしれない型になるんですね!
Null許容チョコはeat()
出来ないので怒られていますね。
?.let { ... }
をうまく使って書いてみましょう。
fun main(args: Array<String>) {
//なおちきのインスタンスを生成
val naotiki = Naotiki()
val calendar = Calendar.getInstance()
//バレンタインなら?
if (calendar[Calendar.MONTH] == Calendar.FEBRUARY && calendar[Calendar.DAY_OF_MONTH] == 14) {
//チョコがもらえる・・・?
val choco = naotiki.kanojo?.choco
- naotiki.eat(choco)
+ naotiki.kanojo?.let { she ->
+ naotiki.eat(she.choco)
+ }
}
}
kanojo
がNullじゃないときにlet
が実行され、その中でNullではないことが保証されたkanojo
(let内ではshe
)から貰ったchoco
をeat()
するんですね。
もしkanojo
がNullなら何も実行されずにそのまま終了するようです。
直し終わったところで・・・
2回目の実行です!
java.exe (省略)
プロセスは終了コード 0 で終了しました
やりました!ぬるぽを回避し私に平穏な2/14が戻ってきました!
私の彼女がNullではない世界線の実行結果
java.exe (省略)
おいし~
プロセスは終了コード 0 で終了しました
おわり
久しぶりにQiita書きたくなったので書きました。
書いてて私は悲しくなりました。1
コメントで(:chocolate_bar:
)をくれると私が喜びます
KotlinのNull Safetyについて、詳しくはこちらを見てください
-
Q. なにも行動しないお前が悪いのでは? A. その通りです。(泣) ↩