Java >> Java tutorial >  >> Tag >> throw

"Sneaky Throws" i Java

1. Oversigt

I Java er det sneaky kast konceptet giver os mulighed for at kaste enhver markeret undtagelse uden at definere den eksplicit i metodesignaturen. Dette tillader udeladelse af kastene erklæring, der effektivt efterligner karakteristikaene for en runtime-undtagelse.

I denne artikel vil vi se, hvordan dette gøres i praksis, ved at se på nogle kodeeksempler.

2. Om luskede kast

Afkrydsede undtagelser er en del af Java, ikke JVM. I bytekoden kan vi smide enhver undtagelse fra hvor som helst, uden begrænsninger.

Java 8 bragte en ny type inferensregel, der siger, at en kaster T udledes som RuntimeException når det er tilladt. Dette giver mulighed for at implementere luskede kast uden hjælpermetoden.

Et problem med luskede kast er, at du sandsynligvis vil fange undtagelserne til sidst, men Java-kompileren tillader dig ikke at fange lusket afkrydsede afkrydsede undtagelser ved hjælp af undtagelsesbehandler for deres særlige undtagelsestype.

3. Luskede kast i aktion

Som vi allerede har nævnt, kan compileren og Jave Runtime se forskellige ting:

public static <E extends Throwable> void sneakyThrow(Throwable e) throws E {
    throw (E) e;
}

private static void throwSneakyIOException() {
    sneakyThrow(new IOException("sneaky"));
}

Compileren ser signaturen med kast T udledt af en RuntimeException type , så det tillader den umarkerede undtagelse at udbrede sig. Java Runtime ser ikke nogen type i kastene, da alle kast er de samme en simpel kast e .

Denne hurtige test demonstrerer scenariet:

@Test
public void throwSneakyIOException_IOExceptionShouldBeThrown() {
    assertThatThrownBy(() -> throwSneakyIOException())
      .isInstanceOf(IOException.class)
      .hasMessage("sneaky")
      .hasStackTraceContaining("SneakyThrowsExamples.throwSneakyIOException");
}

Ydermere er det muligt at kaste en markeret undtagelse ved hjælp af bytekode-manipulation eller Thread.stop(Throwable) , men det er rodet og anbefales ikke.

4. Brug af Lombok-anmærkninger

@SneakyThrows annotering fra Lombok giver dig mulighed for at smide markerede undtagelser uden at bruge kastene erklæring. Dette er praktisk, når du har brug for at rejse en undtagelse fra en metode inden for meget restriktive grænseflader som Runnable.

Lad os sige, at vi kaster en undtagelse fra en Runnable; det vil kun blive videregivet til Tråden' s ubehandlet undtagelsesbehandler.

Denne kode vil kaste undtagelsen forekomst, så det er ikke nødvendigt for dig at pakke det ind i en RuntimeException:

@SneakyThrows
public static void throwSneakyIOExceptionUsingLombok() {
    throw new IOException("lombok sneaky");
}

En ulempe ved denne kode er, at du ikke kan fange en markeret undtagelse, der ikke er erklæret. For eksempel, hvis vi forsøger at fange IOException snigende smidt af metoden ovenfor, ville vi få en kompileringsfejl.

Lad os nu kalde throwSneakyIOExceptionUsingLombok  og forventer, at Lombok smider IOException:

@Test
public void throwSneakyIOExceptionUsingLombok_IOExceptionShouldBeThrown() {
    assertThatThrownBy(() -> throwSneakyIOExceptionUsingLombok())
      .isInstanceOf(IOException.class)
      .hasMessage("lombok sneaky")
      .hasStackTraceContaining("SneakyThrowsExamples.throwSneakyIOExceptionUsingLombok");
}

5. Konklusion

Som vi har set i denne artikel, kan vi narre Java-kompileren til at behandle markerede undtagelser som umarkerede.

Som altid er koden tilgængelig på GitHub.


Java tag