Java static class exception

How to throw an exception from a static block in Java?

A static block is a set of statements, which will be executed by the JVM before the execution of the main() method. At the time of class loading if we want to perform any activity we have to define that activity inside a static block because this block executes at the time of class loading.

Throw an exception from a Static Block

  • A static block can throw only a RunTimeException, or there should be a try and catch block to catch a checked exception.
  • A static block occurs when a class is loaded by a class loader. The code can either come in the form of a static block or as a call to a static method for initializing a static data member.
  • In both cases, checked exceptions are not allowed by the compiler. When an unchecked exception occurs, it is wrapped by the ExceptionInInitializerError, which is then thrown in the context of the thread that triggered the class loading.
  • Trying to throw a checked exception from a static block is also not possible. We can have a try and catch block in a static block where a checked exception may be thrown from the try block but we have to resolve it within the catch block. We can’t propagate it further using a throw keyword.
Читайте также:  Python является ли значение датой

Example

public class StaticBlockException < static int i, j; static < System.out.println("In the static block"); try < i = 0; j = 10/i; >catch(Exception e) < System.out.println("Exception while initializing" + e.getMessage()); throw new RuntimeException(e.getMessage()); >> public static void main(String args[]) < StaticBlockException sbe = new StaticBlockException(); System.out.println("In the main() method"); System.out.println("Value of i is : "+i); System.out.println("Value of j is : "+ j); >>

Output

In the static block Exception while initializing/ by zero Exception in thread "main" java.lang.ExceptionInInitializerError Caused by: java.lang.RuntimeException: / by zero at StaticBlockException.(StaticBlockException.java:10)

Источник

Исключения в Java, Часть II (checked/unchecked)

Это вторая часть статьи (первая часть — try-catch-finally), посвященной такому языковому механизму Java как исключения. Она имеет вводный характер и рассчитана на начинающих разработчиков или тех, кто только приступает к изучению языка.

Также я веду курс «Scala for Java Developers» на платформе для онлайн-образования udemy.com (аналог Coursera/EdX).

1. «Магия» checked/unchecked

Механизм исключительных ситуация в Java связан с двумя элементами «магии», т.е. поведения, которое никак не отражено в исходном коде:
1. «Магию» java.lang.Throwable — в throw, catch и throws могут стоять исключительно Throwable или его наследники (мы уже разбирали в предыдущей лекции). Это «право» находиться в throw, catch и throws никак не отражено в исходном коде.
2. Все исключительные ситуации делятся на «проверяемые» (checked) и «непроверяемые» (unchecked). Это свойство присуще «корневищу» (Throwable, Error, Exception, RuntimeException) и передается по наследству. Никак не видимо в исходном коде класса исключения.

В дальнейших примера просто учтите, что
— Throwable и Exception и все их наследники (за исключением наследников Error-а и RuntimeException-а) — checked
— Error и RuntimeException и все их наследники — unchecked

checked exception = проверяемое исключение, проверяемое компилятором.
Что именно проверяет компилятор мы разберем на этой лекции.

Читайте также:  Svg in css webpack

Напомним иерархию исключений

 Object | Throwable / \ Error Exception | RuntimeException 

Расставим значение свойства checked/unchecked

 Object | Throwable(CHECKED) / \ Error(UNCHECKED) Exception(CHECKED) | RuntimeException(UNCHECKED) 

2. Пессимистичный механизм

Я называю связь между проверяемыми исключениями и throws — «пессимистичной», польку мы можем «напугать» о большем, чем может произойти на самом деле, но не наоборот

Мы не можем бросать, но не предупредить

public class App < public static void main(String[] args) < throw new Exception(); // тут ошибка компиляции >> >> COMPILATION ERROR: unhandled exception: java.lang.Exception 

Мы не можем бросать, но предупредить о «меньшем»

import java.io.IOException; public class App < public static void main(String[] args) throws IOException < throw new Exception(); // тут ошибка компиляции >> >> COMPILATION ERROR: unhandled exception: java.lang.Exception 

