如何从 Java 线程抛出已检查的异常?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1369204/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 11:15:09  来源:igfitidea点击:

How to throw a checked exception from a java thread?

javaexceptionthread-exceptions

提问by mik01aj

Hey, I'm writing a network application, in which I read packets of some custom binary format. And I'm starting a background thread to wait for incoming data. The problem is, that the compiler doesn't let me to put any code throwing (checked) exceptions into run(). It says:

嘿,我正在编写一个网络应用程序,我在其中读取一些自定义二进制格式的数据包。我正在启动一个后台线程来等待传入的数据。问题是,编译器不允许我将任何抛出(检查)异常的代码放入run(). 它说:

run() in (...).Listener cannot implement run() in java.lang.Runnable; overridden method does not throw java.io.IOException

I want the exception to kill the thread, and let it be caught somewhere in the parent thread. Is this possible to achieve or do I have to handle every exception insidethe thread?

我希望异常杀死线程,并让它在父线程中的某个地方被捕获。这是可能实现的还是我必须处理线程的每个异常?

采纳答案by Grundlefleck

Caveat: this may not meet your needs if you have to use the exception mechanism.

警告:如果您必须使用异常机制,这可能无法满足您的需求。

If I understand you correctly, you don't actually need the exception to be checked (you've accepted the answer suggesting an unchecked exception) so would a simple listener pattern be more appropriate?

如果我理解正确,您实际上并不需要检查异常(您已接受建议未检查异常的答案),那么简单的侦听器模式是否更合适?

The listener could live in the parent thread, and when you've caught the checked exception in the child thread, you could simply notify the listener.

侦听器可以存在于父线程中,当您在子线程中捕获已检查的异常时,您可以简单地通知侦听器。

This means that you have a way of exposing that this will happen (through public methods), and will be able to pass more information than an exception will allow. But it does mean there will be a coupling (albeit a loose one) between the parent and the child thread. It would depend in your specific situation whether this would have a benefit over wrapping the checked exception with an unchecked one.

这意味着您可以通过一种方式(通过公共方法)公开这种情况,并且将能够传递比异常允许的更多的信息。但这确实意味着在父线程和子线程之间会有耦合(尽管是松散的)。这将取决于您的具体情况,这是否比用未经检查的异常包装已检查的异常更有好处。

Here's a simple example (some code borrowed from another answer):

这是一个简单的示例(从另一个答案中借用了一些代码):

public class ThingRunnable implements Runnable {
    private SomeListenerType listener;
    // assign listener somewhere

    public void run() {
        try {
            while(iHaveMorePackets()) { 
                doStuffWithPacket();
            }
        } catch(Exception e) {
            listener.notifyThatDarnedExceptionHappened(...);
        }
    }
 }

The coupling comes from an object in the parent thread having to be of type SomeListenerType.

耦合来自父线程中的一个对象,该对象必须是 类型SomeListenerType

回答by Simon Groenewolt

If you really cannot do anything useful when the exception is raised you can wrap the checked exception in a RuntimeException.

如果在引发异常时您确实无法做任何有用的事情,则可以将已检查的异常包装在 RuntimeException 中。

try {
    // stuff
} catch (CheckedException yourCheckedException) {
    throw new RuntimeException("Something to explain what is happening", yourCheckedException);
}

回答by Nettogrof

If your thread's code throw a RuntimeExpection, you doesn't need to add run() throw Exception.

如果您的线程代码抛出 RuntimeExpection,则无需添加 run() throw Exception。

But use this solution only when appropriate because this can be a bad pratice: http://java.sun.com/docs/books/tutorial/essential/exceptions/runtime.html

但仅在适当时使用此解决方案,因为这可能是一种糟糕的做法:http: //java.sun.com/docs/books/tutorial/essential/exceptions/runtime.html

Any RuntimeException or unchecked Exception can help you. Maybe you'll need to create your own RuntimeException

任何 RuntimeException 或 unchecked Exception 都可以帮助您。也许您需要创建自己的 RuntimeException

回答by rmn

the thread can't throw the exception to any other thread (nor to the main thread). and you cannot make the inherited run() method throw any checked exceptions since you can only throw less than the inherited code, not more.

该线程不能向任何其他线程(也不向主线程)抛出异常。并且您不能让继承的 run() 方法抛出任何已检查的异常,因为您只能抛出少于继承的代码,而不是更多。

