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

Lisp表达式求值器异常抛出与捕获问题求助

Lisp表达式求值器异常抛出问题

问题描述

实现LispExpressionEvaluator时,无法正确抛出并打印LispExpressionEvaluatorException和LispExpressionException。已尝试在evaluate方法中添加catch块但未生效,目前除最后3个测试用例外其余测试均正常运行,求解决方案。

相关代码

LispExpressionEvaluator类

package PJ2;
import java.util.*;
public class LispExpressionEvaluator extends LispExpressionEvaluatorException
{
    // 当前输入的Lisp表达式
    private String currentExpression;

    // 主表达式栈,参考evaluate()中的算法
    private Stack<Object> inputExprStack;
    private Stack<Double> evaluationStack;
    public LispExpressionEvaluator() {
         currentExpression = "";
         inputExprStack = new Stack<Object>();
         evaluationStack = new Stack<Double>();
    }
    public LispExpressionEvaluator(String inputExpression) {
        if(inputExpression == null) {
            throw new LispExpressionEvaluatorException();
        }
        currentExpression = inputExpression;
        inputExprStack = new Stack<Object>();
        evaluationStack = new Stack<Double>();
    }
    public void reset(String inputExpression){
        if(inputExpression == null) {
            throw new LispExpressionEvaluatorException();}
        currentExpression = inputExpression;
        inputExprStack.clear();
        evaluationStack.clear();
    }
    // 计算当前运算符和对应操作数的结果
    private void solveCurrentParenthesisOperation() {
        boolean isNumber = true;
        double endResult = 0;
        if(inputExprStack == null) {
            throw new LispExpressionEvaluatorException();}
        String click = "";
        while (isNumber) {
            if (!inputExprStack.empty()) {
                click = String.valueOf(inputExprStack.pop());
            } else {
                isNumber = false;
                break;
            }
            try {
                Double number = Double.parseDouble(click);
                evaluationStack.push(number);
            } catch (NumberFormatException e) {
                isNumber = false;
            }
        }
        if (evaluationStack.size() == 0)
            return;
        switch (click) {
            case "+":
                endResult = evaluationStack.pop();
                while (!evaluationStack.empty()){
                    endResult +=evaluationStack.pop();
                }
            break;
            case "-":
                endResult = evaluationStack.pop();
                if(evaluationStack.size() == 0){
                    endResult = -endResult;
                }
                while (!evaluationStack.empty()){
                    endResult -=evaluationStack.pop();
                }
                break;
            case "*":
                endResult = evaluationStack.pop();
                while (!evaluationStack.empty()){
                    endResult *=evaluationStack.pop();
                }
                break;
            case "/":
                endResult = evaluationStack.pop();
                if(evaluationStack.size() == 0 && endResult != 0){
                    endResult = 1.0/endResult;
                }
                while (!evaluationStack.empty()){
                    endResult /=evaluationStack.pop();
                }
                break;
            default:
                endResult = evaluationStack.pop();
                break;
        }
        inputExprStack.push(endResult);
        System.out.println(endResult + " line 165");
    }
    /**
     * 计算currentExpression中的Lisp表达式,返回结果
     */
    public double evaluate() {
            Scanner currentExpressionScanner = new Scanner(currentExpression);
            currentExpressionScanner = currentExpressionScanner.useDelimiter("\\s*");
            if (inputExprStack == null) {
                throw new LispExpressionEvaluatorException();
            }
            while (currentExpressionScanner.hasNext()) {
                if (currentExpressionScanner.hasNextInt()) {
                    String dataString = currentExpressionScanner.findInLine("\\d+");
                    inputExprStack.push(Double.parseDouble(dataString));
                } else {
                    String aToken = currentExpressionScanner.next();
                    char item = aToken.charAt(0);
                    switch (item) {
                        case '(':
                            break;
                        case '+':
                            inputExprStack.push('+');
                            break;
                        case '-':
                            inputExprStack.push('-');
                            break;
                        case '*':
                            inputExprStack.push('*');
                            break;
                        case '/':
                            inputExprStack.push('/');
                            break;
                        case ')':
                            solveCurrentParenthesisOperation();
                            break;
                        default:
                            throw new LispExpressionEvaluator(item + " is not a legal expression operator");
                    }
                }
            }
            return Double.parseDouble(String.valueOf(inputExprStack.pop()));
        }

    //=====================================================================
    // DO NOT MODIFY ANY STATEMENTS BELOW
    //=====================================================================
    private static void evaluateExprTest(String s, LispExpressionEvaluator expr, String expect)
    {
        Double result;
        System.out.println("Expression " + s);
        System.out.printf("Expected result : %s\n", expect);
        expr.reset(s);
        try {
           result = expr.evaluate();
           System.out.printf("Evaluated result : %.2f\n", result);
        }
        catch (LispExpressionEvaluatorException e) {
            System.out.println("Evaluated result :"+e);
        }
        System.out.println("-----------------------------");
    }
    public static void main (String args[])
    {
        LispExpressionEvaluator expr= new LispExpressionEvaluator();
        String test1 = "(+ (- 6) (* 2 3 4) (/ (+ 3) (* 1) (- 2 3 1)) (+ 0))";
        String test2 = "(+ (- 632) (* 21 3 4) (/ (+ 32) (* 1) (- 21 3 1)) (+ 0))";
        String test3 = "(+ (/ 2) (* 2) (/ (+ 1) (+ 1) (- 2 1 )) (/ 1))";
        String test4 = "(+ (/2)(+ 1))";
        String test5 = "(+ (/2 3 0))";
        String test6 = "(+ (/ 2) (* 2) (/ (+ 1) (+ 3) (- 2 1 ))))";
        String test7 = "(+ (*))";
        String test8 = "(+ (- 6) (* 2 3 4) (/ (+ 3) (* 1) (- 2 3 1)) (+ ))";

        evaluateExprTest(test1, expr, "16.50");
        evaluateExprTest(test2, expr, "-378.12");
        evaluateExprTest(test3, expr, "4.50");
        evaluateExprTest(test4, expr, "1.50");
        evaluateExprTest(test5, expr, "Infinity or LispExpressionEvaluatorException");
        evaluateExprTest(test6, expr, "LispExpressionEvaluatorException");
        evaluateExprTest(test7, expr, "LispExpressionException");
        evaluateExprTest(test8, expr, "LispExpressionException");
    }
}

