Kada Java baca neprijavljeniThrowableException?
Upravo sam najavio novo Uči proljeće tečaj, usredotočen na osnove Spring 5 i Spring Boot 2:
>> PROVJERITE TEČAJ1. 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