“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.