当前位置:   article > 正文

Java 中的 void 和 Kotlin 的 Unit

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 类型的变量时会自动装箱:

val answer: Any = 42 // Any 是引用类型,所以值 42 会被装箱
  • 1

注意 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 来表示:

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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

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

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

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

val address = company.address ?: fail("No address")
println(address.city)
  • 1
  • 2

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/275082
推荐阅读
相关标签
  

闽ICP备14008679号