Создание исключения с использованием Unsafe.getUnsafe (). ThrowException - PullRequest
8 голосов
/ 07 декабря 2010

Я наткнулся на интересный код в java.lang.Class # newInstance0:

// Run constructor
try {
    return tmpConstructor.newInstance((Object[])null);
} catch (InvocationTargetException e) {
    Unsafe.getUnsafe().throwException(e.getTargetException());
    // Not reached
    return null;
}

Ознакомьтесь с оператором Unsafe.getUnsafe().throwException.Похоже, что проверенное исключение выдается из метода, который не объявляет, что оно было выброшено!

Почему они это сделали?Если разработчики Sun могут использовать эту технику, нормально ли нам это делать?

Ответы [ 5 ]

3 голосов
/ 14 сентября 2012

С Java и дженериками вы можете извлечь выгоду из стирания типа и просто выбросить любое исключение с помощью этого простого трюка:

public class Test {
    public static void main(String[] args) {
        doThrow(new SQLException());
    }

    public static void doThrow(Exception e) {
        Test.<RuntimeException> doThrow0(e);
    }

    @SuppressWarnings("unchecked")
    public static <E extends Exception> void doThrow0(Exception e) throws E {
        throw (E) e;
    }
}

Вроде страшно, хотя ...

3 голосов
/ 07 декабря 2010

Почему они это сделали?

Я не совсем уверен, но я ожидаю, что была действительно веская причина. (Когда вы проходите сквозь слои, рефлексивный вызов включает в себя некоторые очень сложные вещи ...)

Если разработчики Sun могут использовать эту технику, нормально ли это для нас?

Я бы сказал нет ... если у вас нет действительно, очень веской причины. Методы, которые генерируют проверенные исключения, не объявляя их, нарушают принцип наименьшего удивления. Подумайте о бедняге, которому, возможно, придется отлаживать ваш код в критической производственной системе в 3 часа ночи. * 10101 *

Просто потому, что какой-то инженер Sun решил, что что-то было хорошей идеей в конкретном контексте, не обязательно делает его хорошей идеей в целом.

2 голосов
/ 07 декабря 2010

Есть интересный блог на Как избежать проверенных исключений от Дона Шварца. Спасибо, что поделились.

1 голос
/ 23 января 2017

Sun, по-видимому, сделал это, чтобы разрешить выбрасывать проверенные исключения непосредственно из Class.newInstance(), вместо того, чтобы либо заключать в InvocationTargetException, либо объявить throws Exception в подписи.

Это "интересный" дизайнрешение, поскольку оно отличается от шаблонов в других местах - например, Constructor.newInstance () обернет любые исключения конструктора в InvocationTargetException.

«Преимущество», которое оно предположительно обеспечивает:

  1. возможность отлавливать исключения конструктора напрямую, в их исходном типе;и

  2. избегает newInstance (), необходимого для объявления throws Exception и вызывающей стороны для перехвата Exception.

Недостатком является:

проверенные исключения не объявляются.Это устраняет основное преимущество / цель проверенных исключений и может выдавать предупреждения о том, что блок catch недоступен из-за того, что проверенное исключение не было объявлено.

Может ли это быть шаблоном, который вы могли бы использовать в своем коде?Мне это кажется маловероятным.Кажется, что это в основном потенциально применимо к универсальному коду / фреймворку, где код клиента, обернутый фреймворком, потенциально генерирует проверенные исключения.Тогда было бы желательно использовать, только если вы хотите распространять проверенные исключения, не объявляя о том, что они могут быть выброшены. Для меня это сомнительно.

Большинство методов платформы Java, обертывающих код клиента, разработаны в одном изтри парадигмы исключений:

  1. чисто исключения во время выполнения, или
  2. , объявляющие throws Exception, чтобы разрешить полный спектр проверенных исключений, или
  3. повторного выброса в оболочке'подход (рассмотрите возможность использования неконтролируемого исключения в качестве оболочки).

Этот конкретный метод Class.newInstance очень необычен, и не объявляя проверенные исключения, которые могут быть потенциально выброшены, он обходит / устраняетединственное реальное преимущество проверенных исключений.

Как правило, произошел серьезный сдвиг в сторону времени выполнения, а не проверенных исключений, и я бы не рекомендовал Unsafe.throwException() (ни "взлом универсального кода", упомянутый Лукасом выше.)

Для применениякод, я бы порекомендовал использовать исключения во время выполнения, если это возможно, и объявить типы исключений.Для кода платформы рассмотрим три приведенные выше парадигмы с предпочтением к исключениям времени выполнения.

Справочная информация: http://literatejava.com/exceptions/checked-exceptions-javas-biggest-mistake/

1 голос
/ 07 декабря 2010

Проблема с использованием класса Unsafe заключается в том, что он предназначен только для внутреннего использования, не имеет определенного интерфейса и отличается для разных платформ.

Вы можете добиться того же, используя стандартные вызовы.(Хотя устарела)

Thread.currentThread().stop(checkedException);
...