【问题标题】:How do I use Java collections of non-nullable elements from Kotlin?如何使用来自 Kotlin 的不可为空元素的 Java 集合?
【发布时间】:2025-11-30 07:55:01
【问题描述】:

使用 Kotlin 的互操作自动化来实现可空性,这样的方法可以在 Kotlin 中获得正确的签名:

@NonNull
public String foo(@NonNull String bar) {
    return "bar";
}

现在将原则提升到集合(或其他泛型,我猜):

@NonNull
public Set<String> foo(@NonNull Collection<String> bar) {
    return new HashSet<String>();
}

这在 Kotlin 中显示为

foo(bar: (Mutable)Collection<String!>) : (Mutable)Set<String!>

(Mutable) 没问题,但是如何摆脱类型参数中的平台类型?也就是说,如何编写或注释 Java 函数,以便我看到来自 Kotlin 的Set&lt;String&gt;(或Set&lt;String?&gt;)?

不允许使用Set&lt;@NonNull String&gt;(“'@NonNull' 不适用于类型使用”)。

如果有什么不同,我会使用 Findbugs 注释(通过 Spotbugs)。我的观点是希望尽可能无缝地使用 Kotlin 的 (Java) 库提供者。

【问题讨论】:

    标签: java collections kotlin interop non-nullable


    【解决方案1】:

    原来这是我使用的注释的实现问题,而不是概念问题。

    从 Spotbugs Annotations 3.1.2 开始,注释 @NotNull@NonNull 未针对目标 ElementType.TYPE_USE 声明。

    Jetbrains annotations 用那个标志声明的,它们可以用在类型参数上:

    @NotNull
    public Set<@NotNull String> foo(@NotNull Collection<@NotNull String> bar) {
        return new HashSet<>();
    }
    

    虽然这在 Java 中看起来有点笨拙,但我们得到了所需的 Kotlin 签名:

    foo(bar: (Mutable)Collection<String>) : (Mutable)Set<String>
    

    请注意,注释类型参数需要源语言级别 Java 8+。


    关于 Android 和其他卡在低语言级别的情况的说明。由于注释具有保留级别CLASS,因此如果应用程序使用如此注释的库,我预计不会出现任何运行时问题。不过,我还没有测试过; cmets 表示赞赏。

    【讨论】:

    • CLASS 意味着它成为类的一部分,运行时必须加载和解释它,然后才丢弃它,因此它不能通过反射获得。具有这些注释的类(我想)必须具有 52 或更高的格式版本号,Android 可能会拒绝。
    • @MarkoTopolnik 我猜它可以忽略所有 CLASS 注释,但它可能不会。您关于格式版本的观点是有效的;我没有足够的 Android 运输经验来估计这里的问题。取决于你想支持的Android版本,我猜? 4.4 仍然存在很多,但很古老。 :/无论如何,我无法(通过谷歌搜索)找出(现代)Android是否支持类型注释。没有手边的 Android Studio 可以尝试,因此最好将其视为仅限 JVM 的答案。
    • Android 一直停留在与 JDK 7 的兼容性上,因此它很可能会向 JDK 8 类格式的库抱怨。不过,可能有解决方法,例如为开发时依赖项和 APK 单独构建。
    • @MarkoTopolnik 我一直对谷歌在那里的战略感到困惑(和恼怒)。我可能会就这些解决方法与您联系!现在,FWIW,我就这个问题提出了addition to the Kotlin docs。感谢您的反馈!
    最近更新 更多