Мы можем предупредить точно о том, что бросаем

Мы можем предупредить о большем, чем мы бросаем

Можем даже предупредить о том, чего вообще нет

Даже если предупреждаем о том, чего нет — все обязаны бояться

public class App < public static void main(String[] args) < f(); // тут ошибка компиляции >public static void f() throws Exception < >> >> COMPILATION ERROR: unhandled exception: java.lang.Exception 

Хотя они (испугавшиеся) могут перепугать остальных еще больше

public class App < // они пугают целым Throwable public static void main(String[] args) throws Throwable < f(); >// хотя мы пугали всего-лишь Exception public static void f() throws Exception < >> 

В чем цель «пессимистичности»? Все достаточно просто.
Вы в режиме протипирования «набросали», скажем, класс-утилиту для скачивания из интернета

public class InternetDownloader < public static byte[] (String url) throws IOException < return "Nothing! It's stub!".getBytes(); > > 

и хотели бы «принудить» пользователей вашего класса УЖЕ ОБРАБАТЫВАТЬ возможное исключение IOException, хотя из реализации-пустышки вы ПОКА НЕ ГЕНЕРИРУЕТЕ такое исключение. Но в будущем — собираетесь.

3. throws с непроверяемым (unckecked) исключением

public class App < public static void main(String[] args) < f(); >public static void f() throws RuntimeException < >> 

Эта конструкция служит цели «указать» программисту-читателю кода на то, что ваш метод может выбросить некоторое непроверяемое (unchecked) исключение.

Пример (java.lang.NumberFormatException — непроверяемое исключение):

package java.lang; public final class Integer extends Number implements Comparable  < . /** * . * * @param s a containing the * representation to be parsed * @return the integer value represented by the argument in decimal. * @exception NumberFormatException if the string does not contain a * parsable integer. */ public static int parseInt(String s) throws NumberFormatException < return parseInt(s,10); >. > 

Integer.parseInt() может бросить unchecked NumberFormatException на неподходящем аргументе (int k = Integer.parseInt(«123abc»)), это отразили
— в сигнатуре метода: throws NumberFormatException
— в документации (javadoc): @ exception
но это ни к чему нас не обязывает.

4. Множественные исключения

Рассмотрим ситуацию с кодом, который может бросать проверяемые исключения разных типов.
Далее учитывайте, что EOFException и FileNotFoundException — потомки IOException.

Мы можем точно указать, что выбрасываем

import java.io.EOFException; import java.io.FileNotFoundException; public class App < // пугаем ОБОИМИ исключениями public static void main(String[] args) throws EOFException, FileNotFoundException < if (System.currentTimeMillis() % 2 == 0) < throw new EOFException(); >else < throw new FileNotFoundException(); >> > 
import java.io.EOFException; import java.io.FileNotFoundException; public class App < // пугаем ОБОИМИ исключениями public static void main(String[] args) throws EOFException, FileNotFoundException < f0(); f1(); >public static void f0() throws EOFException public static void f1() throws FileNotFoundException > 

А можем «испугать» сильнее (предком обоих исключений)

import java.io.EOFException; import java.io.FileNotFoundException; import java.io.IOException; public class App < // пугаем ПРЕДКОМ исключений public static void main(String[] args) throws IOException < if (System.currentTimeMillis() % 2 == 0) < throw new EOFException(); >else < throw new FileNotFoundException(); >> > 
import java.io.EOFException; import java.io.FileNotFoundException; public class App < // пугаем ПРЕДКОМ исключений public static void main(String[] args) throws IOException < f0(); f1(); >public static void f0() throws EOFException public static void f1() throws FileNotFoundException > 

Можно и вот так: EOFException и FileNotFoundException «обобщаем до» IOException, а InterruptedException «пропускаем нетронутым» (InterruptedException — НЕ потомок IOException)

