Java: как создать пользовательское исключение времени выполнения без использования оператора throw?

Скажем, я хочу предотвратить деление на 3 в любом месте моего текущего пакета. Обычная процедура заключается в создании подкласса Exception:

class NoDivbyThreeException extends RuntimeException {
    public NoDivbyThreeException (String msg) {
        super(msg);
    }
}

а затем бросить его, где требуется:

class CustomExceptionDemo {
    public static void main(String[] args) {
        int numr = 5;
        int denr = 3;
        try {
            if (denr==3) throw new NoDivbyThreeException("Div by 3 not allowed");
            else System.out.println("Result: " + numr/denr);
        }
        catch (NoDivbyThreeException e) {
            System.out.println(e);
        }
     }
}

Но я хочу, чтобы JVM предотвращала деление на 3 в любом месте внутри этого пакета без моего явного указания оператора throw внутри main(). Другими словами, так как JVM предотвращает деление на ноль, автоматически выбрасывая исключение всякий раз, когда она сталкивается с таким сценарием, я хочу, чтобы моя программа делала то же самое всякий раз, когда она сталкивается с ситуацией деления на 3 внутри пакета.

Это возможно? Если нет, поясните почему. Это поможет прояснить мои концепции.


person Vignatus    schedule 27.05.2016    source источник
comment
Вы говорите, что хотите, чтобы он вел себя так же, как когда вы пытаетесь разделить на 0?   -  person RaminS    schedule 28.05.2016
comment
Невозможно. Краткое объяснение: stackoverflow.com/ вопросы/21269461/   -  person luk2302    schedule 28.05.2016
comment
Конечно, это легко. Просто отредактируйте исходный код самой JVM и создайте свою собственную версию. Тогда вы можете заставить его делать все, что вы хотите. --- Я сказал легко. Да, может и нет.   -  person Andreas    schedule 28.05.2016
comment
Аналогичный вопрос для Scala, там даже невозможно использовать метод implicit - stackoverflow.com/questions/4443783/   -  person erkfel    schedule 28.05.2016
comment
@Жандарм да, но скажи только в текущем пакете, а не за его пределами   -  person Vignatus    schedule 29.05.2016


Ответы (3)


Невозможно бросить Exception без явного броска. За исключением некоторых внутренних Exceptions, таких как деление на 0, которые обрабатываются JVM. К ним относятся NullPointerException, если они не вызваны явным оператором throw, деление на 0 и несколько других ошибок. Но эти исключения на самом деле создаются при получении ошибки от базовой платформы. Например. в случае деления на 0 ошибка уже генерируется процессором.

Поэтому, если ваш код каким-либо образом не создает ошибку на базовой платформе, вам придется создавать ошибку самостоятельно. Все остальное потребовало бы, чтобы JVM была очень изменчивой, что не имело бы особого смысла из-за непоследовательного поведения, что нежелательно и приводит к чрезвычайному риску безопасности. В качестве примера того, почему нежелательно отключать JVM:
Рассмотрим ваш пример:

У нас может быть три варианта решения этой проблемы (насколько мне известно, их не существует):

  • изменить код в компиляторе, чтобы создать исключение, если произойдет какое-либо деление на три. Недостаток: код раздувается
  • изменить поведение JVM: еще более нежелательно. Рассмотрим библиотеку, которая выдает исключение при делении на 3. Теперь вы хотите использовать эту библиотеку в своем коде. Но вы ожидаете нормального арифметического поведения и получаете какую-то странную ошибку при делении на 3.
  • добавить в библиотеку заголовок, описывающий ожидаемое поведение JVM. По сравнению с первым вариантом, только нагрузка перемещается из компиляции и памяти в среду выполнения и при запуске/во время компиляции.
person Paul    schedule 27.05.2016
comment
Спасибо, я это понял. Вы случайно не знаете какой-нибудь хороший ресурс, где можно прочитать о том, как JVM генерирует внутренние исключения или что-то подобное? - person Vignatus; 29.05.2016
comment
@Vignatus Вы имеете в виду что-то вроде исключения для деления на 0? Хорошим моментом для начала будет спецификация JVM. - person Paul; 29.05.2016

Я не думаю, что это тривиально возможно.

Вы хотите, чтобы 5 / 3 выдало исключение, верно? То же, что 5 / 0? Согласно этому ответу, "В среде Unix, в каком делении -by-zero сигнализируется через SIGFPE, JVM установит обработчик сигналов, который перехватывает SIGFPE и, в свою очередь, выдает исключение ArithmeticException».

Другими словами, ошибка, вызванная 5 / 0, начинается не с JVM, а с ЦП или ядра вне Java. Вы не можете заставить ЦП или ядро ​​генерировать исключение при делении на 3, и вы не можете переопределить поведение деления в Java.

Смотрите также

person DavidS    schedule 27.05.2016

Для этого вам нужно изменить java.lang.ArithmeticException , что, я думаю, власти не позволят вам сделать, если они узнают, что вы хотите сделать ArithmeticException для деления на 3 :) .

person Rafsan Mobasher    schedule 27.05.2016
comment
На самом деле я пытался изменить его, но потом увидел, что java.lang.ArithmeticException имеет только конструкторы, которые передают аргументы своему суперклассу (RuntimeException), который, в свою очередь, снова передает его суперклассу и так далее. Таким образом, в исходном файле нет кода, описывающего, когда возникает исключение. - person Vignatus; 29.05.2016
comment
Здесь мы говорим об изменении JDK. Я не думаю, что разумно создавать исключение деления на 3, но вот ссылка, в которой есть руководство о том, как внести свой вклад в JDK с открытым исходным кодом: openjdk.java.net/contribute - person Rafsan Mobasher; 29.05.2016