防止 NullPointerException 警告的最佳方法?
Posted
技术标签:
【中文标题】防止 NullPointerException 警告的最佳方法?【英文标题】:Best way to prevent NullPointerException warning? 【发布时间】:2016-09-13 16:54:05 【问题描述】:我在 android-studio 中收到了这个警告,告诉我:
方法调用 'data.getExtras().get("address").toString()' 可能会产生 'java.lang.NullPointerException'
所以我更改了代码以消除该警告。
// Function to read the result from newly created activity
@Override
protected void onActivityResult(int requestCode,
int resultCode, Intent data)
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == 100 && data.getExtras().get("x") != null &&
data.getExtras().get("y") != null && data.getExtras().get("address") != null)
String sX = data.getExtras().get("x").toString();
String sY = data.getExtras().get("y").toString();
String sAddress = data.getExtras().get("address").toString();
double dX = Double.parseDouble(sX);
double dY = Double.parseDouble(sY);
ShowSearch(dX, dY, sAddress);
else
Log.d("onActivityResult()", "Something went wrong, either the result code is wrong or the data is null");
然后再三考虑,我选择了 try catch。
// Function to read the result from newly created activity
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == 100)
try
String sX = data.getExtras().get("x").toString();
String sY = data.getExtras().get("y").toString();
String sAddress = data.getExtras().get("address").toString();
double dX = Double.parseDouble(sX);
double dY = Double.parseDouble(sY);
ShowSearch(dX, dY, sAddress);
catch (java.lang.NullPointerException e)
Log.d("onActivityResult()", "Something went wrong, some data is null");
但是当我很确定它不应该出现警告时,使用 try catch 会在 android-studio 中返回警告,因为无论它是否为空,我现在都在处理它。
这是我的问题,这两种解决方案中哪一种在技术上更有效,如果是 try catch 解决方案,为什么 Android Studio 一直给我警告?
(Android Studio 2.1.1)
更新:在尝试了多种解决方案后,我意识到即使在第一个示例中,android studio 也会给我一个警告,所以我仍然有这个警告,但它不再困扰我了。
对于那些感兴趣的人,这是我决定使用的新解决方案:(我仍然收到警告)
// Function to read the result from newly created activity
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == 100 && data != null)
if (data.hasExtra("x") && data.hasExtra("y")
&& data.hasExtra("address"))
if (data.getExtras().get("x") != null && data.getExtras().get("y") != null
&& data.getExtras().get("address") != null)
String sX = data.getExtras().get("x").toString();
String sY = data.getExtras().get("y").toString();
String sAddress = data.getExtras().get("address").toString();
double dX = Double.parseDouble(sX);
double dY = Double.parseDouble(sY);
ShowSearch(dX, dY, sAddress);
else
Toast.makeText(this, "Error in location", Toast.LENGTH_SHORT).show();
Log.d("onActivityResult()", "Something went wrong, some extra data is null");
else
Toast.makeText(this, "Error in location", Toast.LENGTH_SHORT).show();
Log.d("onActivityResult()", "Something went wrong, some extra data doesn't exist");
else
Toast.makeText(this, "No Location found", Toast.LENGTH_SHORT).show();
Log.d("onActivityResult()", "Something went wrong, either the result code is wrong or the data is null");
【问题讨论】:
好的,我会相应地编辑。 “为什么 Android Studio 总是在 try catch 代码上给我一个警告” 我能看到的唯一答案是:Android Studio 没有对知道您正在处理它的代码;或者设计它的警告系统的人不在乎你是否处理它。 关于效率:重要的可能性非常、非常、非常、非常低。从维护的角度来看,做任何你认为最清晰、最干净的事情。在您的第一个示例中,任何体面的 JIT 都会很好地优化空检查(我不知道 Dalvik 的 JIT 有多好)。 不确定哪个更有效,但我不会捕获 NullPointerExceptions。当抛出 NullPointerException 时,它应该是程序员的错误。作为程序员,我们确保它们不会被抛出(通过空检查)。不确定这只是我个人的偏好还是被其他人广泛接受,但我个人认为捕获 NullPointerExceptions 是不好的做法,应尽可能避免。 还有一点未勾选:getExtras()
可以返回null
。使用Intent#hasExtra(String name)
可以解决这个问题,如果nullcheck 知道这一点,我想知道。
【参考方案1】:
您不应该捕获NullPointerException
- 实际上应该捕获极少数RuntimeException
s。
NullPointerException
表示您的代码存在问题,其中调用了变量的方法(或访问其字段),而引用实际上具有 null
值。
这基本上要求检查null
值。
这就是 Android Studio 在这种情况下似乎很主动的地方:当然,您可以通过链接对象上的方法调用来获得 NPE,并且如果您不能保证对象将不会 null
,您应该检查 null
值。
例如:
if (resultCode == 100
&& data.getExtras().get("x") != null
&& data.getExtras().get("y") != null
&& data.getExtras().get("address") != null) ...
... 会变得乏味:
if (resultCode == 100
&& data != null // unlikely
&& data.getExtras() != null
&& data.getExtras().get("x") != null
...
...或者更确切地说,在这种情况下:
if (resultCode == 100
&& data != null // unlikely
&& data.hasExtra("x")
...
这种改变是乏味的并且会增加混乱,但它在性能方面几乎没有关系,只要你的方法调用没有改变任何对象(否则,只需在检查 null
值之前分配给一个变量)。
似乎有一些方法可以根据您从 IDE 收到的警告参数化 Android Studio。
请参阅this 问题以了解大致方向。
注释/后期编辑
由于这是一个旧答案,所以关于 Java 8 的 Optional 的一句话。
Optional
s 旨在传达可能存在或不存在的数据的概念,例如引用对象的实例。
换句话说,Optional<T>
是T
实例的容器,我们不确定它的存在。
Optional
类提供了许多方法来处理这种不确定性,很多比必须繁琐地执行 null
检查,或者有些人可能会争论,而不是必须处理首先是指针的概念,正如可怕的Null
PointerException
s 所传达的那样。
Optional
s 在 Java 8 的流 API 中大量使用。
最后,从 Oracle 自己的角度来看,here 是 Optional
s 的一个很好的起点。
【讨论】:
感谢您提供的信息丰富的答案,我从未意识到以这种方式使用 try catch 的缺点。但是查看您的代码示例,检查“数据!= null”不是多余的吗?只检查“data.getExtras().get("x") != null &&...”不是很好吗,因为如果数据为 null,getExtras 将始终返回 null 对吗? @M.Haché 不客气。不,这不是多余的,正是因为如果您在null
Intent
上调用 getExtras
,您将得到一个 NullPointerException
。不过,我不完全确定Intent
是否真的可以 是null
,因此// unlikely
评论。
@M.Haché 你最好调用hasExtra(yourKey)
,而不是getExtras().get(yourKey) != null
。
我测试过,你是对的,它会给出一个“NullPointerException”。关于使用 'hasExtra(yourKey)' 而不是 'getExtras().get(yourKey) != null' 见comment【参考方案2】:
通常抛出异常是为了避免在不同条件下出现意外的编程错误或失败。另外,在某些情况下抛出异常可能会很昂贵,所以我肯定会使用空检查(如果可能的话)。
Check also this question 了解更多详情。
【讨论】:
【参考方案3】:我认为这将更适合您的要求。如果您只是记录它,则抛出异常是昂贵的。
VariableType extrasX = data.getExtras();
VariableType extrasY = data.getExtras();
VariableType addressS= data.getExtras();
if(extrasX !=null && extraYs != null && addressS != null)
VariableType xType = extrasX.get("X");
VariableType yType = extrasY.get("Y");
VariableType addressType = addressS.get("address");
if(xType !=null && yType != null && addressType != null)
String sX = xType.toString();
String sY = yType.toString();
String sAddress = addressType.toString();
double dX = Double.parseDouble(sX);
double dY = Double.parseDouble(sY);
ShowSearch(dX, dY, sAddress);
else
Log.d("onActivityResult()", "Something went wrong, some data is
else
Log.d("onActivityResult()", "Something went wrong, some data is
【讨论】:
【参考方案4】:涉及Optional
对象的公认答案需要 API 级别 24 或更高,因此我通常采用 Android Studio 建议,即在突出显示的对象周围插入 Objects.requireNonNull()
。
NullPointerException
失败的可能性(这会导致更好的代码)
它适用于低于Optional
的 Android API 级别
它比Optional
所要求的要简洁得多。
所以与其检查data.getExtras().get("x") != null
并在它为空时忽略潜在问题,不如使用
Objects.requireNonNull(data.getExtras().get("x"))
直接在您的代码中。
当然,在某些情况下你可以接受null
,在这种情况下data.getExtras().get("x") != null
检查没问题,导致代码忽略null
时的操作。
【讨论】:
以上是关于防止 NullPointerException 警告的最佳方法?的主要内容,如果未能解决你的问题,请参考以下文章
防止 Android Studio 检查将 Java 流链标记为包含可能的 NullPointerException