import java.io.EOFException; import java.io.FileNotFoundException; public class App < public static void main(String[] args) throws IOException, InterruptedException < f0(); f1(); f2(); >public static void f0() throws EOFException public static void f1() throws FileNotFoundException public static void f2() throws InterruptedException > 

5. Или catch, или throws

public class App < public static void main(String[] args) < try < throw new Exception(); >catch (Exception e) < // . >> > 

или так (ставим catch по предку и точно перехватываем)

public class App < public static void main(String[] args) < try < throw new Exception(); >catch (Throwable e) < // . >> > 

Но если перехватили только потомка, то не выйдет

public class App < public static void main(String[] args) < try < throw new Throwable(); >catch (Exception e) < // . >> > >> COMPILATION ERROR: unhandled exception: java.lang.Throwable 

Не годится, естественно, и перехватывание «брата»

public class App < public static void main(String[] args) < try < throw new Exception(); >catch (Error e) < // . >> > >> COMPILATION ERROR: unhandled exception: java.lang.Exception 

Если вы часть перехватили, то можете этим не пугать

import java.io.EOFException; import java.io.FileNotFoundException; public class App < // EOFException перехватили catch-ом, им не пугаем public static void main(String[] args) throws FileNotFoundException < try < if (System.currentTimeMillis() % 2 == 0) < throw new EOFException(); >else < throw new FileNotFoundException(); >> catch (EOFException e) < // . >> > 

6. Поведение компилятора/JVM

Необходимо понимать, что
проверка на cheched исключения происходит в момент компиляции (compile-time checking)
перехват исключений (catch) происходит в момент выполнения (runtime checking)

public class App < // пугаем Exception public static void main(String[] args) throws Exception < Throwable t = new Exception(); // и лететь будет Exception throw t; // но тут ошибка компиляции >> >> COMPILATION ERROR: unhandled exception: java.lang.Throwable 
public class App < public static void main(String[] args) throws Exception < Object ref = "Hello!"; // ref указывает на строку char c = ref.charAt(0); // но тут ошибка компиляции >> >> COMPILATION ERROR: Cannot resolve method 'charAt(int)' 

Хотя ССЫЛКА ref УКАЗЫВАЕТ на объект типа java.lang.String (у которого имеется метод charAt(int)), но ТИП ССЫЛКИ — java.lang.Object (ссылка типа java.lang.Object на объект типа java.lang.String). Компилятор ориентируется на «левый тип» (тип ссылки, а не тип ссылаемого) и не пропускает такой код.

Хотя В ДАННОЙ СИТУАЦИИ компилятор мог бы разобрать, что t ссылается на Exception, а ref — на String, но этого уже невозможно сделать при раздельно компиляции. Представьте, что мы МОГЛИ БЫ скомпилировать ОТДЕЛЬНО такой класс, упаковать в jar и распространять

// НЕ КОМПИЛИРУЕТСЯ! ИССЛЕДУЕМ ГИПОТЕТИЧЕСКУЮ СИТУАЦИЮ! public class App < public static void f0(Throwable t) throws Exception < throw t; >public static void f1(Object ref) < char c = ref.charAt(0); >> 

А кто-то берет этот класс, добавляет в classpath и вызывает App.f0(new Throwable()) или App.f1(new Integer(42)). В таком случае JVM столкнулась бы с ситуацией, когда от нее требует бросить проверяемое исключение, которое не отследил компилятор (в случае с f0) или вызвать метод, которого нет (в случае с f1)!

