4

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

我的目标是了解是什么支配了这种行为。由于我使用的是打印语句(而不是可能在下面具有类似队列实现的记录器),因此我希望按顺序查看这些语句,但我怀疑这里存在一些并发性。下面是我的代码:

导入 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());
        }
    }

}

关于如何可靠地打印出来的任何想法,更重要的是,什么可能导致控制台中异常的这种不确定性打印?

4

3 回答 3

3

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

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

System.setErr(System.out);

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

显然,如果两个流分开是有原因的,所以你可以按照我告诉你的去做,但要小心在测试期间这样做(比如在 jUnit 中)

于 2013-08-24T22:29:41.293 回答
2

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

于 2013-08-24T22:33:15.097 回答
2

您的异常没有被捕获,因此它会停止程序执行。问题大概是

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

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

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

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

于 2013-08-24T22:30:05.543 回答