【问题标题】:What is the best way to track NullPointerExceptions?跟踪 NullPointerExceptions 的最佳方法是什么?
【发布时间】:2013-12-10 16:03:47
【问题描述】:

我现在遇到了一些这样的异常,我一直在努力解决它们,因此任何关于如何解决它们的指南或建议都会很棒,而不必依赖其他人来帮助解决它们。 目前我有一个关于如何解决它的建议,我们将不胜感激,但从长远来看,关于如何追踪问题原因的一般建议会更好。

class Egg extends Bee{
    protected void anotherDay() {

        eat();
        if(age>=3)
        {
            HashMap<String, Hive> thisHive = Garden.GARDEN.getHiveMap();
            Larvae larvae = new Larvae(this.health, this.age);
            thisHive.get("a").bees.set(thisHive.get("a").beeIndex, larvae);  //-------LINE 27
            //thisHive.get("a").replaceBee(larvae)   Line 27 was origionally this throwing the same exception

        }
        age++;
        System.out.println("Egg" + " age " + this.age + " health " + this.health);

    }
}

import java.util.ArrayList;

class Hive {
    protected int honey;
    protected int royalJelly;
    protected int pollen;
    public int beeIndex; // used to know what the index of bee you are in is
    public boolean holdAdd;
    ArrayList<Bee> bees = new ArrayList<Bee>();
    protected Hive(int honeyStart, int royalJellyStart, int pollenStart)
    {
        bees = new ArrayList<Bee>();
        this.setHoney(honeyStart);
        this.setRoyalJelly(royalJellyStart);
        this.setPollen(pollenStart);
        System.out.println("hive made");
        System.out.println(honey + " honey");
        System.out.println(royalJelly + " royalJelly");
        System.out.println(pollen + " pollen");
        holdAdd = false;
    }
    //code removed ...

    public void replaceBee(Bee addBee) {
        bees.set(beeIndex, addBee);
    }

    // code removed

    protected void anotherDay() {
        int i = 0;
        for(int k = 0; k < bees.size(); k++)
        {
            i++;
            Bee bee = bees.get(k);
            bee.anotherDay(); // ----------------LINE 144
            beeIndex = i;
        }
        // code removed 
    }
}


public class Garden {

    static HashMap<String, Hive> HiveMap = new HashMap<String, Hive>();
    public static final Garden GARDEN = new Garden();
    public static void main(String[] args) {
            GARDEN.anotherDay(); //------------------LINE 21
        }
    }

    //CODE REMOVED

    public HashMap<String, Hive> getHiveMap()
    {
        return Garden.HiveMap;
    }
    // CODE REMOVED


    protected void anotherDay() {
        //CODE REMOVED 

        //should find all Hives and call anotherday() on them each

        for(Hive currentHive : HiveMap.values()){
            currentHive.anotherDay(); //------------LINE 56
        }

        }
        //CODE REMOVED 
}

【问题讨论】:

  • 堆栈跟踪为您提供了空指针出现的行。如果只能从特定行中的一个位置抛出空指针,那么您就知道哪个变量为空并导致了异常。如果该行有多种可能性,调试器会有所帮助。然后只需回溯调用堆栈即可找到 null 出现的位置。
  • 好吧,如果您试图引用一个为空的对象,并且该对象可以为空,请在访问之前检查它是否为空。如果对象永远不应该为空,那么您的代码中存在逻辑错误条件,需要找出原因。
  • 您的代码似乎与您的问题无关。它们之间有什么联系?您是要我们为您调试吗?
  • 最初我打算就问题所在寻求帮助,但问题在我写它时发生了变化,因为我不想依赖其他人来帮助我调试我的代码它会帮助我长期依赖他人调试。

标签: java nullpointerexception runtimeexception


【解决方案1】:

NullPointerException 是代码中的一种情况,您尝试访问/修改尚未初始化的对象。

所以理想情况下,您不应该修复 NPE,而是需要确保您没有在 Null 对象上操作/调用。

  • 你会得到 NPE 的几种情况
  • 在未初始化的对象上调用方法
  • 方法中传递的参数为空使用
  • 在 null 对象上同步
  • Hashtable 的键为空
  • 在单个语句中调用链式方法

我们如何安全处理

1.更好的编码实践

eg 1:改进编码风格

String s=getValue();
// this is error prone
if(s.equals("SOMEVALUE"){
}
// Rather you can check for
if("SOMEVALLUE".equals(s)){

}

eg2:不要从对象返回Null作为返回类型,比如如果你想返回List,而不是返回null,你可以试试Collections.emptyList()

  public List getEmpList(){
    // some operation
     if(exp) {
       return List
     }
     else{
       return Collections.emptyList();  //dont return null
     }

   }

2.提供足够的测试覆盖率。

NPE 是 RunTimeException,您应该能够从测试类中捕获大部分 RTE。

3.不鼓励传递空参数

但有些地方你必须支持NPE

Joshua bloch 在有效的 java 中说:“可以说,所有错误 方法调用归结为非法参数或非法状态, 但其他例外通常用于某些类型的非法 论点和状态。如果调用者在某个参数中传递 null 禁止哪些空值,约定规定 抛出 NullPointerException 而不是 IllegalArgumentException。”

【讨论】:

    【解决方案2】:

    如果你有堆栈跟踪,NullPointerExceptions 通常很容易通过一些练习来发现:它来自调用一个方法或引用一个 null 对象的属性。因此,请查看报告的行并查看引用了哪些对象。在您的示例中:

    thisHive.get("a").bees.set(thisHive.get("a").beeIndex, larvae);
    

    thisHive 可以为空吗? get("a") 返回什么?可以为空吗? (是的,它可以,因为如果找不到键,则映射返回 null)。 bees 可以为空吗?等等。您通常可以仅查看代码就发现它,但调试器使其变得更加容易。在行上设置一个断点,看看什么是空的。然后向后工作以了解为什么它为空。

    需要注意的一点是自动装箱:如果您有一个声明为包装类的变量(LongIntegerBoolean 等)并且您将其作为原语引用,您将得到一个NPE:

    private int getMyInt() {
       Integer myInt = null;
       return myInt;
    }
    
    private void doSomething() {
       int i = getMyInt();
    }
    

    【讨论】:

      【解决方案3】:

      您可以在调试器中为 NPE 设置一个断点,这样当它们发生时它总是会停止,向您显示堆栈帧内容(涉及的字段和对象)。以下是使用 Idea 的方法:

      【讨论】:

        【解决方案4】:

        我的建议是保持行短,不要进行太多嵌套的内联调用。如果您在如下一行中出现错误,则很难确定哪个对象为空。

        thisHive.get("a").bees.set(thisHive.get("a").beeIndex, larvae) .
        

        【讨论】:

        • 原来那行是 thisHive.get("a").replaceBee(larvae);但它在进入 replaceBee() 函数之前抛出了 nullException,不知道发生了什么我试图以不同的方式来查看发生了什么。如果 KeySet 是 null 在这种情况下是 KeySet 是什么导致了 null 异常
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-03-27
        • 2010-09-24
        • 1970-01-01
        • 2010-09-16
        • 2016-06-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多