Java中的空堆栈异常

时间:2015-04-11 22:51:12

标签: java stack lisp calculator

我不确定这个代码在哪里出错了,所以我希望能够让一些更有经验的人为我审查它。

这是我的Stack Trace:

input an expression string:(+ 1 2)
Evaluate expression #1 :(+ 1 2)
Exception in thread "main" java.util.EmptyStackException
at java.util.Stack.peek(Stack.java:102)
at PJ2.SimpleLispExpressionEvaluator.evaluateCurrentOperation(SimpleLispExpressionEvaluator.java:126)
at PJ2.SimpleLispExpressionEvaluator.evaluate(SimpleLispExpressionEvaluator.java:235)
at PJ2_Test.main(PJ2_Test.java:42)
Java Result: 1

这是第126行:

while(tokenStack.peek() instanceof Double){

这是第235行:

evaluateCurrentOperation();

这是我目前的代码:

import java.util.*;

public class StackCalculator{

private String currentExpression;

// Main expression stack, see algorithm in evaluate()
private Stack<Object> tokenStack;

public SimpleLispExpressionEvaluator()
{
    tokenStack = new Stack();
    currentExpression = "";
}

// constructor with an input expression 
public SimpleLispExpressionEvaluator(String inputExpression) 
{
    tokenStack = new Stack();
    tokenStack.push(inputExpression);
    currentExpression = inputExpression;
}

public void reset(String inputExpression) 
{
    currentExpression = inputExpression;
    //tokenStack.clear();
    //tmpStack.clear();

    //not working for some reason
}


// This function evaluates current operator with its operands
// See complete algorithm in evaluate()
//
// Main Steps:
//      Pop operands from tokenStack and push them onto 
//          tmpStack until you find an operator
//      Apply the operator to the operands on tmpStack
//          Push the result into tokenStack
//
private void evaluateCurrentOperation()
{
    Stack<Double> tmpStack=new Stack<Double>();
    double a=0.0;
    while(!tokenStack.isEmpty()){
        while(!tokenStack.isEmpty()){
        if(tokenStack.peek() instanceof Double){
            tmpStack.push((Double)tokenStack.pop());
        }else if(tokenStack.peek() instanceof Character){
        if(!tokenStack.isEmpty()){
        switch((Character)tokenStack.pop()){
            case '+':
                while(!tmpStack.isEmpty()){
                    a += tmpStack.pop();
                }
                tokenStack.push(a);
            break;
            case '-':
                while(!tmpStack.isEmpty()){
                    a -= tmpStack.pop();
                }
                tokenStack.push(a);
            break;    
            case '*':
                while(!tmpStack.isEmpty()){
                    a *= tmpStack.pop();
                }
                tokenStack.push(a);
            break;
            case '/':
                while(!tmpStack.isEmpty()){
                    a /= tmpStack.pop();
                }
                tokenStack.push(a);
            break;
    }
}
}
}

/**
 *
 * The algorithm:  
 *
 * Step 1           Scan the tokens in the string.
 * Step 2       If you see an operand, push operand object onto the tokenStack
 * Step 3           If you see "(", next token should be an operator
 * Step 4       If you see an operator, push operator object onto the tokenStack
 * Step 5       If you see ")"  // steps in evaluateCurrentOperation() :
 * Step 6       Pop operands and push them onto tmpStack until you find an operator
 * Step 7       Apply the operator to the operands on tmpStack
 * Step 8       Push the result into tokenStack
 * Step 9           If you run out of tokens, the value on the top of tokenStack is the result of the expression.
 */
public double evaluate()
{
    Scanner currentExpressionScanner = new Scanner(currentExpression);
    double finRes = 0.0;
    currentExpressionScanner = currentExpressionScanner.useDelimiter("\\s*");
// Step 1: Scan the tokens in the string.
    while (currentExpressionScanner.hasNext())
    {
// Step 2: If you see an operand, push operand object onto the tokenStack
        if (currentExpressionScanner.hasNextInt())
        {
            // This force scanner to grab all of the digits
            // Otherwise, it will just get one char
            String dataString = currentExpressionScanner.findInLine("\\d+");
            tokenStack.push(Double.parseDouble(dataString));
        }
        else
        {
            // Get next token, only one char in string token
            String aToken = currentExpressionScanner.next();
            //System.out.println("Other: " + aToken);
            char item = aToken.charAt(0);


            switch (item)
            {
// Step 3: If you see "(", next token should be an operator
                case '(':
                    String nextToken = currentExpressionScanner.next();
                    if(!nextToken.equals("+")&&!nextToken.equals("- ")&&!nextToken.equals("*")&&!nextToken.equals("/")){
                    throw new LispExpressionException("After this " + item + " should be an operator");
                    }
                    break;
// Step 4: If you see an operator, push operator object onto the tokenStack
                case '+':
                    tokenStack.push(item);
                    break;
                case '*':
                    tokenStack.push(item);
                    break;
                case '-':
                    tokenStack.push(item);
                    break;
                case '/':
                    tokenStack.push(item);
                    break;
// Step 5: If you see ")"  // steps in evaluateCurrentOperation() :
                case ')':
                    evaluateCurrentOperation();
                    break;
                default:  // error
                    throw new LispExpressionException(item + " is not a legal expression operator");
            } // end switch
        } // end else
    } // end while

// Step 9: If you run out of tokens, the value on the top of tokenStack is
//         the result of the expression.
//         return result
    while(!tokenStack.isEmpty()){
    if(tokenStack.peek() instanceof Character){
        throw new LispExpressionException(tokenStack.pop() + " is not a number!");
    }else{
        finRes = (Double)tokenStack.pop();
    }
    }
return finRes; // return correct answer!
}

2 个答案:

答案 0 :(得分:1)

好吧,看看你的代码,这似乎很明显。如果tokenStack仅包含双精度数,那么当您继续从中移除对象时,它最终将变为空。当它为空时,peek()调用将抛出异常。

while(tokenStack.peek() instanceof Double){
      tmpStack.push((Double)tokenStack.pop());
}

答案 1 :(得分:0)

难道不是很明显吗?堆栈是空的,你正试图窥视它,这就是这个错误告诉你的。不知怎的,在你试图偷看它之前,你实际上并没有把任何东西推到堆叠上。

http://docs.oracle.com/javase/7/docs/api/java/util/EmptyStackException.html