【问题标题】:First Java program (calculator) problems第一个Java程序(计算器)问题
【发布时间】:2010-10-03 07:11:26
【问题描述】:

我正在学习 Java,我的第一个项目是计算器,但是我遇到了障碍。我试图让我的计算器让我输入一个数字,然后单击一个运算符(+、-、x、/),输入另一个数字,然后再次点击一个运算符并更新显示并能够继续进行。

例如,我希望能够点击以下内容,并在每次点击运算符后显示总数:

a + b / c - d =

我拥有的代码似乎(对我来说)应该可以工作,但它没有。我做错了什么?

以下是我在点击运算符时使用的代码。默认情况下,等待设置为 false。运行完该类一次后, value1 被存储并将 wait 设置为 true 并且工作正常。从那里开始,它似乎不太正常:

class OperatorListener implements ActionListener {
    public void actionPerformed(ActionEvent event) {
        String input = event.getActionCommand();

        // Set display as string
        String s = display.getText();

        if (!wait) {
            // Convert first input string to double
            try {
                value1 = Double.valueOf(s.trim()).doubleValue();
            } catch (NumberFormatException nfe) {
                System.out.println("NumberFormatException: " + nfe.getMessage());
            }

            dec = false;
        } else {
            // Convert second input string to double
            try {
                value2 = Double.valueOf(s.trim()).doubleValue();
            } catch (NumberFormatException nfe) {
                System.out.println("NumberFormatException: " + nfe.getMessage());
            }

            // Determine operation to be performed
            if (operator == "add") {
                value1 = Operators.add(value1, value2);             
            } else if (operator == "subtract") {
                value1 = Operators.subtract(value1, value2);
            } else if (operator == "multiply") {
                value1 = Operators.multiply(value1, value2);
            } else if (operator == "divide") {
                value1 = Operators.divide(value1, value2);
            }

            // Convert final value to string and display
            display.setText(Double.toString(value1));

            dec = false;
        }

        // Determine operator hit
        if (input.equals("+")) {
            operator = "add";
        } else if (input.equals("-")) {
            operator = "subtract";
        } else if (input.equals("x")) {
            operator = "multiply";
        } else if (input.equals("/")) {
            operator = "divide";
        }

        // Set wait
        wait = true;

    }
}

编辑:更新代码以修复一些混乱并更新 if 语句。即使在此之后,同样的问题仍然存在。此外,完整的源代码可用here

【问题讨论】:

  • 一个建议:在比较字符串时使用 String.equals() 而不是 == (即使字符串字面量是实习的)。
  • 您可能还想研究反向波兰表示法
  • 另一个建议:您的 if-else 块缺少“默认”else 语句,这对于捕获意外值非常有帮助。
  • 你能描述一个有问题的测试用例吗?

标签: java class operators calculator


【解决方案1】:

一些建议。

首先,我建议在使用boolean 作为if 语句的条件时,避免与truefalse 进行比较——无论如何boolean 只有两种状态。此外,由于只有两种状态,而不是使用else if (false)else 就足够了:

if (condition == true)
{
  // when condition is true 
}
else if (condition == false)
{
  // when condition is false
}

可以改写为:

if (condition)
{
  // when condition is true 
}
else
{
  // when condition is false
}

其次,与其比较字符串文字"add""subtract" 等,不如尝试使用常量(final 变量)或enums。进行String 比较(例如(operator == "add"))是在检查字符串文字"add"operator 变量是否都引用同一个对象,而不是是一样的。所以在某些情况下,您可能将operator 设置为"add",但比较可能不是true,因为字符串字面量是指一个单独的对象。一个简单的解决方法是:

final String operatorAdd = "add";
// ...

if (input.equals("+"))
  operator = operatorAdd;
  // ...

if (operator == operatorAdd)
  // ...

现在,operator 的赋值和operator 的比较都引用了常量operatorAdd,因此比较可以使用== 而不是equals() 方法。

第三,因为这似乎是不需要两个操作数(即operand1 + operand2)的计算器类型,而是一个作用于存储值的单个操作数(即operand + currentValue),它可能会更容易拥有一个保存当前值的变量,另一个保存运算符的变量,以及一个根据当前运算符和操作数进行操作的方法。 (或多或少是accumulator machine 或单操作数计算机的概念。)

基本的操作方法是:

  1. 设置currentValue
  2. 设置运算符。
  3. 设置operand
  4. 执行计算。
  5. currentValue设置为计算结果。
  6. 将运算符设置为空白状态。

每个步骤都应该检查上一步是否发生——确保指定了一个操作(operator 设置为一个有效的运算符),然后输入的下一个值变成operand。计算器就像state machine,从一个步骤到另一个步骤必须按照一定的顺序执行,否则将无法进行下一步。

