Kada Java baca neprijavljeniThrowableException?

Java Top

Upravo sam najavio novo Uči proljeće tečaj, usredotočen na osnove Spring 5 i Spring Boot 2:

>> PROVJERITE TEČAJ

1. Pregled

U ovom uputstvu vidjet ćemo što uzrokuje da Java baci instancu UndeclaredThrowableException iznimka.

Prvo ćemo započeti s malo teorije. Zatim ćemo pokušati bolje razumjeti prirodu ove iznimke s dva stvarna primjera.

2. The UndeclaredThrowableException

Teoretski gledano, Java će baciti primjerak UndeclaredThrowableException kad pokušamo baciti neprijavljenu provjerenu iznimku. Odnosno, provjerenu iznimku nismo prijavili u baca klauzula, ali tu iznimku bacamo u tijelo metode.

Netko bi mogao tvrditi da je to nemoguće jer Java kompajler to sprečava pogreškom kompilacije. Na primjer, ako pokušamo sastaviti:

javna praznina undeclared () {baciti novi IOException (); }

Kompajler Java ne uspijeva s porukom:

java: neprijavljena iznimka java.io.IOException; mora biti uhvaćen ili proglašen bačenim

Iako se bacanje neprijavljenih provjerenih iznimaka možda neće dogoditi u vrijeme kompajliranja, to još uvijek postoji tijekom izvođenja. Na primjer, razmotrimo runtime proxy koji presreće metodu koja ne dovodi do izuzetaka:

javno prazno spremanje (podaci o objektu) {// izostavljeni}

Ako sam proxy baci provjerenu iznimku, iz perspektive pozivatelja, uštedjeti metoda baca tu provjerenu iznimku. Pozivatelj vjerojatno ne zna ništa o tom proxyju i okrivit će ga uštedjeti za ovu iznimku.

U takvim okolnostima Java će stvarnu provjerenu iznimku umotati u UndeclaredThrowableException i baci UndeclaredThrowableException umjesto toga. Vrijedno je spomenuti da UndeclaredThrowableException sama po sebi je neprovjerena iznimka.

Sad kad znamo dovoljno o teoriji, pogledajmo nekoliko primjera iz stvarnog svijeta.

3. Java dinamički proxy

Kao prvi primjer, stvorimo runtime proxy za java.util.Popis sučelje i presresti pozive njegove metode. Prvo, trebali bismo implementirati InvocationHandler sučelje i stavite tamo dodatnu logiku:

javna klasa ExceptionalInvocationHandler implementira InvocationHandler {@Override javni objekt poziva (Object proxy, Method method, Object [] args) baca Throwable {if ("size" .equals (method.getName ())) {throw new SomeCheckedException ("Always fails" ); } baciti novi RuntimeException (); }} javna klasa SomeCheckedException proširuje Exception {public SomeCheckedException (String poruka) {super (poruka); }}

Ovaj proxy baca provjerenu iznimku ako je proxyirana metoda veličina. U suprotnom, izbacit će neprovjerenu iznimku.

Pogledajmo kako Java rješava obje situacije. Prvo ćemo nazvati List.size () metoda:

ClassLoader classLoader = getClass (). GetClassLoader (); InvocationHandler invocationHandler = novo ExceptionalInvocationHandler (); Popis proxy = (Popis) Proxy.newProxyInstance (classLoader, nova klasa [] {List.class}, invocationHandler); assertThatThrownBy (proxy :: size) .isInstanceOf (UndeclaredThrowableException.class) .hasCauseInstanceOf (SomeCheckedException.class);

Kao što je gore prikazano, kreiramo proxy za Popis sučelje i nazovite veličina metoda na njemu. Proxy pak presreće poziv i baca provjerenu iznimku. Zatim Java provjerava ovu izuzetku u instancu datoteke UndeclaredThrowableException.To se događa jer nekako bacimo provjerenu iznimku bez da je prijavimo u deklaraciji metode.

Ako na. Pozovemo bilo koju drugu metodu Popis sučelje:

assertThatThrownBy (proxy :: isEmpty) .isInstanceOf (RuntimeException.class);

Budući da proxy baca neprovjerenu iznimku, Java dopušta da se iznimka širi kakva jest.

4. Proljetni aspekt

Ista se stvar događa kada bacimo provjerenu iznimku u Spring Aspect dok ih preporučene metode nisu deklarirale. Počnimo s napomenom:

@Target (ElementType.METHOD) @Retention (RetentionPolicy.RUNTIME) public @interface ThrowUndeclared {}

Sada ćemo savjetovati sve metode označene ovom bilješkom:

@Aspect @Component javna klasa UndeclaredAspect {@Around ("@ anotacija (neprijavljeno)") public Object savjet (ProceedingJoinPoint pjp, ThrowUndeclary undeclary) baca Throwable {throw new SomeCheckedException ("AOP Checked Exception"); }}

U osnovi, ovaj će savjet učiniti sve anotirane metode za bacanje provjerene iznimke, čak i ako nisu proglasile takvu iznimku. Ajmo sada stvoriti uslugu:

@Service javna klasa UndeclaredService {@ThrowUndeclared public void doSomething () {}}

Ako pozovemo anotiranu metodu, Java će baciti primjerak UndeclaredThrowableException iznimka:

@RunWith (SpringRunner.class) @SpringBootTest (classes = UndeclaredApplication.class) javna klasa UndeclaredThrowableExceptionIntegrationTest {@Autowired private UndeclaredService service; @Test javna praznina givenAnAspect_whenCallingAdivedMethod_thenShouldWrapTheException () {assertThatThrownBy (service :: doSomething) .isInstanceOf (UndeclaredThrowableException.class) .hasCauseInstanceOf (SomeCheckedExcexcex) }}

Kao što je gore prikazano, Java enkapsulira stvarnu iznimku kao uzrok i baca datoteku UndeclaredThrowableException umjesto toga iznimka.

5. Zaključak

U ovom smo tutorijalu vidjeli što Java uzrokuje bacanje instance UndeclaredThrowableException iznimka.

Kao i obično, svi su primjeri dostupni na GitHubu.

Dno Java

Upravo sam najavio novo Uči proljeće tečaj, usredotočen na osnove Spring 5 i Spring Boot 2:

>> PROVJERITE TEČAJ

$config[zx-auto] not found$config[zx-overlay] not found