从 Kotlin 调用 Java 时可为空的规则是什么

2023-12-24

为什么 Kotlin 在一种情况下推断从 Java 返回的类型可以为 null,而在另一种情况下它可以是可为 null 或不可为 null?

我都检查过HashMap.get and JsonNode.get我无法在类中或继承链中的任何位置识别任何类似 @NotNull 的注释。是什么让 Kotlin 以不同的方式对待这两个调用?

我已阅读文档https://kotlinlang.org/docs/java-interop.html#null-safety-and-platform-types https://kotlinlang.org/docs/java-interop.html#null-safety-and-platform-types但它解释使用“平台类型”,但没有解释它们是什么,并且无论如何也没有解释行为差异。

import com.fasterxml.jackson.databind.JsonNode

private fun docType(node: JsonNode, map: java.util.HashMap<String,String>) {
    val x: JsonNode = node.get("doc_type")  // DOES compile and can throw NPE at runtime
    val y: JsonNode? = node.get("doc_type") // DOES compile and Kotlin's type system will force you to check for null
    val z: String = map.get("a")            // ERROR: Type mismatch: inferred type is String? but String was expected
}

Kotlin 提供了与 Java 的无缝互操作性,几乎不影响其自身的空安全性。一个例外是 Kotlin 假设allJava 中定义的类型不是 null。

为了理解,让我们看看JsonNode.get()

平台类型

public JsonNode get(String fieldName) { return null; }

注意JsonNode是在 Java 中定义的,因此是平台类型 https://kotlinlang.org/docs/java-interop.html#null-safety-and-platform-types- Kotlin 不会将其“翻译”为JsonNode?,即使这在技术上是正确的(因为在 Java 中所有类型都是可为空的)。

从 Kotlin 调用 Java 时,为了方便 https://discuss.kotlinlang.org/t/why-doesnt-kotlin-default-to-nullable-for-java-types/16753假设平台类型不可为空。如果不是这样的话,你会always必须检查任何平台类型的任何实例不为空。

因此,要回答您关于“平台类型”是什么的问题,这个术语的意思是

  • 用外部目标语言定义的某种类型,
  • 你不能在 Kotlin 代码中明确提及它(但可能有一个同义的 Kotlin 等效项),
  • 为了方便起见,我们假设它是不可为空的。
  • 记号也是<type>!, 例如String!- 我们可以理解为String or String?

可空性注释

与 Kotlin 的 nullable 最接近的 Java 等价物?符号是可空性注释 https://kotlinlang.org/docs/java-interop.html#nullability-annotations,Kotlin 编译器可以解析并考虑它。然而,没有一个被用于JsonNode方法。所以 Kotlin 会很高兴地假设node.get("")将返回JsonNode, not JsonNode?.

正如您所指出的,没有定义HashMap.get(...).

那么 Kotlin 如何知道这一点map.get("a")返回可空类型?

类型推断

类型推断 https://kotlinlang.org/spec/type-inference.html#type-inference没办法。 (Java) 方法签名

public V get(Object key) {
  //...
}

表明一个HashMap<String, String>应该返回String, not String?。肯定还有其他事情发生...

映射类型

对于大多数 Java 类型,Kotlin 将仅使用所提供的定义。但对于某些,Kotlin 决定特殊对待它们,并用自己的版本完全替换 Java 定义。

你可以看到文档中映射类型的列表 https://kotlinlang.org/docs/java-interop.html#mapped-types。而同时HashMap不在那里,Map是。所以,当我们编写 Kotlin 代码时,HashMap不继承自java.util.Map- 因为它被映射到kotlin.collections.Map

Aside: in fact if you try and use java.util.Map you'll get a warning code that uses java.util.Map with an IntelliJ warning: This class shouldn't be used in Kotlin. Use kotlin.collections.Map or kotlin.collections.MutableMap instead.

所以如果我们看一下代码get功能是kotlin.collections.Map定义,我们可以看到它返回一个可为空的值类型 https://github.com/JetBrains/kotlin/blob/6fc27c22f44d8051bf2e89f1657c0d9741c281c0/core/builtins/native/kotlin/Collections.kt#L320