回答by AlBlue

On the assumption that your code is in some kind of loop, you'd write:

假设您的代码处于某种循环中,您将编写:

public class ThingRunnable implements Runnable {
  public void run() {
    try {
      while(iHaveMorePackets()) { 
        doStuffWithPacket()
      }
    } catch(Exception e) {
      System.out.println("Runnable terminating with exception" + e );
    }
  }
}

The exception will automatically break you out of your loop, and at the end of the run() method, the thread will stop.

异常会自动使您退出循环,并且在 run() 方法结束时,线程将停止。

回答by Don Branson

What I do is to catch the exception in the thread and store it as a member variable of the Runnable. This exception is then exposed via a getter on the Runnable. I then scan all the threads from the parent to see if any had exceptions, and take the appropriate action.

我所做的是在线程中捕获异常并将其存储为Runnable的成员变量。然后通过 Runnable 上的 getter 公开此异常。然后我扫描来自父级的所有线程以查看是否有任何异常,并采取适当的措施。

回答by Esko Luontola

To be able to send the exception to the parent thread, you can put your background thread in a Callable(it allows throwing also checked exceptions) which you then pass to the submitmethod of some Executor. The submit method will return a Futurewhich you can then use to get the exception (its getmethod will throw an ExecutionExceptionwhich contains the original exception).

为了能够将异常发送到父线程,您可以将后台线程放在Callable 中(它也允许抛出已检查的异常),然后将其传递给某些 Executorsubmit方法。submit 方法将返回一个Future,然后您可以使用它来获取异常(它的get方法将抛出一个包含原始异常的ExecutionException)。

回答by a.b.d

This answer is based on Esko Luontola one but it provides a working example.

这个答案基于 Esko Luontola one,但它提供了一个工作示例。

Unlike the run() method of the Runnable interface the call() method of Callable allows to throw some exceptions. Here is an implementation example :

与 Runnable 接口的 run() 方法不同,Callable 的 call() 方法允许抛出一些异常。这是一个实现示例:

public class MyTask implements Callable<Integer> {

    private int numerator;
    private int denominator;

    public MyTask(int n, int d) {
        this.numerator = n;
        this.denominator = d;
    }

    @Override
    // The call method may throw an exception
    public Integer call() throws Exception {
        Thread.sleep(1000);
        if (denominator == 0) {
            throw new Exception("cannot devide by zero");
        } else {
            return numerator / denominator;
        }
    }

}

Executor provides a mechanism to run a Callable inside a thread and to handle any kind of exceptions :

Executor 提供了一种在线程内运行 Callable 并处理任何类型异常的机制:

public class Main {

    public static void main(String[] args) {

        // Build a task and an executor
        MyTask task = new MyTask(2, 0);
        ExecutorService threadExecutor = Executors.newSingleThreadExecutor();

        try {
            // Start task on another thread
            Future<Integer> futureResult = threadExecutor.submit(task);

            // While task is running you can do asynchronous operations
            System.out.println("Something that doesn't need the tasks result");

            // Now wait until the result is available
            int result = futureResult.get();
            System.out.println("The result is " + result);
        } catch (ExecutionException e) {
            // Handle the exception thrown by the child thread
            if (e.getMessage().contains("cannot devide by zero"))
                System.out.println("error in child thread caused by zero division");
        } catch (InterruptedException e) {
            // This exception is thrown if the child thread is interrupted.
            e.printStackTrace();
        }
    }
}

回答by programmar

Wrapping your exception inside a RuntimeExceptionseems to do the trick.

将您的异常包装在 a 中RuntimeException似乎可以解决问题。

someMethod() throws IOException
{
    try
    {
        new Thread(() ->
        {
            try
            {
                throw new IOException("a checked exception thrown from within a running thread");
            }
            catch(IOException ex)
            {
                throw new RuntimeException("a wrapper exception", ex); // wrap the checked exception inside an unchecked exception and throw it
            }
        }).start();
    }
    catch(RuntimeException ex) // catch the wrapped exception sent from within the thread
    {
        if(ex.getCause() instanceof IOException)
            throw ex.getCause; // unwrap the checked exception using getCause method and use it however you need
        else
            throw ex;
    }
}