Подтвердить что ты не робот

Как выбросить проверенное исключение из потока java?

Эй, я пишу сетевое приложение, в котором я читаю пакеты некоторого пользовательского двоичного формата. И я начинаю фоновый поток, чтобы ждать входящих данных. Проблема заключается в том, что компилятор не позволяет мне помещать исключения кода (отмеченные) в run(). В нем говорится:

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

Я хочу, чтобы исключение убило поток, и пусть оно будет поймано где-то в родительском потоке. Возможно ли это для достижения или выполнения каких-либо исключений внутри потока?

4b9b3361

Ответ 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;
    }
}