6

在我的程序中,我从一个可运行的程序中创建了一个断言(评估结果为假),但从未看到任何关于断言的控制台输出。我想知道我的断言是否为假,但似乎 runnable 正在捕获所有抛出的断言?

下面是我可以编写来演示的最简单的示例程序。(断言已启用。如果未启用,则程序的行为会有所不同,并打印两行而不是仅一行)。程序的输出是。

即将断言 False

而已。之后,断言语句抛出并被某些东西捕获,我永远不知道它。我想知道它,我做错了什么?

import java.nio.ByteBuffer;
import java.util.concurrent.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

import java.awt.FlowLayout;
import javax.swing.*;

class App
{
  private static final ScheduledExecutorService sExecutor =
    Executors.newSingleThreadScheduledExecutor();

  // Main
  public static void main(String[] args)
  {
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
        public void run() { createAndShowGUI(); } });

  }

  // Swing GUI
  private static void createAndShowGUI()
  {
    // Just create a swing thing. Boring
    JFrame frame = new JFrame("Title String");
    JLabel label = new JLabel("Hello World");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().add(label);
    frame.getContentPane().setLayout(new FlowLayout());
    frame.pack();
    frame.setVisible(true);

    // ********************************************
    // INTERESTING CODE HERE. We schedule a runnable which assert's false
    // but we never see a console assert error!
    // ********************************************
    sExecutor.schedule(new Runnable()
      { @Override public void run() { doAssertFalse(); }}, 0, TimeUnit.SECONDS);

  }

  public static void doAssertFalse()
  {
    System.out.println("About to assert False");
    assert false;
    System.out.println("Done asserting False");
  }
}
4

2 回答 2

3

这将做到:

private static final ScheduledExecutorService sExecutor =
        Executors.newSingleThreadScheduledExecutor();

// Main
public static void main(String[] args)
{
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            try {
                createAndShowGUI();
            } catch (ExecutionException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } });

}

// Swing GUI
private static void createAndShowGUI() throws ExecutionException, InterruptedException {
    // Just create a swing thing. Boring
    JFrame frame = new JFrame("Title String");
    JLabel label = new JLabel("Hello World");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().add(label);
    frame.getContentPane().setLayout(new FlowLayout());
    frame.pack();
    frame.setVisible(true);

    // ********************************************
    // INTERESTING CODE HERE. We schedule a runnable which assert's false
    // but we never see a console assert error!
    // ********************************************
    ScheduledFuture<?> future = sExecutor.schedule(new Runnable() {
        @Override
        public void run() {
            doAssertFalse();
        }
    }, 0, TimeUnit.SECONDS);
    future.get();

}

public static void doAssertFalse()
{
    System.out.println("About to assert False");
    assert false;
    System.out.println("Done asserting False");
}

请注意,我将结果保存scheduleScheduledFuture变量中。get()除非您在将来调用该方法,否则不会返回异常。所有异常都抛出包裹在一个ExecutionException.

不幸的是,这会阻塞,所以另一种获得异常的方法是这样的:

// Swing GUI
private static void createAndShowGUI() {
    // Just create a swing thing. Boring
    JFrame frame = new JFrame("Title String");
    JLabel label = new JLabel("Hello World");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().add(label);
    frame.getContentPane().setLayout(new FlowLayout());
    frame.pack();
    frame.setVisible(true);

    // ********************************************
    // INTERESTING CODE HERE. We schedule a runnable which assert's false
    // but we never see a console assert error!
    // ********************************************
    sExecutor.schedule(new Runnable() {
        @Override
        public void run() {
            try {
                doAssertFalse();
            } catch (Error e) {
                e.printStackTrace();
            }
        }
    }, 0, TimeUnit.SECONDS);

}

public static void doAssertFalse() {
    System.out.println("About to assert False");
    assert false;
    System.out.println("Done asserting False");
}

请注意,我正在捕获错误,而不是异常。我这样做是因为断言抛出 java.lang.AssertionError,而不是 *Exception。

我在 Javadoc 中找不到任何文档说 ScheduledExecutorService 吞下异常,除非您执行这些操作,但通过我的测试似乎是这种情况。

于 2013-01-15T19:27:13.243 回答
0

线程对异常不做任何事情(他们怎么可能?如果您不使用 STDERR 或 STDOUT 但登录到数据库怎么办, Thread.run() 怎么知道在哪里记录异常或将异常重新抛出给谁?)

您可以使用一个 Thread.UncaughtExceptionHandler ,当您这样做时,您的 Asserts 应该可以通过它。

我想问题在于 Assert 的机制正在使用异常,因此必须遵循预先确定的异常规则。就我个人而言,我不介意 Assert 是否只是打印了一个堆栈转储并执行了一个 exit(0),因为无论如何您都不应该捕获该异常——但它就是这样。

请注意,您也可以对应用程序中的所有线程只使用一次 Thread.setDefaultUncaughtExceptionHandler(注意“DEFAULT”)......这应该是一个非常好的通用解决方案。

导入java.lang.*;

公共类 ThreadDemo {

   公共静态无效主要(字符串[]参数){

     线程 t = 新线程(新 adminThread());

     t.setUncaughtExceptionHandler(新线程。
     UncaughtExceptionHandler() {
        公共无效未捕获异常(线程 t2,可抛出 e){
           System.out.println(t2 + " 抛出异常:" + e);
        }
     });
     // 这将调用 run() 函数
     t.start();

   }
}

类 adminThread 实现 Runnable {

   公共无效运行(){
      断言(假);
      抛出新的 RuntimeException();
   }
}

当我运行这个“正常”时,它显示 RuntimeException 被抛出。当我使用“-ea”选项运行时,它会显示 AssertException。试试看。

于 2013-01-15T21:20:42.433 回答