/**
* Returns the value corresponding to the given [key], or `null` if such a key is not present in the map.
*/
public operator fun get(key: K): V?

所以 Kotlin 编译器可以查看HashMap.get(...)并推断出这一点,因为它正在实施kotlin.collections.Map.get(...),返回值must是一个可为空的值,在我们的例子中是String?.

解决方法:外部注释

无论出于何种原因,杰克逊没有使用可以解决此问题的可为空注释。幸运的是,IntelliJ 提供了一种解决方法,虽然不那么严格,但会提供有用的警告:外部注释 https://www.jetbrains.com/help/idea/external-annotations.html.

一旦我按照说明操作...

  1. Alt+Enter → '注释方法...'

  2. 选择“可为空”注释

  3. Save annotations.xml

Now node.get("")将显示警告。

此注释对 Kotlin 编译器不可见,因此它只能是警告,而不是编译错误。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从 Kotlin 调用 Java 时可为空的规则是什么 的相关文章

  • Jetpack Compose:制作全屏(绝对定位)组件

    我怎样才能在全屏渲染树的深处制作一个可组合的 类似于Dialog可组合作品 例如 当用户单击图像时 它会显示该图像的全屏预览 而无需更改当前路线 我可以用 CSS 来做到这一点position absolute or position fi
  • JetPack Compose - 卡中行中的weight() 不起作用

    创建 Android 应用程序时 我将一些可组合项放在卡片的一行中 如下所示 但它没有按我的预期工作 我添加 weight 1f 的可组合项不再显示 data class Test val title String val text Str
  • Oracle:动态设置表中所有 NOT NULL 列以允许 NULL

    我有一个包含 75 多个列的表 几乎所有列都有 NOT NULL 约束 如果执行巨大的更改表修改语句 其中的每一列 我会收到一条错误消息 内容大致为 您不能将此字段设置为 NULL 因为它已经是 NULL 我必须对几个表执行此操作 因此更希
  • Android Room 数据库 - 未解析的引用 @Entity 和其他注释

    我在我的应用程序中使用 Android Room Persistence 库 v 1 0 0 alpha1 虽然它工作正常 但当我在 Android studio 中打开模型类 Kotlin 数据类 时 它显示用于 Room 数据库的所有注
  • 如何将依赖 ThreadLocal 的代码与 Kotlin 协程一起使用

    一些 JVM 框架使用ThreadLocal存储应用程序的调用上下文 例如SLF4j MDC https logback qos ch manual mdc html 事务管理器 安全管理器等 然而 Kotlin 协程是在不同的线程上调度的
  • kotlin 从数组中获取随机字符串

    刚接触 kotlin 有不少问题和解答 大部分是 Java 方面的 在遵循文档并针对大量 SO 进行验证之后问题和答案 https stackoverflow com questions 6726963 random string from
  • 在 Anko DSL 中创建自定义 View/ViewGroup 类

    我想创建一个自定义视图 它只是一些 Android 视图的包装 我考虑创建一个自定义 ViewGroup 来管理其子视图的布局 但我不需要这么复杂 我基本上想做的是 class MainActivity verticalLayout tex
  • 在浏览器中运行 Kotlin HTML Builder

    我是一名 Java 开发人员 对 Kotlin 非常陌生 不过我喜欢这门语言 而且我喜欢用它可以轻松地完成 Web 应用程序 问题是我无法弄清楚如何在浏览器中运行 Kotlin HTML 构建器文件 以便我可以在 kotlin 中创建基本的
  • 如何在 kotlin 中检查 lambda 空值

    在 Kotlin 中如何检查 lambda 是否为空 例如 我有这样的签名 onError Throwable gt Unit 我如何区分它的默认值是应用于主体还是应用于此函数的值 您无法测试 lambda 的主体是否为空 因此它不包含源代
  • 使用 Jetpack Compose 仅​​在给定边界内拖动可组合项

    所以我在另一个盒子 边界 内有一个黑盒子 矩形 并且该矩形设置为可拖动 但现在我可以在整个窗口周围拖动矩形 但我希望如果矩形 离开 边界 它应该消失在边界后面 我可以使用其他修改器吗 这里有一些背景 我的代码如下所示 MaterialThe
  • Jackson Kotlin - 反序列化 JsonNode

    Problem 我有字符串形式的 JSON 内容 我首先想用 Jackson 以编程方式遍历它 然后 当我有感兴趣的节点时 我想反序列化它 我尝试过的 我已使用 mapper readValue 成功反序列化字符串 但现在我想在 jsonN
  • kotlin 命令行编译器

    如何使用js命令行编译器 fun main args Array
  • 使用 navhost 停止底部导航中的片段刷新

    这个问题已经被问过几次了 但现在已经是 2020 年了 有没有人找到一个好的可用的解决方案呢 我希望能够使用底部导航控件进行导航 而无需在每次选择片段时刷新片段 这是我目前拥有的 导航 main xml
  • 如何在 Kotlin 中将字节大小转换为人类可读的格式?

    在 StackOverflow 中找不到类似的主题 问题类似于如何在java中将字节大小转换为人类可读的格式 https stackoverflow com questions 3758606 如何在Java中将字节大小转换为人类可读的格式
  • 找不到具有不同构建变量的包名称“....”的匹配客户端

    我想实现推送通知 我添加到项目级别 dependencies classpath com android tools build gradle 2 2 2 classpath com google gms google services 3
  • 蓝牙权限在 jetpack compose 中无法正常工作

    我在用com google accompanist accompanist permissions 0 25 1在我的项目中 我正在尝试在运行时请求蓝牙权限 我想知道用户如何知道权限被永久禁用 清单 xml
  • Android 导航 DeepLinks - 如何区分使用导航操作进行导航与深层链接

    我有导航操作和深层链接 根据您导航的位置 将您带到某个片段 我想确定是使用了深层链接还是仅使用了导航操作 这正是KEY DEEP LINK INTENT https developer android com reference andro
  • 如何在 Kotlin 中使用参数进行延迟初始化

    在 Kotlin 中 我可以在没有参数的情况下执行延迟初始化 如下声明 val presenter by lazy initializePresenter abstract fun initializePresenter T 但是 如果我的
  • 如何在调用主构造函数之前运行代码?

    我正在编写一个包含两个不可变值的类 它们在主构造函数中设置 我想添加一个辅助构造函数 它接受一个字符串并解析它以获取这两个值 但是 我无法找到在 Kotlin 中实现此功能的方法 因为辅助构造函数在解析字符串之前立即调用主构造函数 在jav
  • 如何在 LazyColumn 底部添加空白区域?

    我想添加 LazyColumn 的空白底部 并且我想允许用户调出底部元素 我怎样才能实现这个 Example LazyColumn modifier Modifier fillMaxWidth height 300 dp border 2

