scala - Scala 中的哪个函数将 java.lang.Integer (null) 转换为 scala Int (zero)?
问题描述
最近发现了一个意外行为(感谢单元测试)。
斯卡拉:2.13.[4,6]
代码示例:
scala> def pri(value: Int): Int = value
def pri(value: Int): Int
scala>val jInt: java.lang.Integer = null
val jInt: Integer = null
scala> pri(jInt)
val res0: Int = 0
我希望NullPointerException
这里有一个,但显然 JavaInteger
null
被隐式转换Int
为零。
Scala的Predef.scala.Integer2int
似乎没有被称为:
implicit def Integer2int(x: java.lang.Integer): Int = x.intValue
解决方案
在 Scala 中,Int
类型对应于 java int
。
Scala 类型系统分为AnyVal
和AnyRef
层次结构,它们都是Any
.
此AnyVal
层次结构具有对应于 Java 原始类型的 等Int
。Long
这些AnyVal
s 可以boxed
转换为相应的AnyRef
类型(即Integer
for Int
)。
Int
从to Integer
(称为boxing
) 的类型转换是通过Int.box
调用发生的,这个实现来自运行时实现scala.runtime.BoxesRunTime.boxToInteger
,它被定义为,
public static java.lang.Integer boxToInteger(int i) {
return java.lang.Integer.valueOf(i);
}
因此,这首先适应i: Int
a int i
,然后转换为Integer
using java.lang.Integer.valueOf(i)
。
类似地,从Integer
to Int
(称为unboxing
)的类型转换是由 完成的Int.unbox
。这个实现来自运行时实现scala.runtime.BoxesRunTime.unboxToInt
,它被定义为,
public static int unboxToInt(Object i) {
return i == null ? 0 : ((java.lang.Integer)i).intValue();
}
请注意null
签入null ? 0 : ((java.lang.Integer)i).intValue()
。这unboxing
对“增加空值安全性”有一点“改进”,但可以throw
aClassCastException
作为输入可以是 any Object
。
Scala Predef 有以下两个在implicits
需要implicitly
时进行这种类型转换。
implicit def int2Integer(x: Int): java.lang.Integer = x.asInstanceOf[java.lang.Integer]
implicit def Integer2int(x: java.lang.Integer): Int = x.asInstanceOf[Int]
请注意,从Scala 2.12.0
这些方法开始进行类型转换,并且不要调用任何方法,例如x.intValue
(这是完成Scala 2.11.x
的,您将看到与NullPointerException
在 Java 中看到的相同,但随后它与显式Int.box
调用不一致,这可能是原因对于implicit definitions
) 的变化。
Scala-Java 互操作有很多“意想不到的”情况,因此当您将 Scala 与几乎所有 Java 库一起使用时,您需要非常小心(有趣的是,我们几乎所有的东西都使用 Java 库)。
这里有一些惊喜int
,Int
和Integer
。
public class JavaIntMagic {
public static int toPrimitiveInt(Integer integer) {
return integer;
}
public static Integer toInteger(int i) {
return i;
}
}
object ScalaIntMagic {
def toPrimitiveInt(integer: java.lang.Integer): Int = integer
def toInteger(i: Int): java.lang.Integer = i
}
当从 Scala 和 Java 代码调用时,这些实现具有不同的行为。
public class JavaMain {
public static void main(String[] args) {
Integer integer = null;
int i1 = ScalaIntMagic.toPrimitiveInt(integer);
// 0
int i2 = JavaIntMagic.toPrimitiveInt(integer);
// fails with NullPointerException
Integer integer1 = ScalaIntMagic.toInteger(integer);
// fails with NullPointerException
Integer integer2 = JavaIntMagic.toInteger(integer);
// fails with NullPointerException
}
}
object ScalaMain {
def main(args: Array[String]): Unit = {
val integer: java.lang.Integer = null
val i1: Int = ScalaIntMagic.toPrimitiveInt(integer)
// 0
val i2: Int = JavaIntMagic.toPrimitiveInt(integer)
// fails with NullPointerException
val integer1: java.lang.Integer = ScalaIntMagic.toInteger(integer)
// 0
// why ? because the "null safe" unboxing strikes again
val integer2: java.lang.Integer = JavaIntMagic.toInteger(integer)
// 0
// why ? because the "null safe" unboxing strikes again
}
}
在使用或其他 java 驱动程序时,当您的数据库表神奇地有一些数字而不是预期的(或写入失败)JDBC
时,请不要感到惊讶。添加越来越多的单元测试(即使是看起来很微不足道的东西)。0
null
奇怪的是,一方面,我们没有任何用于网络、数据库等基础内容的“纯”Scala 库,并且严重依赖包装在 Scala API 中的 Java 库,但另一方面,我们没有为了在 Scala 生态系统中可靠地使用这些库,不强调一致和可预测的 Java 互操作(即使是非常基本的东西,如 int、boolean、bytes)。
推荐阅读
- java - 使用 apache.commons.compress.archivers.zip 读取远程 zip 文件
- python - 如何解决python的全局变量问题
- python - 在 Python 中只允许输入消息中的某些字符
- python - python - 该进程无法访问该文件,因为它正在被另一个人使用
- c - C 运算符中的求值顺序
- php - 更新或创建行数据库。拉拉维尔
- sql - Excel:分别对多列进行排序
- python - TypeError:视图函数没有返回有效的响应元组。元组的形式必须为 (body, status, headers), (body, status),
- excel - Excel vlookup为所有记录返回相同的值
- vba - VBA - 处理带有 utf8 字符的文件夹名称