【问题标题】:Best way to prevent NullPointerException warning?防止 NullPointerException 警告的最佳方法?
【发布时间】: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 知道这一点,我想知道。

标签: java android-studio nullpointerexception


【解决方案1】:

您不应该捕获NullPointerException - 实际上应该捕获极少数RuntimeExceptions。

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 的一句话。

  • Optionals 旨在传达可能存在或不存在的数据的概念,例如引用对象的实例。
  • 换句话说,Optional<T>T 实例的容器,我们不确定它的存在。
  • Optional 类提供了许多方法来处理这种不确定性,很多比必须繁琐地执行 null 检查,或者有些人可能会争论,而不是必须处理首先是指针的概念,正如可怕的NullPointerExceptions 所传达的那样。
  • Optionals 在 Java 8 的流 API 中大量使用。
  • 最后,从 Oracle 自己的角度来看,hereOptionals 的一个很好的起点。

【讨论】:

  • 感谢您提供的信息丰富的答案,我从未意识到以这种方式使用 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时的操作。

      【讨论】:

        猜你喜欢
        • 2011-04-01
        • 2020-06-29
        • 1970-01-01
        • 2017-10-15
        • 1970-01-01
        • 1970-01-01
        • 2023-03-29
        • 1970-01-01
        • 2021-02-18
        相关资源
        最近更新 更多