随机推荐

  • 如何获取 symfony/symfony 3 中的捆绑包列表?

    我刚刚开始使用 symfony 我想从特定供应商获取捆绑包列表 迭代它们并在每个默认控制器上调用 bundle gt renderSomething 函数 首先 我需要获取要迭代的包列表 或迭代每个对象 关于最好的方法有什么想法吗 在控制台
  • Meteor 会自动更新 mongodb 版本吗?

    我安装了 Meteor 1 2 2 根据 MeteorBlog 它应该安装 Mongodb v3 0 或更高版本 但是 如果使用 Mongo shell meteor mongo 并执行以下操作 db version 我得到 2 6 7 不
  • 如何在 React JS 中检查损坏的图像

    我正在编写一个模块 它从 json 获取文章数据并在文章文本上显示一个大图像 正如他们所说的英雄模块 我已经获得数据并进行了设置 因此如果有图像 它将显示该图像 如果数据中没有图像 它将显示默认图像 问题是此方法不会替换损坏的链接以显示默认
  • 在 LINQ select(x => new 中声明变量

    我正在将 POCO 映射到模型中 代码如下所示 NOT NEEDED var noneRequiredUserDocuments new List
  • 使用 SDK 8 中的 Android MediaPlayer 进行流式传输

    SDK 级别 8 Froyo 引入了 MediaPlayer 连接到流媒体源 如 Shoutcast 的本机功能 以前的 SDK 版本能够采取解决方法 例如在设备上运行本地代理 请参阅NPR http code google com p n
  • 防止 XslCompiledTransform 使用自关闭标签

    我在用XslCompiledTransform将 XML 文件转换为 HTML 有没有办法阻止它使用自关闭标签 e g span span span span
  • 从编辑重定向到父资源不会(重新)渲染模板

    我的用户界面的布局是一个列表 出口 子导航 详细信息 出口 出口 如中所述我之前的问题之一 https stackoverflow com questions 16342616 ember js how to refresh parent
  • python请求post数据为字符串类型时默认编码是什么?

    用下面的代码 payload 工作报告 总体情况 良好 r requests post http httpbin org post data payload Requests post数据为string类型时默认编码是什么 UTF8 还是
  • 从静态站点中托管的 javascript 运行 git Push

    想象一下用 jekyll 编译并托管在 github 页面上的静态网站 是否可以在这个页面上有一些 javascript 要求用户输入一些内容 然后将这个输入 git Push 到某个 github 存储库中 换句话说 如何用 javasc
  • Silverlight 4 - 将文本发送到记事本

    我尝试这个教程 http elegantcode com 2010 02 20 silverlight 4 com interop and the cool stuff you can do with it http elegantcode
  • NSArray 和 NSString

    我目前正在阅读的书让我编写以下代码 IBAction displaySomeText id sender NSString cow Milk NSString chicken Egg NSString goat Butter NSArray
  • 使用 java -jar 运行 scala 应用程序

    我在使用 java 时遇到了一些问题 一探究竟 sebastian sebastian desktop scaaaaaaaaala java cp home sebastian m2 repository org scala lang sc
  • OrientDB SELECT 和子查询

    我对此真的很困惑 为什么这有效 SELECT out Posted out IsFromCategory FROM 18 1 而这并不 SELECT out IsFromCategory FROM SELECT out Posted FRO
  • 是否需要处理实体框架上下文对象

    我们在 WCF 服务方法中使用实体框架与数据库进行通信 最近我们在服务代码上运行代码审查工具 像往常一样 我们通过工具收到了许多审查建议 并且许多审查意见建议处置实体框架上下文对象 所以 我的问题是 如果我在方法中使用实体框架上下文对象 并
  • 在 Swift 命令行应用程序中捕获信号

    How to capture different signals such as SIGINT and SIGTERM in Swift correctly For example when people stop my script by
  • 将外部资源添加到 Tomcat 8 中的类路径

    我有一个 Tomcat 应用程序 需要引用应用程序外部的一些属性文件 一般来说 它们存储在本地计算机上的特定位置 例如C PROJECT NAME conf 在 Tomcat 7 中 这可以通过放置一个来实现context xml文件内 M
  • 点击 jQuery 可排序列表不会模糊输入

    我可以通过单击页面上除 jQuery 可排序列表之外的任何位置来模糊输入 我怎样才能解决这个问题 更新 demo http jsfiddle net 43Wbh sortable mousedown function document ac
  • git-receive-pack:找不到命令

    我正在尝试使用 Gitpush到我的远程服务器 但它一直说 git receive pack 找不到命令 我尝试搜索 有人说是服务器 有人说是客户端 操作系统 Windows 8 64位服务器 Cent OSCPanel最新版本 Git 内
  • 如何查找活动 app.config 文件的路径?

    我正在尝试完成这个异常处理程序 if ConfigurationManager ConnectionStrings ConnectionString null string pathOfActiveConfigFile throw new
  • 从 Kotlin 调用 Java 时可为空的规则是什么

    为什么 Kotlin 在一种情况下推断从 Java 返回的类型可以为 null 而在另一种情况下它可以是可为 null 或不可为 null 我都检查过HashMap get and JsonNode get我无法在类中或继承链中的任何位置识