使用以下代码的默认设置在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");
}
}
}
它在“可能的错误”下产生以下警告:
第16行的方法调用'value.equals(“default”)'可能会产生'java.lang.NullPointerException'
但是,如果首选项不存在,则返回默认值。即使使用以下命令将首选项的值显式设置为null
sharedPref.edit().putString("somekey", null).commit();
将返回默认值(可能在引擎盖下这实际上是删除了首选项,但这在这里并不重要)。
上述代码实际生成NPE的唯一方法是在首选项不存在时传递null
值作为默认值:
String value = sharedPref.getString("somekey", null);
然而,如果某人这样做了,那么他之后很可能错过了空检查。我确实认识到null
在这里可能不是文字,可能来自其他一些变量,但同样也是一个不太可能的用例来获取偏好。
我确实意识到“这只是一个警告”,我“可以忽略它”而且这是我的代码,我可以做“我想要的任何东西”和“棉绒不是保姆”以及其他所有内容,但是它让我感到烦恼(请原谅双关语),在代码检查过程中,这个显然微不足道的非bug会显示为“可能的错误”。
现在问题:
试图回答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");
}
}
}
导致预期警告并按预期爆炸。很公平。
下一步...
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");
}
}
}
没有警告,没有崩溃。明显。
下一步...
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");
}
}
}
显然随机崩溃(字面意思),但没有警告!哎哟。
所以,让我们在@Nullable
上贴上getString()
注释。现在我们得到警告,好。但是,SharedPreferences
getString()
上似乎没有注释。
好吧,让我们尝试相反的方式。在@NonNull
上粘贴getString()
。新警告:
表达式'value'可能会计算为null,但由声明为@NotNull的方法返回(在第28行)
很酷,所以代码检查知道getString()
的结果可能是null
,但为什么在尝试使用返回值时它不会给我们原始警告?
更新
这里还有一个隐含的问题,第一次我可能没有强调过。
此特定代码检查的描述如下:
标记为@Nullable或@NotNull的变量,方法参数和返回值被视为可为空(或分别为非null)并使用 在分析期间检查可空性合同,例如报告可能的NullPointerException错误。
这似乎意味着那些注释是驱动警告的原因。
实际上,我的方法在使用@Nullable
注释时会生成警告 。但是,SharedPreferences
getString()
会生成此警告,但不已注释。这是为什么?
答案 0 :(得分:2)
在我推测的无错误代码中是否存在一些我尚未见过的潜伏危险?
可能不是。注意分析仪结果并通过修复或有选择地抑制它们来解决任何问题仍然是有意义的。
代码检查是否不够智能? 在代码检查期间实际触发此警告的是什么?
是的,它不够聪明。
分析器可以看到一个方法可以返回null并且返回值是未经检查的,但不能足够深入地说明你的代码中不会出现这种情况。
如何删除警告?
体型
"default".equals(value)
正如您已经发现的那样,样式。这样可以在所有情况下进行无NPE比较,并且还可以防止分析仪唠叨。
如果不可能,请取消警告本地,例如:
//noinspection ConstantConditions
switch (value) {
...