“Sneaky Throws” på Java

1. Oversikt

I Java er sneaky kast konseptet lar oss kaste ethvert avkrysset unntak uten å definere det eksplisitt i metodesignaturen. Dette tillater utelatelse av kaster erklæring, som effektivt imiterer egenskapene til et kjøretidsunntak.

I denne artikkelen vil vi se hvordan dette gjøres i praksis, ved å se på noen kodeeksempler.

2. Om snike kaster

Merkede unntak er en del av Java, ikke JVM. I bytekoden kan vi kaste ethvert unntak hvor som helst, uten begrensninger.

Java 8 brakte en ny type inferensregel som sier at en kaster T er utledet som RuntimeException når det er tillatt. Dette gir muligheten til å implementere snike kast uten hjelpemetoden.

Et problem med sluete kast er at du sannsynligvis vil fange unntakene til slutt, men Java-kompilatoren lar deg ikke fange snikete kastede avmerkede unntak ved å bruke unntaksbehandler for deres spesielle unntakstype.

3. Luskede kaster i aksjon

Som vi allerede har nevnt, kan kompilatoren og Jave Runtime se forskjellige ting:

public static void sneakyTrow (Throwable e) throw E {throw (E) e; } private statiske tomrom kasterSneakyIOException () {sneakyThrow (ny IOException ("sneaky")); }

Kompilatoren ser signaturen med kaster T utledet til en RuntimeException type, så det lar det ukontrollerte unntaket forplante seg. Java Runtime ser ingen type i kastene, ettersom alle kast er like enkle kaste e.

Denne raske testen viser scenariet:

@Test offentlig ugyldig nårCallSneakyMethod_thenThrowSneakyException () {prøv {SneakyThrows.throwsSneakyIOException (); } catch (Exception ex) {assertEquals ("sneaky", ex.getMessage (). toString ()); }}

Det er mulig å kaste et avkrysset unntak ved hjelp av bytecode-manipulering, eller Thread.stop (Throwable), men det er rotete og anbefales ikke.

4. Bruke Lombok-merknader

De @SneakyThrows kommentar fra Lombok lar deg kaste avmerkede unntak uten å bruke kaster erklæring. Dette er nyttig når du trenger å heve et unntak fra en metode innen veldig restriktive grensesnitt som Kjørbar.

Si at vi kaster et unntak innenfra a Kjørbar; det vil bare bli overført til Tråd's ubehandlet unntaksbehandler.

Denne koden vil kaste Unntak eksempel, så det er ikke noe behov for deg å pakke den inn i en RuntimeException:

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

En ulempe med denne koden er at du ikke kan fange et avkrysset unntak som ikke er erklært; så vil det ikke kompilere.

Her er riktig skjema for å kaste et luskent unntak:

@SneakyThrows public void run () {prøv {kast nytt InterruptedException (); } fange (InterruptedException e) {e.printStackTrace (); }}

Og her er testen for denne oppførselen:

@Test offentlig ugyldig når CallSneakyRunnableMethod_thenThrowException () {prøv {new SneakyRunnable (). Run (); } fange (Unntak e) {assertEquals (InterruptedException.class, e.getStackTrace ()); }}

5. Konklusjon

Som vi har sett i denne artikkelen, kan Java-kompilatoren bli lurt til å behandle avmerkede unntak som ukontrollert.

Som alltid er koden tilgjengelig på GitHub.


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