Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/338.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java:如何使lint尊重从内部函数调用引发的RuntimeException?_Java_Android Studio_Lint - Fatal编程技术网

Java:如何使lint尊重从内部函数调用引发的RuntimeException?

Java:如何使lint尊重从内部函数调用引发的RuntimeException?,java,android-studio,lint,Java,Android Studio,Lint,我正在使用AndroidStudio编写Android代码,它在编写代码时会自动执行lint检查 我有这样一个代码片段: Obj fun() { Obj o; if (SOME_CONDITION) { if (SOME_OTHER_CONDITION) { o = SOMETHING; } else { panic(); } } else { panic();

我正在使用AndroidStudio编写Android代码,它在编写代码时会自动执行lint检查

我有这样一个代码片段:

Obj fun() {
    Obj o;
    if (SOME_CONDITION) {
        if (SOME_OTHER_CONDITION) {
            o = SOMETHING;
        } else {
            panic();
        }
    } else {
        panic();
    }
    return o;
}
其中
panic()
是另一个类似的函数

void panic() {
    throw new IllegalStateException();
}
但是,lint检查器报告的错误是,o可能尚未初始化。 显然,当转到
else
分支时,会抛出
非法状态异常
(运行时异常的子类),因此执行已终止

注意
o=SOMETHING语句是一个简化的描述。实际代码更复杂,并且包含其他条件检查

添加
会引发RuntimeException
(或
IllegalStateException
)到
panic()


如何告诉linter它不会出错(不捕获异常并再次抛出它)?

Lint是正确的。考虑到“恐慌”可以在将来改变,或者被子类重写而不是抛出异常。o将被取消初始化。如果你真的想让lint闭嘴,就初始化它

更好的选择是将o的声明和return语句移动到o=something的分支。这是唯一一个真正使用它的地方,它在其他地方模糊了代码的真正意图。抛出异常,而不是函数末尾的返回。如果panic()真的抛出了一个异常,那么该行将永远不会被调用,但它应该让每个人都感到高兴

事实上,根据实际代码,您可以进一步简化:

Obj fun() {
    if (SOME_CONDITION && SOME_OTHER_CONDITION) {
            return SOMETHING;
    } 
    panic();
    throw new RuntimeException("We don't expect to get here");
}
必须明确指定局部变量 你想要的是不可能的。这不仅仅是AndroidStudio中的一条linter规则,它是编译器强制执行的语言规则。(重点加上):

对于每次访问局部变量或空白
final
字段
x
x
必须在访问之前明确分配,否则会发生编译时错误

你能做什么 重新定义panic()

然后这样使用它,以允许编译器验证控制流不会导致对未分配变量的访问:

...
} else {
    throw panic();
}
...

panic()
方法可以执行额外的工作,但不鼓励记录然后引发异常,因为它会导致冗余记录。

如果确实确定移动到
else
块将始终导致
非法状态异常
,然后首先检查该条件并抛出异常。沿着这条路线的东西。如果不能,那么另一种选择是使用
null
初始化
o
。您不应该这样做。如果方法调用的唯一目的是无条件地抛出异常,那么让它返回一个异常实例,并将其抛出到实际应该抛出它的函数中。有人可能会在以后将panic的非契约语义更改为有条件抛出,而您使用panic的方法将得到一个隐藏的bug。@MDSayemAhmed可能是我过度简化了我的案例。更新后的代码片段可能会更好地阐明这一点。关键的一点是,可能有多个地方需要调用
panic
,所以我认为把支票放在任何地方都不是一个好主意。GuardClauses对于简单的情况(例如,只有一个变量需要分配)可能是一个不错的选择,但对于复杂的情况可能不够好。@OlegSklyar
panic
方法是我自己编写的一个帮助函数,它只包装了我在调试时想做的一些常见事情(例如,记录日志,然后抛出异常)。它不是简单地“仅”抛出异常,而是无条件地抛出异常。重点在于如何使简单案例/快速原型设计更容易,同时保留一些调试的可能性。我认为“你不应该这样做”并不意味着“你不能这样做”,除非这是由语言强制执行的。这会起作用,但恐慌应该被重命名为CreateException之类的东西。在这种情况下,让它做额外的工作也会破坏SRP。在Android环境中,日志记录和抛出是有意义的,因为我无法收集异常消息(和堆栈跟踪)。我同意@GonenI的说法,即需要重命名该方法(这仍然有点复杂,因为调用
pacnic
后我仍然需要编写
throw
,尽管比以前好多了)。@renyuneyun你为什么不能收集消息和堆栈跟踪?好吧,我怎么能呢(如果电话不是我的,即未通过adb连接到我的计算机)?有些用户只是不知道如何使用adb。@renyuneyun不,我的意思是,在您的示例中,
return o
的路径并不一定指定变量
o
。如果编译此代码,它将允许在某些条件下返回未定义的值。当您通过引发异常中止这些路径时,compiler可以看到,在返回之前,剩余的路径肯定分配了
o
。这使编译器感到满意。同样,在修订后的问题语句中,这只是一个简化的代码,只是为了更直接地表示问题。实际的代码做了更多的条件检查和额外的工作(我认为它们太复杂了,所以我没有直接复制),所以像这样简化它们是不可接受的(返回很多,因为在不同的条件下有很多赋值)。一个简短的注释:添加
会在
panic()的定义中抛出RuntimeException
并没有阻止lint批评这一点。这是有道理的,因为所有java函数都隐式抛出RuntimeException。这基本上就是RuntimeException的定义:任何函数都可以在任何时候抛出它,而无需在throws子句中声明它。添加throws RuntimeException在java中没有效果。
...
} else {
    throw panic();
}
...