使用以下代码的默认设置在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"); } }}
它在“可能的错误”下产生以下警告:
Method invocation ‘value.equals(“default”)’ at line 16 may produce ‘java.lang.NullPointerException’
但是,如果首选项不存在,则返回默认值.即使首选项的值明确设置为null,其中:
sharedPref.edit().putString("somekey", null).commit();
将返回默认值(可能在引擎盖下这实际上是删除了首选项,但这在这里并不重要).
上述代码实际生成NPE的唯一方法是在首选项不存在时传递null值作为默认值:
String value = sharedPref.getString("somekey", null);
但是,如果有人这样做,那么他之后很可能不会错过空检查.我确实认识到null在这里可能不是一个字面值,可能来自其他一些变量,但同样也是一个获得偏好的不太可能的用例.
我确实意识到“它只是一个警告”而我“可以忽略它”而且它是我的代码,我可以做“我想要的任何东西”和“lint不是保姆”以及其他所有内容,但它让我烦恼(原谅双关语),这个明显琐碎的非BUG在代码检查过程中显示为“可能的错误”.
现在的问题是:
>在我推测的无错误代码中是否存在一些我尚未见过的潜伏危险?
>代码检查是否不够智能?
>在代码检查期间实际触发此警告的是什么?
>可以采取哪些措施来消除警告?
试图回答4.我想出了以下内容:
>什么都没有,只是忽略输出.看起来很丑,看起来你根本没有考虑警告.
>禁用整个警告类.可能隐藏其他真正的错误.
>经典,将等于改为“默认”.equals(值).不适用于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"); } }}
显然随机崩溃(字面意思),但没有警告!哎哟.
所以,让我们在getString()上添加一个@Nullable注释.现在我们得到警告,好.但是,SharedPreferences getString()似乎没有注释.
好吧,让我们尝试相反的事情.在getString()上粘贴@NonNull.新警告:
Expression ‘value’ might evaluate to null but is returned by the method declared as @NotNull (at line 28)
很酷,所以代码检查知道getString()的结果可能为null,但为什么在尝试使用返回值时它不会给我们原始警告?
更新
这里还有一个隐含的问题,第一次我可能没有足够强调.
此特定代码检查的描述如下:
Variables, method parameters and return values marked as @Nullable or @NotNull are treated as nullable (or not-null, respectively) and used
during the analysis to check nullability contracts, e.g. report possible NullPointerException errors.
这似乎意味着那些注释是驱动警告的原因.
事实上,我自己的方法只有在使用@Nullable注释时才会生成警告.但是,SharedPreferences getString()会生成此警告,尽管它没有注释.为什么是这样?
解决方法:
Is there some lurking danger in my presumed BUG-free code that I haven’t seen yet?
可能不是.注意分析仪结果仍然是有意义的,并努力通过修复或有选择地抑制它们来消除任何问题.
Is the code inspection just not smart enough?
What actually triggers this warning during code inspection?
是的,它不够聪明.
分析器可以看到一个方法可以返回null并且返回值是未经检查的,但不能足够深入地说明你的代码中不会出现这种情况.
What can be done to remove the warning?
比较喜欢
"default".equals(value)
你已经发现的可能的风格.这样可以在所有情况下进行无NPE比较,并且还可以防止分析仪唠叨.
如果不可能,请在本地禁止警告,例如:
//noinspection ConstantConditions switch (value) { ...
总结 以上是内存溢出为你收集整理的android – 为什么对具有默认值报告的SharedPreferences.getString()进行代码检查“可能会产生NPE”?全部内容,希望文章能够帮你解决android – 为什么对具有默认值报告的SharedPreferences.getString()进行代码检查“可能会产生NPE”?所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)