简体   繁体   English

JAVA评估后缀表达式-无法抛出空或无效的表达式

[英]JAVA Evaluating postfix expressions — unable to throw empty or invalid expressions

I'm writing a program that will evaluate a postfix expression and print both the original expression and the result. 我正在编写一个程序,该程序将评估后缀表达式并打印原始表达式和结果。 But I want to account for the validity of the expression as well. 但是我也想解释该表达式的有效性。 For this, I've written two exception classes -- one for an empty collection and one for invalid postfix expressions. 为此,我编写了两个异常类-一个用于空集合,一个用于无效的后缀表达式。 But my code is getting stuck somewhere; 但是我的代码被卡在某个地方。 my output evaluates the first expression correctly, but then only prints the original postfix expressions after that. 我的输出正确评估了第一个表达式,但之后仅输出原始的后缀表达式。 I believe the problem is perhaps coming from my PostfixEvaluator class (see below), where I attempt to check for the size of my stack in the evaluate method. 我相信问题可能出在我的PostfixEvaluator类中(请参见下文),在该类中我尝试在评估方法中检查堆栈的大小。 When commented out, my postfix expressions evaluate (albeit without the exceptions being caught, but still, it's something). 当被注释掉时,我的后缀表达式将求值(尽管没有捕获到异常,但仍然如此)。

My code and resulting output: 我的代码和结果输出:

Postfix Tester: Postfix测试器:

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class PostfixTester    
{
    /**
     * Reads and evaluates multiple postfix expressions.
     * @throws FileNotFoundException 
     */
    public static void main(String[] args) throws FileNotFoundException{
        String expression, again;
        int result;

        //Scanner in = new Scanner(System.in);
        Scanner in = new Scanner(new File("test.txt"));
        PostfixEvaluator evaluator = new PostfixEvaluator();
        while(in.hasNext()){
            expression = in.nextLine();
            System.out.println(expression);
            try{
                result = evaluator.evaluate(expression);
                System.out.println("The result is: " + result);
            }
            catch(EmptyCollectionException e){
                e.getMessage();
            }
            catch(InvalidPostfixExpressionException e){
                e.getMessage();
            }
            System.out.println();
        }
   }
}

Postfix Evaluator: 后缀评估器:

import java.util.Stack;
import java.util.Scanner;


public class PostfixEvaluator
{
    private final static char ADD = '+';
    private final static char SUBTRACT = '-';
    private final static char MULTIPLY = '*';
    private final static char DIVIDE = '/';

    private ArrayStack<Integer> stack;

    /**
     * Sets up this evalutor by creating a new stack.
     */
    public PostfixEvaluator()
    {
        stack = new ArrayStack<Integer>();
    }

    /**
     * Evaluates the specified postfix expression. If an operand is
     * encountered, it is pushed onto the stack. If an operator is
     * encountered, two operands are popped, the operation is
     * evaluated, and the result is pushed onto the stack.
     * @param expr string representation of a postfix expression
     * @return value of the given expression
     */
    public int evaluate(String expr)
    {
        int op1, op2, result = 0;
        String token;
        Scanner parser = new Scanner(expr);

        while (parser.hasNext())
        {
            token = parser.next();

            if (isOperator(token))
            {
                op2 = (stack.pop()).intValue();
                op1 = (stack.pop()).intValue();
                result = evaluateSingleOperator(token.charAt(0), op1, op2);
                stack.push(new Integer(result));
            }
            else
                stack.push(new Integer(Integer.parseInt(token)));
        }
        if(stack.size() != 1){
            throw new InvalidPostfixExpressionException();
        }
        return result;
    }

    /**
     * Determines if the specified token is an operator.
     * @param token the token to be evaluated 
     * @return true if token is operator
     */
    private boolean isOperator(String token)
    {
        return ( token.equals("+") || token.equals("-") ||
                 token.equals("*") || token.equals("/") );
    }

    /**
     * Peforms integer evaluation on a single expression consisting of 
     * the specified operator and operands.
     * @param operation operation to be performed
     * @param op1 the first operand
     * @param op2 the second operand
     * @return value of the expression
     */
    private int evaluateSingleOperator(char operation, int op1, int op2)
    {
        int result = 0;

        switch (operation)
        {
            case ADD:
                result = op1 + op2;
                break;
            case SUBTRACT:
                result = op1 - op2;
                break;
            case MULTIPLY:
                result = op1 * op2;
                break;
            case DIVIDE:
                result = op1 / op2;
        }

        return result;
    }
}

My ArrayStack class: 我的ArrayStack类:

import java.util.Arrays;

public class ArrayStack<T> implements StackADT<T>
{
    private final static int DEFAULT_CAPACITY = 100;

    private int top;  
    private T[] stack;

    /**
     * Creates an empty stack using the default capacity.
     */
    public ArrayStack()
    {
        this(DEFAULT_CAPACITY);
    }

    /**
     * Creates an empty stack using the specified capacity.
     * @param initialCapacity the initial size of the array 
     */
    public ArrayStack(int initialCapacity)
    {
        top = 0;
        stack = (T[])(new Object[initialCapacity]);
    }

    /**
     * Adds the specified element to the top of this stack, expanding
     * the capacity of the array if necessary.
     * @param element generic element to be pushed onto stack
     */
    public void push(T element)
    {
        if (size() == stack.length) 
            expandCapacity();

        stack[top] = element;
        top++;
    }

    /**
     * Creates a new array to store the contents of this stack with
     * twice the capacity of the old one.
     */
    private void expandCapacity()
    {
        stack = Arrays.copyOf(stack, stack.length * 2);   
    }

    /**
     * Removes the element at the top of this stack and returns a
     * reference to it. 
     * @return element removed from top of stack
     * @throws EmptyCollectionException if stack is empty 
     */
    public T pop() throws EmptyCollectionException
    {
        if (isEmpty())
            throw new EmptyCollectionException("stack");

        top--;
        T result = stack[top];
        stack[top] = null; 

        return result;
    }

    /**
     * Returns a reference to the element at the top of this stack.
     * The element is not removed from the stack.  
     * @return element on top of stack
     * @throws EmptyCollectionException if stack is empty
     */
    public T peek() throws EmptyCollectionException
    {
        if (isEmpty())
            throw new EmptyCollectionException("stack");

        return stack[top-1];
    }

    /**
     * Returns true if this stack is empty and false otherwise. 
     * @return true if this stack is empty
     */
    public boolean isEmpty()
    {
        // To be completed as a Programming Project
        return top==0;
    }

    /**
     * Returns the number of elements in this stack.
     * @return the number of elements in the stack
     */
    public int size()
    {
        // To be completed as a Programming Project
        return top;
    }

    /**
     * Returns a string representation of this stack. 
     * @return a string representation of the stack
     */
    public String toString()
    {
        return stack.toString();
    }
}

My input file of expressions (for testing purposes, the final two should throw the two exceptions): 我的表达式输入文件(出于测试目的,最后两个应该抛出两个异常):

8 4 + 3 *
7 5 2 * +
3 1 + 4 2 - *
5 8 2 - +
5 8 - +
6 3 2 -

My actual output: 我的实际输出:

8 4 + 3 *
The result is: 36

7 5 2 * +

3 1 + 4 2 - *

5 8 2 - +

5 8 - +

6 3 2 -

Obviously, I was expecting the first four expressions to follow as the first one did, and the final two to display my exception messages, but I can't seem to figure out where I've gone wrong. 显然,我期望前四个表达式跟第一个一样,最后两个表达式显示我的异常消息,但是我似乎无法弄清楚哪里出了问题。

You push the result to the evaluator stack. 您将结果推送到评估程序堆栈。

You reuse the evaluator in the tester. 您可以在测试仪中重用评估程序。

The evaluator is not clean when you start the second iteration in tester (the result of the previous expression is in the stack). 当您在测试器中开始第二次迭代时,评估程序并不干净(上一个表达式的结果在堆栈中)。

The easiest (and the correct) way to fix this is to change "return result;" 解决此问题的最简单(正确的方法)是更改“返回结果”; to "return stack.pop();" 来“返回stack.pop();”

Next time use a debugger and step through your failing code. 下次使用调试器并逐步检查失败的代码。 It's one of the most useful skills you can have in programming. 这是您可以在编程中拥有的最有用的技能之一。

Asserting preconditions would help too. 主张前提条件也会有所帮助。 Check that stack is empty when you start evaluating an expression. 开始计算表达式时,请检查堆栈是否为空。

The exceptions are thrown but since class PostfixTester is using e.getMessgage() , you won't see the error in the output. 引发了异常,但是由于类PostfixTester使用e.getMessgage() ,您不会在输出中看到错误。 You should use, System.out.println(e.getMessage()) in order to print message. 您应该使用System.out.println(e.getMessage())来打印消息。 But even this change will print null . 但是,即使此更改也将输出null You need to catch exceptions in PostfixEvaluator.evaluate() method and throw again with the message. 您需要在PostfixEvaluator.evaluate()方法中捕获异常,然后再次抛出该消息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM