«Sneaky Throws» en Java

1. Vue d'ensemble

En Java, le concept de lancement sournois nous permet de lancer n'importe quelle exception vérifiée sans la définir explicitement dans la signature de la méthode. Cela permet l'omission de la déclaration throws , imitant effectivement les caractéristiques d'une exception d'exécution.

Dans cet article, nous verrons comment cela est réalisé en pratique, en examinant quelques exemples de code.

2. À propos des lancers sournois

Les exceptions vérifiées font partie de Java, pas de la JVM. Dans le bytecode, nous pouvons lever n'importe quelle exception de n'importe où, sans restrictions.

Java 8 a apporté une nouvelle règle d'inférence de type qui stipule qu'un throws T est inféré comme RuntimeException chaque fois que cela est autorisé. Cela donne la possibilité d'implémenter des lancers sournois sans la méthode d'assistance.

Un problème avec les lancers sournois est que vous souhaiterez probablement intercepter les exceptions éventuellement, mais le compilateur Java ne vous permet pas d'attraper les exceptions vérifiées sournoises à l'aide du gestionnaire d'exceptions pour leur type d'exception particulier.

3. Les lancers sournois en action

Comme nous l'avons déjà mentionné, le compilateur et le Jave Runtime peuvent voir des choses différentes:

public static  void sneakyThrow(Throwable e) throws E { throw (E) e; } private static void throwsSneakyIOException() { sneakyThrow(new IOException("sneaky")); }

Le compilateur voit la signature avec le throws T inféré à un type RuntimeException , il permet donc à l'exception non vérifiée de se propager. Le Java Runtime ne voit aucun type dans les lancers car tous les lancers sont identiques à un simple lancer e .

Ce test rapide illustre le scénario:

@Test public void whenCallSneakyMethod_thenThrowSneakyException() { try { SneakyThrows.throwsSneakyIOException(); } catch (Exception ex) { assertEquals("sneaky", ex.getMessage().toString()); } }

Il est possible de lancer une exception vérifiée en utilisant la manipulation de bytecode, ou Thread.stop (Throwable) , mais c'est compliqué et déconseillé.

4. Utilisation des annotations Lombok

L' @SneakyThrows annotation de Lombok vous permet de lancer des exceptions vérifiés sans utiliser la throws déclaration. Cela est pratique lorsque vous devez lever une exception à partir d'une méthode dans des interfaces très restrictives telles que Runnable.

Disons que nous lançons une exception depuis un Runnable ; il ne sera transmis à la « discussion s unhandled gestionnaire d'exceptions.

Ce code lèvera l' instance d' Exception , il n'est donc pas nécessaire de l'envelopper dans une RuntimeException:

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

Un inconvénient de ce code est que vous ne pouvez pas intercepter une exception vérifiée qui n'est pas déclarée; donc, il ne se compilera pas .

Voici la forme correcte pour lancer une exception sournoise:

@SneakyThrows public void run() { try { throw new InterruptedException(); } catch (InterruptedException e) { e.printStackTrace(); } }

Et voici le test de ce comportement:

@Test public void whenCallSneakyRunnableMethod_thenThrowException() { try { new SneakyRunnable().run(); } catch (Exception e) { assertEquals(InterruptedException.class, e.getStackTrace()); } }

5. Conclusion

Comme nous l'avons vu dans cet article, le compilateur Java peut être amené à traiter les exceptions vérifiées comme non vérifiées.

Comme toujours, le code est disponible sur GitHub.