有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java跟踪NullPointerException的最佳方法是什么?

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

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 
}

共 (4) 个答案

  1. # 1 楼答案

    我的建议是保持线路短,不要打太多嵌套的内联电话。如果在下面这样的一行中出现错误,则很难找出哪个对象为空

    thisHive.get("a").bees.set(thisHive.get("a").beeIndex, larvae) .
    
  2. # 2 楼答案

    NullPointerException是代码中试图访问/修改尚未初始化的对象的情况

    因此,理想情况下,您不应该修复NPE,而是需要确保您没有对空对象进行操作/调用

    • 很少有情况下你会得到NPE
    • 在未初始化的对象上调用方法
    • 方法中传递的参数为null,使用
    • 已在空对象上同步
    • 哈希表的键为空
    • 单个语句中的链式方法调用

    我们如何安全处理

    1。更好的编码实践

    例1:改进编码风格

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

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

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

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

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

    3。不鼓励传递空参数

    但是有些地方你必须支持NPE

    Joshua bloch in effective java says that “Arguably, all erroneous method invocations boil down to an illegal argument or illegal state, but other exceptions are standardly used for certain kinds of illegal arguments and states. If a caller passes null in some parameter for which null values are prohibited, convention dictates that NullPointerException be thrown rather than IllegalArgumentException.”

  3. # 3 楼答案

    如果你有stacktrace,NullPointerException通常很容易通过一些实践发现:它来自于调用一个方法或引用一个空对象上的属性。因此,请查看报告的行,并查看引用了哪些对象。在你的例子中:

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

    thisHive可以为空吗?返回什么?它可以是空的吗?(可以,因为如果找不到键,映射将返回null)。bees可以为空吗?等等。你通常只需看代码就可以发现它,但调试器使它变得更容易。在该行上设置一个断点,看看什么是空的。然后反向工作以理解它为什么为空

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

    private int getMyInt() {
       Integer myInt = null;
       return myInt;
    }
    
    private void doSomething() {
       int i = getMyInt();
    }
    
  4. # 4 楼答案

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

    enter image description here

    enter image description here