UnitはJavaのvoidとVoidを良いとこ取りしたような型である。 Javaのメソッドで返却値がない場合、voidを指定する。
void print() { System.out.println("msg"); return; }
メソッド末尾のreturnは省略可能なので、多くの場合は記載しないが、 処理の途中で返却する場合は明示的にreturnを記載する。 また、returnの代わりにthrowを使うこともある。
void fail() throws Exception { throw new Exception("hoge"); }
kotlinで同様の内容を書く場合、以下のように記載できる。
fun fail() : Unit { throw Exception("hoge"); }
ちなみにUnitの指定は省略することができる。
>>> fun hoge() : Unit {} >>> fun hoge() {}
と、ここまでの用途であればKotlinのUnitはvoidと変わらない。 違いが出てくるのはVoidである。 JavaのGenericsで返却値のないメソッドを扱う場合、以下の2つの方法がある。
クラスやメソッドが返却値の有無に関わらず共通の場合はVoidを使用する。 VoidはObjectの子クラスで、インスタンスを生成できない。 また、voidでもないため、返却値をreturnする必要があり、 インスタンスを生成できないVoidは必然的にnullを返すことになる。
Void fail(int i) { return; // NG. return nullと書くかthrowでないとビルドエラー }
Void fail(int i) { return null; // OK }
KotlinのUnitは上記のようなコードをvoidのように記載することができる。
interface Hoge<T> { fun run() : T } class Fuga : Hoge<Unit> { override fun run() { println("hoge"); } }
KotlinではUnitとは別に返却値を返さない場合に使える便利な型がある。 それがNothingである。 Javaでは以下のようなコードを書くことができない。
boolean is1(int i) { return i == 1; } void fail() throws Exception { throw new Exception("hoge"); } void exec() throws Exception { String s = is1(1) ? "hoge" : fail(); // fail()がStringを返さないのでNG }
このような処理を書く場合、Javaでは以下のように代入とfail()の呼び出しを分ける必要がある。
boolean is1(int i) { return i == 1; } void fail() throws Exception { throw new Exception("hoge"); } void exec() throws Exception { String s; if (is1(1)) { s = "hoge"; } else { fail(); // fail()がStringを返さないのでNG } }
しかしKotlinのNothingを使用すると以下のように記載することができる。
fun Int.is1() : Boolean = this == 1 fun fail() : Nothing = throw Exception("hoge") var s:String = if (1.is1()) "hoge" else fail()
UnitとNothingはJavaのvoid/Voidを使用していた用途で使用するが 使用方法に違いがある。 例えばUnitは前述したNothingのように以下のような記載はできない。 (以下はkotlinc-jvmの実行)
>>> fun Int.is1() : Boolean = this == 1 >>> fun fail1() { throw Exception("hoge") } >>> fun fail2() : Nothing = throw Exception("hoge") >>> >>> var s:String = if (1.is1()) "hoge" else fail1() error: type mismatch: inferred type is Unit but String was expected var s:String = if (1.is1()) "hoge" else fail1() ^ >>> >>> var s:String = if (1.is1()) "hoge" else fail2() >>> var s:String = if (2.is1()) "hoge" else fail2() java.lang.Exception: hoge at Line_14.fail2(Line_14.kts:1) >>>
逆にNothingはUnitのようにthrow以外で終わるコードを記載できない。
>>> fun fail1() {println("hoge")} >>> >>> fun fail2() : Nothing {println("hoge")} error: a 'return' expression required in a function with a block body ('{...}') fun fail2() : Nothing {println("hoge")} >>>
また、定義方法としてもそれぞれ以下のような違いがある。
>>> fun fail1() : Unit { throw Exception("hoge") } // OK >>> fun fail1() { throw Exception("hoge") } // OK >>> fun fail1() = throw Exception("hoge") // NG >>> fun fail2() : Nothing = throw Exception("hoge") // OK >>> fun fail2() : Nothing { throw Exception("hoge") } // OK