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
相关产品推荐
相关产品推荐

