Når kaster Java UndeclaredThrowableException?

Java Top

Jeg kunngjorde nettopp det nye Lær våren kurs, med fokus på det grunnleggende i vår 5 og vårstøvel 2:

>> KONTROLLER KURSET

1. Oversikt

I denne opplæringen skal vi se hva som får Java til å kaste en forekomst av UndeclaredThrowableException unntak.

Først begynner vi med litt teori. Deretter vil vi prøve å bedre forstå innholdet i dette unntaket med to virkelige eksempler.

2. Den UndeclaredThrowableException

Teoretisk sett vil Java kaste en forekomst av UndeclaredThrowableException når vi prøver å kaste et ikke-deklarert krysset unntak. Det vil si at vi ikke erklærte det avmerkede unntaket i kaster klausul, men vi kaster det unntaket i metodekroppen.

Man kan hevde at dette er umulig ettersom Java-kompilatoren forhindrer dette med en kompileringsfeil. For eksempel hvis vi prøver å kompilere:

offentlig ugyldig svart () {kast ny IOException (); }

Java-kompilatoren mislykkes med meldingen:

java: unapportert unntak java.io.IOException; må fanges eller erklæres kastet

Selv om det ikke er mulig å kaste svartelagde unntak på kompileringstidspunktet, er det fremdeles en mulighet ved kjøretid. La oss for eksempel vurdere en runtime-proxy som avlytter en metode som ikke gir unntak:

offentlig tomrom lagre (Objektdata) {// utelatt}

Hvis proxyen i seg selv kaster et avkrysset unntak, settes fra den som ringer lagre metoden kaster det sjekket unntaket. Innringeren vet sannsynligvis ingenting om den fullmakten og vil skylde på lagre for dette unntaket.

Under slike omstendigheter vil Java pakke det faktiske kontrollerte unntaket inn i et UndeclaredThrowableException og kast UndeclaredThrowableException i stedet. Det er verdt å nevne at UndeclaredThrowableException i seg selv er et ukontrollert unntak.

Nå som vi vet nok om teorien, la oss se noen eksempler fra den virkelige verden.

3. Java Dynamic Proxy

Som vårt første eksempel, la oss lage en runtime-proxy for java.util.Liste grensesnitt og fange opp metodeanropene. Først bør vi implementere InvocationHandler grensesnitt og legg den ekstra logikken der:

offentlig klasse ExceptionalInvocationHandler implementerer InvocationHandler {@Override public Object invoke (Object proxy, Method method, Object [] args) throws Throwable {if ("size" .equals (method.getName ())) {throw new SomeCheckedException ("Feiler alltid" ); } kast nytt RuntimeException (); }} offentlig klasse SomeCheckedException utvider Unntak {public SomeCheckedException (strengmelding) {super (melding); }}

Denne proxyen kaster et avkrysset unntak hvis den nærliggende metoden er størrelse. Ellers kaster det et ukontrollert unntak.

La oss se hvordan Java håndterer begge situasjoner. Først vil vi ringe List.size () metode:

ClassLoader classLoader = getClass () getClassLoader (); InvocationHandler invocationHandler = ny ExceptionalInvocationHandler (); List proxy = (List) Proxy.newProxyInstance (classLoader, new Class [] {List.class}, invocationHandler); assertThatThrownBy (proxy :: size) .isInstanceOf (UndeclaredThrowableException.class) .hasCauseInstanceOf (SomeCheckedException.class);

Som vist ovenfor oppretter vi en proxy for Liste grensesnitt og ring størrelse metode på den. Fullmakten avskjærer i sin tur samtalen og kaster et avkrysset unntak. Deretter pakker Java dette avmerkede unntaket i en forekomst av UndeclaredThrowableException.Dette skjer fordi vi på en eller annen måte kaster et avkrysset unntak uten å erklære det i metodedeklarasjonen.

Hvis vi kaller noen annen metode på Liste grensesnitt:

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

Siden proxyen har et unchecked unntak, lar Java unntaket forplante seg som det er.

4. Våraspekt

Det samme skjer når vi kaster et avkrysset unntak i en Spring Aspect mens de anbefalte metodene ikke erklærte dem. La oss starte med en kommentar:

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

Nå skal vi gi råd om alle metoder som er merket med denne kommentaren:

@Aspect @Component public class UndeclaredAspect {@Around ("@ annotation (undeclared)") public Object advis (ProceedingJoinPoint pjp, ThrowUndeclared undeclared) kaster Throwable {throw new SomeCheckedException ("AOP Checked Exception"); }}

I utgangspunktet vil dette rådet gjøre alle merkede metoder for å kaste et avkrysset unntak, selv om de ikke erklærte et slikt unntak. La oss nå opprette en tjeneste:

@Service public class UndeclaredService {@ThrowUndeclared public void doSomething () {}}

Hvis vi kaller den merkede metoden, vil Java kaste en forekomst av UndeclaredThrowableException unntak:

@RunWith (SpringRunner.class) @SpringBootTest (klasser = UndeclaredApplication.class) offentlig klasse UndeclaredThrowableExceptionIntegrationTest {@Autowired private UndeclaredService service; @Test offentlig ugyldig givenAnAspect_whenCallingAdvisedMethod_thenShouldWrapTheException () {assertThatThrownBy (service :: doSomething) .isInstanceOf (UndeclaredThrowableException.class) .hasCauseInstanceOf (SomeCheckedException.class). }}

Som vist ovenfor, kapsler Java inn det faktiske unntaket som en årsak og kaster UndeclaredThrowableException unntak i stedet.

5. Konklusjon

I denne opplæringen så vi hva som får Java til å kaste en forekomst av UndeclaredThrowableException unntak.

Som vanlig er alle eksemplene tilgjengelige på GitHub.

Java bunn

Jeg kunngjorde nettopp det nye Lær våren kurs, med fokus på det grunnleggende i vår 5 og vårstøvel 2:

>> KONTROLLER KURSET

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