所以,计算器可能是这样的(伪代码!):

// Initialize calculator (Step 1)
currentValue = 0;
operand = 0;
operator = operatorNone;

loop 
{
  operand = getOperand();     // Step 2
  operator = getOperator();   // Step 3

  // Step 4 and 5
  if (operator == operatorAdd)
    currentValue += operand;
  if (operator == operatorSubtract)
    currentValue -= operand;
  // ...

  // Step 6
  operator = operatorNone;
}

虽然上述代码使用单个循环并且不像基于事件的 GUI 模型那样工作,但它应该概述了运行计算器所需的步骤。

【讨论】:

  • 你不想用 operator.equals() 代替 == 吗?
  • 通过在分配变量和比较变量时引用一个常量,使用 == 是有效的,因为它们都将引用同一个对象。在上面的示例中,不需要使用 equals() 方法。
【解决方案2】:

每当你输入一个操作符,你的代码就会执行这个:

Double.valueOf(s.trim())

用于设置value1value2(取决于wait)。这将引发异常,因为运算符不能被解析为双精度。在尝试将输入解析为数字之前,您可能会更好地检查运算符 first。那么如果是算子,就可以跳过数字解析部分。

还要考虑如果有人连续输入两个数字或两个运算符会发生什么。

【讨论】:

  • s的值在String中设置 s = output.getText();部分。另外,如果我先设置运算符,那么它不会使用正确的运算符来合计这两个值。
  • 哦,我明白你在做什么了,你正在使用单个显示字段进行输入和输出。使用“输出”作为输入变量名称是出乎意料的。 :)
  • 是的,我将其命名为“输出”,因为它是输出到屏幕的值。我已将其更新为“显示”以避免混淆。
  • 我认为是时候做一个测试用例了。我们必须处理的最好的事情是“它似乎不太正确”,正如您可以想象的那样,很难将其转化为实际输入。 (1) 你做了什么? (2) 发生了什么? (3) 你预计会发生什么?
【解决方案3】:

正如 Greg 所说,无论输入是什么,无论当前程序状态如何,您总是会解析出数字。您需要更清晰地跟踪程序状态。我假设当你的代码有“String s = output.getText();”你的意思是“String s = input.getText();”。

还要注意

如果(等待==假){ // !wait 的东西 } else if (wait == true) { // 等待的东西 }

是不必要的冗余。您可以将其替换为:

如果(!等待){ // !wait 的东西 } 别的 { // 等待的东西 }

您可能应该首先检查输入字符串以查看它是否是运算符,如果不是,则确保它是数字。编写infix 计算器(正确处理优先级)并非易事。

【讨论】:

  • 当我说 String s = output.getText();我指的是一个名为“object”的 JTextField 实例。我想我应该把它改成“显示”,这是一个更合适的词。另外,虽然我同意您的 if 语句更改,但您的建议不应该对执行产生影响,我错了吗?
  • 执行起来没有区别,只是看起来更干净
  • 虽然我会先检查等待是否为真,然后在 else 部分中有 !wait 代码
  • 我试图让代码流保持在输入的逻辑顺序中。首先等待值是第一个,您将为 value1 分配一个值,然后下一次您将分配给 value2 并计算总数。在我看来只是让阅读更容易。
【解决方案4】:

在高处和低处搜索后,我终于确定问题不在我提供的代码中。我有一个“等待=假;”在我的 NumberListener 类中搞砸了执行。为了解决这个问题,我创建了 2 个单独的等待变量,到目前为止一切正常。

感谢大家的帮助和提示,感谢大家的尝试。

【讨论】:

    【解决方案5】:

    您可以使用 Java 中的脚本引擎。如果你没有 Java 6+,你可以使用 Rhino,它做同样的事情。然后,您几乎可以在 JavaScript 中做任何可以做的事情

    // create a script engine manager
    ScriptEngineManager factory = new ScriptEngineManager();
    // create a JavaScript engine
    ScriptEngine engine = factory.getEngineByName("JavaScript");
    
    // expose a, b, c, d
    engine.put("a", 1);
    engine.put("b", 8);
    engine.put("c", 2);
    engine.put("d", 3);
    
    // evaluate JavaScript code from String
    Number value = (Number) engine.eval("a + b / c * d");
    System.out.println(value);
    

    For more examples

    【讨论】:

    • 技术上可行,但我认为它错过了问题的重点——理解 Java 代码——此外,将简单的任务委托给另一种语言(尤其是 Javascript)是一个不好的习惯,因为语言边界是容易发生错误的地方。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-20
    • 1970-01-01
    • 2018-07-31
    • 2012-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多