Java — язык со статической типизацией (т.е. отслеживание корректности использования типов (наличие используемых полей, наличие вызываемых методов, проверка на checked исключения, . ) проводится компилятором), запрещает такое поведение. В некоторых языках (языки с динамической типизацией — отслеживание корректности использования типов проводится средой исполнения (оно разрешено, например в JavaScript).

Компилятор не пропустит этот код, хотя метод main ГАРАНТИРОВАННО НЕ ВЫБРОСИТ ИСКЛЮЧЕНИЯ

public class App < // пугаем Exception public static void main(String[] args) throws Exception < try < Throwable t = new Exception(); // и лететь будет Exception throw t; // но тут ошибка компиляции >catch (Exception e) < System.out.println("Перехвачено!"); >> > >> COMPILATION ERROR: unhandled exception: java.lang.Throwable 
public class App < // ТЕПЕРЬ пугаем Throwable public static void main(String[] args) throws Throwable < try < Throwable t = new Exception(); // а лететь будет Exception throw t; >catch (Exception e) < // и мы перехватим Exception System.out.println("Перехвачено!"); >> > >> Перехвачено! 

7. Overriding и throws

При переопределении (overriding) список исключений потомка не обязан совпадать с таковым у предка.
Но он должен быть «не сильнее» списка предка:

import java.io.FileNotFoundException; import java.io.IOException; public class Parent < // предок пугает IOException и InterruptedException public void f() throws IOException, InterruptedException <>> class Child extends Parent < // а потомок пугает только потомком IOException @Override public void f() throws FileNotFoundException <>> 

Однако тут мы попытались «расширить тип» бросаемых исключений

import java.io.IOException; public class Parent < public void f() throws IOException, InterruptedException <>> class ChildB extends Parent < @Override public void f() throws Exception <>> >> COMPILATION ERROR: overridden method does not throw 'java.lang.Exception' 

Почему можно сужать тип, но не расширять?
Рассмотрим следующую ситуацию:

// тут ошибка компиляции в Java, но, ДОПУСТИМ, ее нет public class Child extends Parent < // потомок расширил Exception до Throwable public void f() throws Throwable <>> 
public class Demo < public static void test(Parent ref) < // тут все компилируется, Parent.f() пугает Exception и мы его ловим catch try < ref.f(); >catch(Exception e) <> > > 

Внимательно посмотрите на этот пример — если бы потомок мог расширять тип бросаемого исключения предка, то те места которые «ждут» предка, а получают экземпляр «расширенного» потомка могли бы неконтролируемо выбрасывать проверяемые исключения

8. Передача свойства по наследству

 Object | Throwable(CHECKED) / \ Error(UNCHECKED) Exception(CHECKED) | RuntimeException(UNCHECKED) 

Логика расположения свойства НЕ СВЯЗАНА С НАСЛЕДОВАНИЕМ. Эту логику мы рассмотрим позже (в следующих статьях).
Однако свойство checked/unchecked пользовательских классов исключений строится ИСКЛЮЧИТЕЛЬНО НА ОСНОВЕ НАСЛЕДОВАНИЯ.
Правило крайне простое:
1. Если исключение из списка Throwable, Error, Exception, RuntimeException — то твое свойство надо просто запомнить.
2. Если ты не из списка, то твое свойство равно свойству предка. Нарушить наследование тут нельзя.

Если мы породим потомков A, B, C, D, E, F, G, H, I, J, K, L которые следующим образом наследуются от «корневища» (Throwable, Error, Exception, RuntimeException), то значение их свойства checked/unchecked можно увидеть на схеме

 Object | Throwable(CHECKED) / | \ Error(UNCHECKED) | Exception(CHECKED) | | | | | A(UNC) D(UNC) | F(C) RuntimeException(UNCHECKED) / \ | / \ | | B(UNC) C(UNC) | G(C) H(C) I(UNC) J(UNC) E(C) / \ K(UNC) L(UNC) 

Контакты

  1. показываю различные варианты применения
  2. строю усложняющуюся последовательность примеров по каждому варианту
  3. объясняю логику двигавшую авторами (по мере возможности)
  4. даю большое количество тестов (50-100) всесторонне проверяющее понимание и демонстрирующих различные комбинации
  5. даю лабораторные для самостоятельной работы

skype: GolovachCourses
email: GolovachCourses@gmail.com

Источник

Оцените статью