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

Java RPN计算器NullPointerException问题排查求助

排查RPN计算器的NullPointerException问题

嘿,我来帮你理清这个空指针异常的问题,咱们一步步拆解:

核心问题1:初始调用outof()时top为null

你的RPN类里,top作为成员变量,默认初始值是null(Java里引用类型成员变量如果不手动初始化,就会是null,所以你注释掉构造里的top = null也没用)。而get()方法第一行就执行了double val = outof( );——这时候栈里还没压入任何元素,top是null,outof()方法里第一行top = top.underneath直接就触发了空指针异常,因为你不能访问null对象的属性。

核心问题2:outof()方法的出栈逻辑完全颠倒

栈的出栈逻辑应该是先取当前栈顶的数据,再把栈顶指针移动到下一个节点,但你现在的实现是先移动指针,再取新指针的数据:

public double outof( ) {
    top = top.underneath; // 先移动指针
    double top_data = top.data; // 再取数据
    return top_data;
}

这不仅违背了栈"后进先出"的规则,还会在栈只剩一个元素时,移动指针后top变成null,此时访问top.data就会抛出NPE。比如你输入"21+"时,压入2和1后栈顶是1,第一次调用outof()会把top改成2,返回2;第二次调用outof()会把top改成2的underneath也就是null,这时候访问top.data直接炸了。

核心问题3:get()方法末尾的栈检查逻辑错误

正确的RPN计算完成后,栈里应该恰好剩下一个结果元素,但你现在的判断是if(top != null)就抛异常——这等于要求计算完栈必须是空的,完全搞反了,会导致正常计算完成后也抛出错误。

修复后的代码

下面是修复了这些问题的版本,我标注了关键修改点:

import java.util.Scanner;
class StackNode {
    public StackNode underneath;
    public double data;
    public StackNode(double data, StackNode underneath) {
        this.data = data;
        this.underneath = underneath;
    }
}
class RPN {
    private String command;
    private StackNode top;
    public void into(double new_data) {
        StackNode new_node = new StackNode(new_data, top);
        top = new_node;
    }
    // 修复:先取当前top的数据,再移动指针,同时增加空栈判断
    public double outof( ) {
        if (top == null) {
            throw new IllegalStateException("栈为空,无法出栈");
        }
        double top_data = top.data; // 先取当前栈顶数据
        top = top.underneath; // 再移动指针到下一个节点
        return top_data;
    }
    public RPN(String command) {
        this.command = command;
        // top默认是null,不需要手动赋值
    }
    public double get( ) {
        // 移除开头错误的outof()调用
        for(int i = 0; i < command.length( ); i++) {
            if(Character.isDigit(command.charAt(i))) {
                double number;
                String temp = "";
                int j; // 把j的声明移到这里,避免作用域问题
                // 修复:避免遍历超出字符串长度
                for(j = 0; (i + j < command.length()) && (Character.isDigit(command.charAt(i+j)) || (command.charAt(i+j) == '.')); j++) {
                    temp = temp + String.valueOf(command.charAt(i+j));
                }
                number = Double.parseDouble(temp);
                into(number);
                i += j - 1; // 调整i的位置,避免重复遍历
            } else if(command.charAt(i) == '+') {
                double b = outof( );
                double a = outof( );
                into(a + b);
            } else if(command.charAt(i) == '-') {
                double b = outof( );
                double a = outof( );
                into(a - b);
            } else if(command.charAt(i) == '*') {
                double b = outof( );
                double a = outof( );
                into(a * b);
            } else if(command.charAt(i) == '/') {
                double b = outof( );
                double a = outof( );
                into(a / b);
            }else if(command.charAt(i) == '^') {
                double b = outof( );
                double a = outof( );
                into(Math.pow(a, b));
            } else if(command.charAt(i) != ' ') {
                throw new IllegalArgumentException("非法字符");
            }
        }
        // 修复:检查栈里是否恰好有一个元素
        if(top == null || top.underneath != null) {
            throw new IllegalArgumentException("RPN表达式格式错误");
        }
        return top.data; // 返回栈里剩下的结果
    }
    public static void main(String args[]) {
        // 修复:把Scanner放在循环外面,避免重复创建和关闭System.in
        Scanner in = new Scanner(System.in);
        while(true) {
            System.out.println("Enter RPN expression or \"quit\".");
            String line = in.nextLine( );
            if(line.equals("quit")) {
                break;
            } else {
                try {
                    RPN calc = new RPN(line);
                    System.out.printf("Answer is %.2f\n", calc.get( ));
                } catch (Exception e) {
                    System.out.println("错误:" + e.getMessage());
                }
            }
        }
        in.close(); // 最后再关闭Scanner
    }
}

额外修复的小细节

  • 数字遍历的时候,原来的j循环可能会超出字符串长度,我改成了i + j < command.length()避免数组越界
  • 增加了异常捕获,让程序出错时不会直接崩溃,而是给出友好提示
  • 修复了main方法里重复创建Scanner并关闭的问题,否则第二次输入会报错

现在你输入"2 1 +"(标准RPN一般用空格分隔数字和运算符,如果你想支持无空格输入,可以再调整数字识别的逻辑),就能得到正确的结果3.0了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 03:02:52