LispExpressionEvaluatorException异常类

package PJ2;

public class LispExpressionEvaluatorException extends RuntimeException
{
    public LispExpressionEvaluatorException()
    {
        this("");
    }

    public LispExpressionEvaluatorException(String errorMsg) 
    {
        super(errorMsg);
    }
}

项目配置文件project.iml

<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
  <component name="NewModuleRootManager" inherit-compiler-output="true">
    <exclude-output />
    <content url="file://$MODULE_DIR$">
      <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
    </content>
    <orderEntry type="inheritedJdk" />
    <orderEntry type="sourceFolder" forTests="false" />
  </component>
</module>

问题分析与解决方案

核心问题点

  1. 缺少LispExpressionException类:测试用例7、8期望抛出该异常,但当前代码中仅定义了LispExpressionEvaluatorException,未实现前者。
  2. 求值器错误继承异常类:LispExpressionEvaluator继承LispExpressionEvaluatorException违反面向对象设计原则,导致逻辑混乱。
  3. 异常触发逻辑缺失:部分错误场景(如无操作数的运算符、除零、格式错误)未触发对应异常。
  4. 异常捕获范围不全:测试方法仅捕获LispExpressionEvaluatorException,未处理LispExpressionException。

修复步骤

1. 创建LispExpressionException类

新建PJ2.LispExpressionException类:

package PJ2;

public class LispExpressionException extends RuntimeException {
    public LispExpressionException() {
        this("");
    }

    public LispExpressionException(String errorMsg) {
        super(errorMsg);
    }
}

2. 修正求值器的继承关系

移除LispExpressionEvaluator对异常类的继承:

public class LispExpressionEvaluator { // 去掉extends LispExpressionEvaluatorException
    // 原有代码不变
}

3. 完善solveCurrentParenthesisOperation的异常触发逻辑

补充错误场景检测,抛出对应异常:

private void solveCurrentParenthesisOperation() {
    boolean isNumber = true;
    double endResult = 0;
    if(inputExprStack == null) {
        throw new LispExpressionEvaluatorException("表达式栈未初始化");
    }
    String click = "";
    while (isNumber) {
        if (!inputExprStack.empty()) {
            click = String.valueOf(inputExprStack.pop());
        } else {
            throw new LispExpressionException("括号匹配错误或运算符缺失");
        }
        try {
            Double number = Double.parseDouble(click);
            evaluationStack.push(number);
        } catch (NumberFormatException e) {
            isNumber = false;
        }
    }
    if (evaluationStack.size() == 0) {
        throw new LispExpressionException("运算符" + click + "缺少操作数");
    }
    switch (click) {
        case "+":
            endResult = evaluationStack.pop();
            while (!evaluationStack.empty()){
                endResult +=evaluationStack.pop();
            }
            break;
        case "-":
            endResult = evaluationStack.pop();
            if(evaluationStack.size() == 0){
                endResult = -endResult;
            }
            while (!evaluationStack.empty()){
                endResult -=evaluationStack.pop();
            }
            break;
        case "*":
            endResult = evaluationStack.pop();
            while (!evaluationStack.empty()){
                endResult *=evaluationStack.pop();
            }
            break;
        case "/":
            endResult = evaluationStack.pop();
            if(evaluationStack.size() == 0 && endResult != 0){
                endResult = 1.0/endResult;
            }
            while (!evaluationStack.empty()){
                double divisor = evaluationStack.pop();
                if(divisor == 0) {
                    throw new LispExpressionEvaluatorException("除零错误");
                }
                endResult /= divisor;
            }
            break;
        default:
            throw new LispExpressionEvaluatorException("非法运算符:" + click);
    }
    inputExprStack.push(endResult);
}

4. 扩展测试方法的异常捕获范围

修改evaluateExprTest,添加对LispExpressionException的捕获:

private static void evaluateExprTest(String s, LispExpressionEvaluator expr, String expect) {
    Double result;
    System.out.println("表达式 " + s);
    System.out.printf("预期结果 : %s\n", expect);
    expr.reset(s);
    try {
        result = expr.evaluate();
        System.out.printf("求值结果 : %.2f\n", result);
    } catch (LispExpressionEvaluatorException e) {
        System.out.println("求值结果 :" + e);
    } catch (LispExpressionException e) {
        System.out.println("求值结果 :" + e);
    }
    System.out.println("-----------------------------");
}

5. 完善evaluate方法的格式检查

在方法末尾添加栈状态检查,确保表达式格式正确:

public double evaluate() {
    // 原有扫描逻辑不变
    if(inputExprStack.size() != 1) {
        throw new LispExpressionException("表达式格式错误,存在未闭合括号或多余运算符");
    }
    return Double.parseDouble(String.valueOf(inputExprStack.pop()));
}

验证修复

完成修改后,测试用例5会抛出除零异常,测试用例6-8会抛出表达式格式/操作数缺失异常,所有测试用例均能按预期触发并打印异常。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 06:57:01