„Подли хвърляния“ в Java

1. Общ преглед

В Java концепцията sn eaky throw ни позволява да хвърляме всяко проверено изключение, без да го дефинираме изрично в подписа на метода. Това позволява пропускането на декларацията за хвърляния , ефективно имитирайки характеристиките на изключение по време на изпълнение.

В тази статия ще видим как това се прави на практика, като разгледаме някои примери за кодове.

2. Относно подлите хвърляния

Проверените изключения са част от Java, а не от JVM. В байт кода можем да хвърлим всяко изключение отвсякъде, без ограничения.

Java 8 донесе ново правило за извеждане на типа, което гласи, че хвърлянето на T се извежда като RuntimeException, когато е разрешено. Това дава възможност за изпълнение на подли хвърляния без помощния метод.

Проблем с подлите хвърляния е, че вероятно искате да уловите изключенията в крайна сметка, но Java компилаторът не ви позволява да уловите подло хвърлени проверени изключения, използвайки манипулатор на изключения за техния конкретен тип изключения.

3. Подли хвърляния в действие

Както вече споменахме, компилаторът и Jave Runtime могат да видят различни неща:

public static  void sneakyThrow(Throwable e) throws E { throw (E) e; } private static void throwsSneakyIOException() { sneakyThrow(new IOException("sneaky")); }

Компилаторът вижда подписа с хвърлянията T заключи към RuntimeException тип , така че позволява на нерегистриран изключение да се разпространяват. Java Runtime не вижда никакъв тип в хвърлянията, тъй като всички хвърляния са еднакви, просто хвърляне e .

Този бърз тест демонстрира сценария:

@Test public void whenCallSneakyMethod_thenThrowSneakyException() { try { SneakyThrows.throwsSneakyIOException(); } catch (Exception ex) { assertEquals("sneaky", ex.getMessage().toString()); } }

Възможно е да се хвърли отметнато изключение, като се използва манипулация на байт код или Thread.stop (Throwable) , но е объркано и не се препоръчва.

4. Използване на анотации на Lombok

В @SneakyThrows анотация от Ломбок ви позволява да хвърлят проверени изключения, без да използвате хвърлянията декларация. Това е полезно, когато трябва да създадете изключение от метод в рамките на много ограничителни интерфейси като Runnable.

Да кажем, че хвърляме изключение от Runnable ; той ще се подаде само до Thread " и необработено изключение манипулатор.

Този код ще изхвърли екземпляра на изключението , така че няма нужда да го обвивате в RuntimeException:

public class SneakyRunnable implements Runnable { @SneakyThrows(InterruptedException.class) public void run() { throw new InterruptedException(); } }

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

Ето правилната форма за хвърляне на подло изключение:

@SneakyThrows public void run() { try { throw new InterruptedException(); } catch (InterruptedException e) { e.printStackTrace(); } }

И ето теста за това поведение:

@Test public void whenCallSneakyRunnableMethod_thenThrowException() { try { new SneakyRunnable().run(); } catch (Exception e) { assertEquals(InterruptedException.class, e.getStackTrace()); } }

5. Заключение

Както видяхме в тази статия, компилаторът на Java може да бъде подмамен, за да третира проверените изключения като непроверени.

Както винаги кодът е достъпен в GitHub.