Hvornår kaster Java UndeclaredThrowableException?

Java Top

Jeg har lige annonceret det nye Lær foråret kursus med fokus på det grundlæggende i Spring 5 og Spring Boot 2:

>> KONTROLLER KURSEN

1. Oversigt

I denne vejledning skal vi se, hvad der får Java til at kaste en forekomst af UndeclaredThrowableException undtagelse.

Først starter vi med en smule teori. Derefter forsøger vi bedre at forstå denne undtagelses karakter med to virkelige eksempler.

2. Den UndeclaredThrowableException

Teoretisk set vil Java kaste en forekomst af UndeclaredThrowableException når vi forsøger at smide en sort deklareret undtagelse. Det vil sige, at vi ikke erklærede den afkrydsede undtagelse i kaster klausul, men vi kaster denne undtagelse i metodekroppen.

Man kan argumentere for, at dette er umuligt, da Java-kompilatoren forhindrer dette med en kompileringsfejl. For eksempel, hvis vi forsøger at kompilere:

offentlig ugyldig sort () {smid ny IOException (); }

Java-kompilatoren mislykkes med meddelelsen:

java: ikke rapporteret undtagelse java.io.IOException; skal fanges eller erklæres kastet

Selvom det ikke kan ske at kaste sort afkrydsede undtagelser på kompileringstidspunktet, er det stadig en mulighed ved kørsel. Lad os for eksempel overveje en runtime-proxy, der opfanger en metode, der ikke kaster nogen undtagelser:

offentlig ugyldig gemme (Objektdata) {// udeladt}

Hvis proxyen i sig selv kaster en markeret undtagelse, set fra den, der ringer op, Gemme metode kaster den kontrollerede undtagelse. Den, der ringer, ved sandsynligvis ikke noget om den proxy og vil bebrejde den Gemme for denne undtagelse.

Under sådanne omstændigheder vil Java indpakke den faktiske kontrollerede undtagelse i en UndeclaredThrowableException og smid UndeclaredThrowableException i stedet. Det er værd at nævne, at UndeclaredThrowableException i sig selv er en ukontrolleret undtagelse.

Nu hvor vi ved nok om teorien, lad os se et par eksempler fra den virkelige verden.

3. Java Dynamic Proxy

Lad os som vores første eksempel oprette en runtime-proxy til java.util.List grænseflade og opfange dens metodeopkald. Først skal vi implementere InvocationHandler interface og sæt den ekstra logik 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 ("Fejler altid" ); } smid ny RuntimeException (); }} offentlig klasse SomeCheckedException udvider Undtagelse {public SomeCheckedException (strengbesked) {super (besked); }}

Denne proxy kaster en afkrydset undtagelse, hvis den proxy-metode er størrelse. Ellers kaster det en ukontrolleret undtagelse.

Lad os se, hvordan Java håndterer begge situationer. Først kalder vi List.size () metode:

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

Som vist ovenfor opretter vi en proxy til Liste interface og kalde størrelse metode på det. Proxyen til gengæld aflytter opkaldet og kaster en markeret undtagelse. Derefter indpakker Java denne afkrydsede undtagelse i en forekomst af UndeclaredThrowableException.Dette sker, fordi vi på en eller anden måde kaster en kontrolleret undtagelse uden at erklære det i metodedeklarationen.

Hvis vi kalder en anden metode på Liste grænseflade:

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

Da proxyen kaster en ikke-markeret undtagelse, lader Java undtagelsen propagere som den er.

4. Forårsaspekt

Den samme ting sker, når vi kaster en afkrydset undtagelse i et Spring Aspect, mens de rådede metoder ikke erklærede dem. Lad os starte med en kommentar:

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

Nu rådgiver vi alle metoder, der er kommenteret med denne kommentar:

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

Dybest set vil dette råd gøre alle kommenterede metoder til at smide en kontrolleret undtagelse, selvom de ikke erklærede en sådan undtagelse. Lad os nu oprette en tjeneste:

@Service offentlig klasse UndeclaredService {@ThrowUndeclared public void doSomething () {}}

Hvis vi kalder den annoterede metode, kaster Java en forekomst af UndeclaredThrowableException undtagelse:

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

Som vist ovenfor indkapsler Java den faktiske undtagelse som en årsag og kaster UndeclaredThrowableException undtagelse i stedet.

5. Konklusion

I denne vejledning så vi, hvad der får Java til at smide en forekomst af UndeclaredThrowableException undtagelse.

Som sædvanligt er alle eksemplerne tilgængelige på GitHub.

Java bund

Jeg har lige annonceret det nye Lær foråret kursus med fokus på det grundlæggende i Spring 5 og Spring Boot 2:

>> KONTROLLER KURSEN