在弹出元素时将堆栈打印到控制台会不确定地抛出异常

时间:2013-08-24 22:20:32

标签: java eclipse concurrency stack

我只是在日食Juno IDE上用Java编写了一个非常简单的“Stack”类,它有2个操作 - 推送和弹出。我在pop()方法中的一个检查是查看堆栈是否为空;如果是这样,我抛出一个NoSuchElementException。因此,如果我按顺序推1,2,3,4,5然后弹出元素五次,我希望看到按顺序打印5,4,3,2,1。但是在添加了五个元素后,如果我故意尝试将堆栈弹出SIX次,我会期望5,4,3,2,1,然后是NoSuchElementException。

在我的情况下发生的事情是控制台随意打印出NoSuchElementException(即在打印出5,4,3,2,1之后并不总是;有时会打印出来:

stack pop: 5
stack pop: 4
Exception in thread "main" java.util.NoSuchElementException: Stack Underflow
stack pop: 3
stack pop: 2
stack pop: 1
    at Stack.pop(Stack.java:29)
    at Stack.main(Stack.java:47)

有时打印出来:

Exception in thread "main" stack pop: 5
stack pop: 4
stack pop: 3
stack pop: 2
stack pop: 1
java.util.NoSuchElementException: Stack Underflow
    at Stack.pop(Stack.java:29)
    at Stack.main(Stack.java:47)

我的目标是了解管理此行为的原因。由于我正在使用print语句(而不是一个可能在下面有类似队列的实现的记录器),我希望按顺序看到这些语句,但我怀疑这里有一些并发性。以下是我的代码:

import java.util.NoSuchElementException;

public class Stack {

    private Node first;
    private int size;

    private class Node{
       Node next;
       int value;
    }

    public Stack(){
       size=0;
       first=null;
    }

    public void push(int x){        
        Node previousFirst = first;
        first = new Node();
        first.value = x;
        first.next = previousFirst;
        size++;
    }

    public int pop(){
        if(first == null){
            throw new NoSuchElementException("Stack Underflow");
        }       
        int poppedNodeVal = first.value;
        first = first.next;
        size--;
        return poppedNodeVal;
    }

    public static void main(String[] args) {
        Stack stack1 = new Stack();
        stack1.push(1);
        stack1.push(2);
        stack1.push(3);
        stack1.push(4);
        stack1.push(5); 
        for(int i=5; i>=0;i--){
            System.out.println("stack pop: " + stack1.pop());
        }
    }

}

关于如何可靠地打印出来的任何想法,更重要的是,在控制台中可能导致异常打印异常的原因是什么?

3 个答案:

答案 0 :(得分:3)

这是因为System.err和System.out不是同一个流,有时会发生它们未同步的情况。 System.err用于例外,System.out就是您使用的。

也许你想尝试这样的事情:

System.setErr(System.out);

Thiw会将标准System.err路由到System.out 现在你应该有正确的5,4,3,2,1,异常流程。

显然,如果两个流分离是有原因的,那么你可以做我告诉你的事情但是在测试期间要小心(比如在jUnit中)

答案 1 :(得分:2)

您的异常未被捕获,因此会停止执行程序。问题可能是

a)您正在插入5个元素并提取6,将您的循环更改为

 for(int i = 5; i >0; i--)

b)在执行了所有5个元素的System.out.println之后抛出异常(否则这些行根本不会打印,因为程序退出)。但部分内容尚未打印到控制台(它有一个缓冲区)。当异常中断时,它会打印到System.err(不同的缓冲区),因为在您的情况下,System.outSystem.err在控制台中结束,您将获得混合内容。

for包裹在try/catch块中并拦截例外。打印一条消息给System.out通知它。您将看到它在打印最后一个元素之前出现。

答案 2 :(得分:2)

您的邮件正在使用System.out,但例外情况会打印在System.err上。 Eclipse控制台不会同步这两个流,因此它们可能无序地出现在控制台上。尝试将您的消息输出到System.err,它们应该按顺序排列。