ci_*_*ci_ 6 android android-preferences android-studio
在Android Studio 1.2.2中使用以下代码的默认设置运行“分析/检查代码”时:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
String value = sharedPref.getString("somekey", "default");
if (value.equals("default")) {
Log.d("MainActivity", "value matches default");
}
}
}
Run Code Online (Sandbox Code Playgroud)
它在“可能的错误”下产生以下警告:
第16行的方法调用'value.equals(“ default”)'可能会产生'java.lang.NullPointerException'
但是,如果首选项不存在,则将返回默认值。即使使用以下方法将首选项的值显式设置为null:
sharedPref.edit().putString("somekey", null).commit();
Run Code Online (Sandbox Code Playgroud)
默认值将被返回(大概是在实际上删除了首选项,但这在这里并不重要)。
上面的代码实际上可以产生NPE的唯一方法是在null不存在首选项时通过将值作为默认值传递:
String value = sharedPref.getString("somekey", null);
Run Code Online (Sandbox Code Playgroud)
但是,如果有人这样做了,那以后他错过空检查的可能性就很小。我确实意识到这null可能不是字面值,可能来自其他变量,但同样,获得首选项的可能性很小。
我确实意识到“这只是一个警告”,我“可以忽略它”,这是我的代码,我可以执行“任何我想做的”和“皮棉不是保姆”之类的事情,但这一切都困扰着我(原谅双关语),在代码检查过程中,这个显然不重要的非错误显示为“可能的错误”。
现在的问题:
为了回答4.,我提出了以下建议:
"default".equals(value)。不适用于switch(value){...}if (value != null) {...}。多余的检查,投降的气味。为了尝试回答3.,我做了一些实验:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String value = null;
if (value.equals("default")) {
Log.d("MainActivity", "value matches default");
}
}
}
Run Code Online (Sandbox Code Playgroud)
导致预期的警告并按预期爆炸。很公平。
下一个...
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String value = "test";
if (value.equals("default")) {
Log.d("MainActivity", "value matches default");
}
}
}
Run Code Online (Sandbox Code Playgroud)
没有警告,没有崩溃。明显。
下一个...
public class MainActivity extends Activity {
private String getString() {
String value = null;
if (new Random().nextBoolean())
value = "test";
return value;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String value = getString();
if (value.equals("default")) {
Log.d("MainActivity", "value matches default");
}
}
}
Run Code Online (Sandbox Code Playgroud)
显然是随机崩溃(从字面上看),但没有警告!哎哟。
因此,让我们在上添加@Nullable注释getString()。现在我们得到了警告,很好。但是,似乎没有注释SharedPreferences getString()。
好吧,让我们尝试相反的做法。坚持@NonNull下去getString()。新警告:
表达式“值”的值可能为null,但由声明为@NotNull的方法返回(在第28行)
太酷了,因此代码检查知道getString()may by 的结果null,但是为什么在尝试使用返回值时却没有给出原始警告呢?
更新资料
这里还有一个隐性问题,我可能在第一时间没有足够强调。
此特定代码检查的描述为:
标记为@Nullable或@NotNull的变量,方法参数和返回值被视为可为空(或分别为非空),并在分析期间用于检查可为空性合同,例如报告可能的NullPointerException错误。
这似乎暗示着这些注释是引起警告的原因。
实际上,我自己的方法仅在使用注释时才会生成警告@Nullable。但是,SharedPreferences getString()尽管未注释,但会生成此警告。为什么是这样?
我假定的无错误代码中是否存在一些我尚未看到的潜在危险?
可能不会。关注分析器结果并努力通过修复或选择性抑制问题来消除任何问题仍然是有意义的。
代码检查还不够智能吗?在代码检查期间究竟是什么触发了此警告?
是的,它不够聪明。
分析器可以看到一个方法可以返回 null,并且返回值未经检查地使用,但无法深入推理,因此您的代码中不会出现这种情况。
可以采取什么措施来消除警告?
更喜欢
"default".equals(value)
Run Code Online (Sandbox Code Playgroud)
尽可能采用您已经发现的风格。这使您在所有情况下都可以进行无 NPE 的比较,并且还可以防止分析器烦扰。
如果不可能,请在本地抑制警告,例如:
//noinspection ConstantConditions
switch (value) {
...
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
343 次 |
| 最近记录: |