juin
2010
Java Quiz #38
Can you help the poor Exception to escape the Matrix ?
Beware, the Agents are nearby and will spot you if you attempt in any way to modify or remove the existing lines of code ! (but you may add new ones).
public class Matrix { public static void getTheSpoon() { throw new java.lang.NoSuchMethodException("There is no spoon !"); } }
public class Test { public static void main(String[] args) { try { Matrix.getTheSpoon(); } catch (Exception ex) { System.out.println(ex instanceof java.lang.NoSuchMethodException ? "You passed the Quiz !" : "You failed !"); } } }
Answer :
Several responses were possible for this quiz, and most have been provided in the comments. Some were very inventive, and some were almost cheating :)
But that's the most interesting part of the quiz isn't it ?
My favourite answer is the one that shamelessly exploits the way the compiler works with java Generics. Simple, effective, but deliciously disgusting :)
public class Matrix { public static void getTheSpoon() { try { throw new NoSuchMethodException("There is no spoon !"); } catch (NoSuchMethodException e) { Matrix.<RuntimeException>escapeFromTheMatrix(e); } } private static<T extends Throwable> void escapeFromTheMatrix(Exception ex) throws T { throw (T) ex; // D'oh ! } }
The trick here is to fool the compiler into thinking that our exception is a RuntimeException
, so that it does not check the getTheSpoon()
method signature for it.
To do that, we take advantage of the type erasure process that occurs during compilation, and cast our NoSuchMethodException
to a mere RuntimeException
- without any compatibility check !
No need to say : I don't recommend using this technique in production.
(But if you find interesting use-cases, please let me know !)
Commentaires
NoSuchMethodException extends RuntimeExption ?
Can you write the quiz in English too please???
Un petit coup de Class.newInstance() fait l'affaire :
public class Matrix {
public static void getTheSpoon() {
try {
Matrix.class.newInstance();
} catch (InstantiationException e) {
// OSEF
} catch (IllegalAccessException e) {
// OSEF
}
}
public Matrix() throws NoSuchMethodException {
throw new NoSuchMethodException("There is no spoon !");
}
}
(si y'a moyen de formatter ça je suis preneur)
Merci le quiz #36 !
Pour ne pas attirer l'attention des agents, je n'ai touché ni à la signature ni au corps de la méthode getTheSpoon(), en ajoutant une classe interne à Matrix :
static class NoSuchMethodException extends RuntimeException {
}
Réponses intéressantes, y'a de l'imagination :)
Maintenant, essayez de résoudre le quiz sans recourir à la Réflexion (il existe plusieurs techniques).
Euh un simple " throws NoSuchMethodException" sur la méthode getTheSpoon ça suffit pas ? (de toute façon ça compile pas sans je pense)
Ops désolé j'ai pas bien lu l'énoncé...
Voilà une autre technique sans introspection mais utilisant une API deprecated :
public class Matrix {
}
Une autre version plus... funky :
public class Matrix {
}
Explications : le <Error> fait croire au compilo qu'on va lancer une Error (donc pas besoin de throws). Le cast (T) devrait en toute naïveté planter au runtime vu qu'on n'a pas une Error mais une Exception, sauf que par la magie des generics Java et de l'erasure, ce cast ne sert à rien et on reste avec notre Throwable.
Pfiou, j'ai mal à la tête moi...
Une variante qui n'utilise ni introspection, ni deprecated, ni warning, et qui répond à la lettre à l'énonce :
public class Matrix {
}
Ma préférée entre toutes : la dernière de Jérôme. Son auteur ne manque ni de finesse ni de rouerie... ;-)))
Comme il ne fait aucun doute que la classe Matrix fait partie du système on peut tout simplement écrire :
public class Matrix {
}
Cela demande d'ajouter la classe au bootclasspath avec le paramètre -Xbootclasspath/a. On pourrait faire sans mais ça ferait appel à java.lang.reflect.
@Emmanuel Bourg : ajouter le paramètre -Xbootclasspath/a impose de rebooter la matrice ;-)
Une dernière variante. C'est pas vraiment de l'introspection :D
public class Matrix {
}
public class Neo extends java.util.ListResourceBundle {
}
Et le gros morceau :
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
public class NeoClassLoader extends ClassLoader {
}
Jérôme, tu es officiellement déclaré Fumeur de Moquette en Chef :D
Tes solutions sont intéressantes et pour le moins inventives ! Si tu n'es pas déjà abonné, je te recommande vivement le Club JavaSpecialist (http://javaspecialists.eu/club), tu y seras comme un poisson dans l'eau !
@Olivier Croisier
Cool, je suis Chef \o/
Je suis abonné à la mailing list de Heinz Kabutz depuis bien longtemps, mais je ne suis pas convaincu de la valeur ajoutée du Java Specialists Club. Si on exclut les webinars qui sont trop preneurs de temps à mon goût, tu y trouves quoi qu'il n'y ait pas ailleurs ?
You could just throw comment block start and end around the throwing of the exception also.