Как выбросить проверенное исключение из потока java?
Эй, я пишу сетевое приложение, в котором я читаю пакеты некоторого пользовательского двоичного формата. И я начинаю фоновый поток, чтобы ждать входящих данных. Проблема заключается в том, что компилятор не позволяет мне помещать исключения кода (отмеченные) в run()
. В нем говорится:
run() in (...).Listener cannot implement run() in java.lang.Runnable; overridden method does not throw java.io.IOException
Я хочу, чтобы исключение убило поток, и пусть оно будет поймано где-то в родительском потоке. Возможно ли это для достижения или выполнения каких-либо исключений внутри потока?
Ответы
Ответ 1
Предостережение: это может не соответствовать вашим потребностям, если вам нужно использовать механизм исключения.
Если вы правильно поняли, вам действительно не нужно проверять исключение (вы приняли ответ, предлагающий исключение), а простой шаблон слушателя будет более подходящим?
Слушатель может жить в родительском потоке, и когда вы поймали проверенное исключение в дочернем потоке, вы можете просто уведомить слушателя.
Это означает, что у вас есть способ показать, что это произойдет (с помощью общедоступных методов) и сможет передавать больше информации, чем это позволит исключение. Но это означает, что между родительским и дочерним потоком будет связь (пусть и свободная). В вашей конкретной ситуации будет зависеть от того, будет ли это иметь преимущество перед переносом проверенного исключения с помощью непроверенного.
Вот простой пример (некоторый код, заимствованный из другого ответа):
public class ThingRunnable implements Runnable {
private SomeListenerType listener;
// assign listener somewhere
public void run() {
try {
while(iHaveMorePackets()) {
doStuffWithPacket();
}
} catch(Exception e) {
listener.notifyThatDarnedExceptionHappened(...);
}
}
}
Связь происходит от объекта в родительском потоке, который должен иметь тип SomeListenerType
.
Ответ 2
Чтобы иметь возможность отправлять исключение в родительский поток, вы можете поместить фоновый поток в Callable (он также позволяет метать проверенные исключения), которые затем переходят к submit метод некоторый Исполнитель. Метод submit возвращает Future, который затем можно использовать для получения исключения (его get вызовет ExecutionException, который содержит исходное исключение).
Ответ 3
Этот ответ основан на Esko Luontola, но он дает рабочий пример.
В отличие от метода run() интерфейса Runnable метод call() Callable позволяет вызывать некоторые исключения. Вот пример реализации:
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;
}
}
}
Исполнитель предоставляет механизм для запуска вызываемой внутри потока и для обработки любых исключений:
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();
}
}
}
Ответ 4
Я делаю это, чтобы поймать исключение в потоке и сохранить его как переменную-член Runnable. Это исключение затем открывается через геттер на Runnable. Затем я просматриваю все потоки от родителя, чтобы узнать, есть ли какие-либо исключения, и предпримите соответствующие действия.
Ответ 5
Если вы действительно ничего не можете сделать полезными, когда возникает исключение, вы можете перенести исключенное исключение в исключение RuntimeException.
try {
// stuff
} catch (CheckedException yourCheckedException) {
throw new RuntimeException("Something to explain what is happening", yourCheckedException);
}
Ответ 6
нить не может генерировать исключение ни для какого другого потока (ни для основного потока). и вы не можете заставить унаследованный метод run() выкидывать любые проверенные исключения, поскольку вы можете бросить меньше, чем унаследованный код, а не больше.
Ответ 7
Если ваш код потока выдает RuntimeExpection, вам не нужно добавлять исключение throw() throw Exception.
Но используйте это решение только тогда, когда это необходимо, потому что это может быть плохая оценка:
http://java.sun.com/docs/books/tutorial/essential/exceptions/runtime.html
Любое исключение RuntimeException или непроверенное исключение может помочь вам. Возможно, вам нужно создать собственное RuntimeException
Ответ 8
В предположении, что ваш код находится в каком-то цикле, вы должны написать:
public class ThingRunnable implements Runnable {
public void run() {
try {
while(iHaveMorePackets()) {
doStuffWithPacket()
}
} catch(Exception e) {
System.out.println("Runnable terminating with exception" + e );
}
}
}
Исключение автоматически вырвет вас из вашего цикла, а в конце метода run() поток остановится.
Ответ 9
Обертка вашего исключения внутри 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;
}
}