Java 中的 void 和 Kotlin 的 Unit

1 Java 中的 void 和 Kotlin 中的 Unit

在 Java 中,如果定义的函数没有返回值,就需要用 void 来修饰,即 void 不可以省略。这也在 Java 中不能说函数调用皆是表达式的原因,因为有些方法不具有返回值和类型信息,就不能算作是表达式。

Java 在语言层设计一个 Void 类。java.lang.Void 类类似于 java.lang.Integer,Integer 是为了对基本类型 int 的实例进行装箱操作。Void 的设计则是为了对应 void。由于 void 表示没有返回值,所以,Void 并不能具有实例,它继承自 Object。

在 Kotlin 中,函数在所有的情况下都有返回值类型,所以 Kotlin 引入了 Unit 来代替 Java 中的 void 关键字。

Unit 和 int 一样,都是一种类型,然而,Unit 不代表任何信息。那么,Kotlin 为什么要引入 Unit 呢?很大一个原因是函数式编程。

在 Kotlin 中,对象或者函数都有类型,如果方法的返回类型是 Unit 时,可以省略。

对比:

  • Java 中的 void 表示什么都不返回,Kotlin 中的 Unit 是一个真实的数据类型;
  • Java 中的 void 是一个关键字,Kotlin 中的 Unit 是一个类;

2 Any 和 Any? : 根类型

和 Object 作为 Java 类层级结构的根差不多,Any 类型是 Kotlin 所有非空类型的超类型(非空类型的根)。

但是在 Java 中,Object 只是所有引用类型的超类型(引用类型的根),而基本数据类型并不是类层级结构的一部分。这意味着当我们需要 Object 的时候,不得不使用像 java.lang.Integer 这样的包装类型来表示基本数据类型的值。

而在 Kotlin 中,Any 是所有类型的超类型(所有类型的根),包括像 Int 这样的基本数据类型。

和 Java 一样,把基本数据类型的值赋给 Any 类型的变量时会自动装箱:

kotlin 复制代码
val answer: Any = 42 // Any 是引用类型,所以值 42 会被装箱

注意 Any 是非空类型,所以 Any 类型的变量不可以持有 null 值。在 Kotlin 中如果我们需要可以持有任何可能值的变量,包括 null 在内,必须使用 Any? 类型。

在底层,Any 类型对应 java.lang.Object。Kotlin 把 Java 方法参数和返回类型中用到的 Object 类型看作 Any。当 Kotlin 函数使用 Any 时,它会被编译成 Java 字节码中的 Object。

所有的 Kotlin 类中都包含:toString、equals 和 hashCode。这些方法都继承自 Any。Any 并不能使用其他 java.lang.Object 的方法(比如 wait 和 notify),但是可以通过手动把值转换成 java.lang.Object 来调用这些方法。

3 Nothing 类型:这个函数永不返回

对于某些 Kotlin 函数来说,"返回类型"的概念没有任何意义,因为它们不会成功地结束。 例如,许多测试库都有一个叫做 fail 的函数,它通过抛出带有特定消息的一场来让当前测试失败。一个包含无限循环的函数也永远不会成功地结束。

当调用这样的函数代码时,知道函数永远不会正常终止是很有帮助的。Kotlin 使用一种特殊的返回类型 Nothing 来表示:

kotlin 复制代码
fun main() {
    fail("Error occurred")
}

fun fail(message: String): Nothing {
    throw java.lang.IllegalStateException(message)
}

// Exception in thread "main" java.lang.IllegalStateException: Error occurred
// 	at com.ixuea.test.TestKt.fail(Test.kt:158)
// 	at com.ixuea.test.TestKt.main(Test.kt:152)
// 	at com.ixuea.test.TestKt.main(Test.kt)

Nothing 类型没有任何值,只有被当作函数返回值使用,或者被当作泛型函数返回值的类型参数使用才会有意义。在其他所有情况下,声明一个不能存储任何值的变量没有任何意义。

Nothing 是没有任何实例的类型,Nothing 类型的表达式不会产生任何值。需要注意的是,任何返回值为 Nothing 的表达式之后的语句都是无法执行的。这里有点像 return 或者 break 的作用。在 Kotlin 中 return、throw 等,返回值都是 Nothing。

注意,返回 Nothing 的函数可以放在 Elvis 运算符的右边来做先决条件检查:

kotlin 复制代码
val address = company.address ?: fail("No address")
println(address.city)

上面这个例子展示了在类型系统中拥有 Nothing 为什么极其有用。编译器知道这种返回类型的函数从不正常终止,然后在分析调用这个函数的代码时利用这个信息。在上面的例子中,编译器会把 address 的类型推断成非空,因为它为 null 时的分支处理会始终抛出异常。

相关推荐
Java技术小馆3 分钟前
SpringBoot中暗藏的设计模式
java·面试·架构
xiguolangzi4 分钟前
《springBoot3 中使用redis》
java
꧁坚持很酷꧂6 分钟前
配置Ubuntu18.04中的Qt Creator为中文(图文详解)
开发语言·qt·ubuntu
李菠菜11 分钟前
非SpringBoot环境下Jedis集群操作Redis实战指南
java·redis
不当菜虚困23 分钟前
JAVA设计模式——(四)门面模式
java·开发语言·设计模式
ruyingcai66666623 分钟前
用python进行OCR识别
开发语言·python·ocr
m0Java门徒31 分钟前
面向对象编程核心:封装、继承、多态与 static 关键字深度解析
java·运维·开发语言·intellij-idea·idea
liuweidong080233 分钟前
【Pandas】pandas DataFrame radd
开发语言·python·pandas
_一条咸鱼_1 小时前
深度剖析 Android ViewPager:从源码探究其使用原理
android·面试·kotlin
无心水1 小时前
【Java面试笔记:基础】8.对比Vector、ArrayList、LinkedList有何区别?
java·笔记·面试·vector·arraylist·linkedlist