Java瞬态关键字和null

Java瞬态关键字和null,java,intellij-idea,transient,Java,Intellij Idea,Transient,我正在使用Intellij IDEA,下面的代码生成了一个警告:“表达式testObj的计算结果可能为null,但由声明为@NotNull的方法返回(在第16行)” 只有将testObj标记为transient时才会发生这种情况。删除关键字将清除警告。瞬态和可空性之间是否存在一些我不了解的交互作用,或者这只是一个想法上的错误?在编译器中,可空性是非常严格的。是的,您确实会检查null,但存在一个问题,您的代码可能会在多线程上下文中使用。考虑这种情况: 执行此块: if(testObj =

我正在使用Intellij IDEA,下面的代码生成了一个警告:“
表达式testObj的计算结果可能为null,但由声明为@NotNull的方法返回(在第16行)


只有将testObj标记为transient时才会发生这种情况。删除关键字将清除警告。瞬态和可空性之间是否存在一些我不了解的交互作用,或者这只是一个想法上的错误?

在编译器中,可空性是非常严格的。是的,您确实会检查null,但存在一个问题,您的代码可能会在多线程上下文中使用。考虑这种情况:

执行此块:

    if(testObj == null) {
        testObj = new Object();
    }
当前线程被抢占,另一个线程出现并将
testObj
设置为null。然后原始线程再次变为活动线程并完成执行,并返回
testObj
null

编写此代码以避免null警告的正确方法如下:

public Object getTestObj() {
    Object tmpObj = testObj
    if(tmpObj == null) {
        tmpObj = new Object();
        testObj = tmpObj;
    }

    return tmpObj;
}
在这种情况下,可以保证返回值从不为null

诚然,这是一个非常棘手的问题,大多数程序永远不需要这样的安全级别,但编译器应该这样检查null


添加瞬态时,null警告消失的事实似乎是IntelliJ错误。但是,上面建议的代码是处理字段可空性的正确方法。如果这对您来说过于繁重,我建议您避免在字段上添加null注释。

唯一一件事(我不知道)是显而易见的——如果一个可序列化实例被反序列化,它将为null,除非它在@jdpenix处理,但该方法已经检查了该条件。如果该对象被反序列化,testObj将为null,这一点是正确的,但同样适用于默认初始化为null的非瞬态字段。我已经将该字段标记为@Nullable。字段如何变为空不应该是一个问题。wierd的想法是,在检查testObj是否为空后,testObj可以立即为空。事实上,我怀疑存在bug。我认为产生错误的部分没有被您复制到这里。IntelliJ指的是一种方法,它没有null注释,但根据代码的定义,它可以返回null。第20行是哪一行?了解这一点可能会有所帮助。你没有复制的NotNull方法在哪里?@hamedmoghadam我复制了一个默认的版权头,它将所有内容向上移动,我的想法是假设所有方法都是非空的,除非另有说明。我的想法还设置为别名javax.annotation.Nonnull和NotNull,因此差异不是问题所在。我修正了问题,我想你误读了我的问题。警告仅在我使用transient关键字时出现。我知道线程会弄乱这个方法,在多线程上下文中这样做需要volatile关键字或某种类型的同步/内存障碍(由于内存缓存和java的内存模型,我不完全确定您的解决方案是否能工作)。奇怪的是,如果没有transient关键字,IDEA会非常快乐,但会开始对它感到不安。在我的最后一段中,我提到了带有transient关键字的行为可能是正确的,而没有transient关键字的行为是奇怪的。
public Object getTestObj() {
    Object tmpObj = testObj
    if(tmpObj == null) {
        tmpObj = new Object();
        testObj = tmpObj;
    }

    return tmpObj;
}