You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java深度优先搜索(DFS)迷宫算法空指针异常排查求助

迷宫DFS算法空指针异常排查

运行以下Java迷宫DFS求解代码时,抛出空指针异常:

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "depthfirstsearch.NodeClass.getState()" because "currentNode" is null

但在循环内部打印currentNode时,发现它并非null,现需排查问题原因及解决建议。

完整代码

//Upgraded dfs algorithm that creates an array of nodeclass objects

package depthfirstsearch;

public class DepthFirstSearch {

    public static void main(String[] args) {
       
        int[][] stateArr = 
        {
        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
        {0, 2, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0},
        {0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0},
        {0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0},
        {0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0},
        {0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0},
        {0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0},
        {0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0},
        {0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0},
        {0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0},
        {0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0},
        {0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0},
        {0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0},
        {0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0},
        {0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0},
        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0},
        {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0},
        {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0},
        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0},
        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
        //Maze array declaration
        
        int mazeRows = stateArr.length;
        int mazeCols = stateArr[0].length;
        
        //Creates an array of NodeClass objects
        NodeClass[][] mazeArr = new NodeClass[mazeRows][mazeCols];
        
        //Assigning values to the nodes (state, isPath, coords)
        for(int i = 0; i < mazeRows; i++)
        {
            for(int j = 0; j < mazeCols; j++)
            {
                int state = stateArr[i][j];
                mazeArr[i][j] = new NodeClass(i, j, state);    //Assigning coordinates & state (wall, path) to the node              
            }   //End of col for-loop            
        }   //End of row for-loop
        
        //Currently have an array of nodes with coordinates, state and isPath = false
        
        NodeClass currentNode = mazeArr[1][1];  //This is the node we'll be working with. Assigned the value of the starting node at position (1;1)
 
        
        while(currentNode.getState() != 3)  //3 Indicates the end of the maze. While we haven't reached the end
        {
            //Getting the position of the current node
            int row = currentNode.getNodeRow();
            int col = currentNode.getNodeCol();
            System.out.println("Run");
            System.out.println(currentNode);
            
            //We'll be taking the currentNode and checking every unchecked adjacent node:

            //Check up
            if((mazeArr[row-1][col].getState() == 1 || mazeArr[row-1][col].getState() == 3) && (mazeArr[row-1][col].haveTried() == false))
            {
                //Storing the parent node:
                NodeClass temp = currentNode;   //Stores the current node as the node temp
                mazeArr[row-1][col].setParentNode(temp); //Stores the current node as the parent node the new checked node
                
                mazeArr[row][col].setTried(true);   //Sets the current node as tried
                mazeArr[row][col].setIsPath(true);  //Considers the current node as a potential path

                currentNode = mazeArr[row-1][col];  //The new current node is the node above the original node

                System.out.println("Up");   //We moved up
            }
            
            //Check right
            else if((mazeArr[row][col+1].getState() == 1 || mazeArr[row][col+1].getState() == 3) && (mazeArr[row][col+1].haveTried() == false))
            {
                //Storing the parent node:
                NodeClass temp = currentNode;   //Stores the current node as the node temp
                mazeArr[row-1][col].setParentNode(temp); //Stores the current node as the parent node the new checked node
                
                mazeArr[row][col].setTried(true);   //Sets the current node as tried
                mazeArr[row][col].setIsPath(true);  //Considers the current node as a potential path

                currentNode = mazeArr[row][col+1];  //The new current node is the node above the original node

                System.out.println("Right");   //We moved right
            }
            
            //Check down
            else if((mazeArr[row+1][col].getState() == 1 || mazeArr[row+1][col].getState() == 3) && (mazeArr[row+1][col].haveTried() == false))
            {
                //Storing the parent node:
                NodeClass temp = currentNode;   //Stores the current node as the node temp
                mazeArr[row+1][col].setParentNode(temp); //Stores the current node as the parent node the new checked node
                
                mazeArr[row][col].setTried(true);   //Sets the current node as tried
                mazeArr[row][col].setIsPath(true);  //Considers the current node as a potential path

                currentNode = mazeArr[row+1][col];  //The new current node is the node below the original node

                System.out.println("Down");   //We moved down
            }
            
            //Check left
            else if((mazeArr[row][col-1].getState() == 1 || mazeArr[row][col-1].getState() == 3) && (mazeArr[row][col-1].haveTried() == false))
            {
                //Storing the parent node:
                NodeClass temp = currentNode;   //Stores the current node as the node temp
                mazeArr[row][col-1].setParentNode(temp); //Stores the current node as the parent node the new checked node
                
                mazeArr[row][col].setTried(true);   //Sets the current node as tried
                mazeArr[row][col].setIsPath(true);  //Considers the current node as a potential path

                currentNode = mazeArr[row][col-1];  //The new current node is the node left of the original node

                System.out.println("Left");   //We moved left
            }
            
            //If there are no paths left: we reached a dead end and need to back track
            else
            {
                mazeArr[row][col].setTried(true);   //Sets the current node as tried
                mazeArr[row][col].setIsPath(false); //Since it's a dead end, we remove it from the potential solution

                currentNode = mazeArr[row][col].getParentNode();    //Sets the current node as the previous node    
            }
            
        }   //End of while-loop for finding the solution
        
        System.out.println("Yay yay, we did it!");
        
    }   //End of main method
    
}   //End of DepthFirstSearch Class

问题原因

  1. 回溯时currentNode变为null:起始节点mazeArr[1][1]的parentNode初始为null。当算法回溯到起始节点且没有可走路径时,执行currentNode = mazeArr[row][col].getParentNode()会将currentNode赋值为null。而空指针异常是在while循环条件判断时触发的(currentNode.getState()),你在循环内部打印currentNode的时机早于这个判断,所以看不到null的情况。
  2. 分支中parentNode赋值错误:在Check right分支里,错误地将mazeArr[row-1][col]的parentNode设置为当前节点,而不是应该移动到的mazeArr[row][col+1]。这个错误会导致部分节点的父节点未正确设置,加剧回溯时的null问题。
  3. 无边界校验:检查上下左右方向时,未判断坐标是否越界(比如row-1可能为-1,col+1可能超出数组长度),这会引发其他潜在异常。

排查与修复建议

  • 修复parentNode赋值错误:检查四个方向的分支,确保给对应方向的节点设置父节点。比如Check right分支中,将mazeArr[row-1][col].setParentNode(temp)改为mazeArr[row][col+1].setParentNode(temp)。
  • 循环条件增加非空判断:将while循环条件改为while(currentNode != null && currentNode.getState() != 3),避免currentNode为null时调用getState()。
  • 处理起始节点回溯边界:可以给起始节点设置一个特殊的父节点(比如自身),或者在回溯分支中判断如果当前节点是起始节点且无路径,直接终止循环。
  • 添加回溯调试日志:在else回溯分支中打印当前节点及其父节点,比如:
    System.out.println("回溯节点:" + currentNode + ",父节点:" + currentNode.getParentNode());
    
    这样能清晰追踪currentNode何时变为null。
  • 增加边界校验:每个方向判断前先检查坐标是否合法,比如Check up的条件先加row-1 >= 0:
    if(row-1 >= 0 && (mazeArr[row-1][col].getState() == 1 || mazeArr[row-1][col].getState() == 3) && !mazeArr[row-1][col].haveTried())
    

内容的提问来源于stack exchange,提问作者LonelyBoi404

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 15:55:54