Java, 400
Java est béni (?) Avec de nombreux Exception
s et Error
s. De nombreux Exception
s sont spécifiques au fonctionnement d'une seule classe. À titre d’exemple de l’un des cas les plus extrêmes, il existe plus de 10 Exception
s (tous sont des sous-classes de IllegalFormatException
)Formatter
classe seule, et j'ai pris le temps de faire le code jette (presque) tous.
Ma réponse actuelle comporte 40 Exception
s / Error
s différents, et ils sont exécutés au hasard en fonction du module de System.nanoTime()
avec un entier.
Cette méthode ne peut être utilisée que pour mesurer le temps écoulé et n'est liée à aucune autre notion de temps système ou d'horloge murale. La valeur renvoyée représente des nanosecondes depuis un certain temps d'origine fixe mais arbitraire (peut-être à l'avenir, donc les valeurs peuvent être négatives). La même origine est utilisée par toutes les invocations de cette méthode dans une instance d'une machine virtuelle Java; d'autres instances de machine virtuelle sont susceptibles d'utiliser une origine différente.
La méthode ci-dessus doit être autorisée, car elle tombe dans le cas «3. Impossible d'utiliser le nombre de cycles de tics ou de CPU, à moins qu'ils ne soient comptés par rapport au début du thread principal du programme» .
Instruction de compilation
JRE / JDK ou OpenJDK d'Oracle est fortement recommandé pour exécuter le code. Sinon, certaines exceptions peuvent ne pas être levées, car certaines d'entre elles reposent sur les détails internes de l'implémentation de référence et je n'ai pas de solution de secours fiable.
Le code ci-dessous se compile avec succès javac 1.7.0_11
et produit toutes les exceptions java 1.7.0_51
.
Pour exécuter ce code, vous devez copier et coller le code ci-dessous dans un éditeur compatible Unicode (par exemple Notepad ++), l'enregistrer en UTF-16 (Big-Endian ou Little-Endian n'a pas d'importance tant que la nomenclature est écrite) .
Changez le répertoire de travail ( cd
) à l'endroit où le code source est enregistré ( c'est important ).
Compilez le code avec la commande suivante:
javac G19115.java -encoding "UTF-16"
Et exécutez le code:
java G19115
Il n'y a rien de destructeur dans mon code, car je veux aussi le tester sur mon ordinateur. Le code le plus "dangereux" est la suppression du ToBeRemoved.class
fichier dans le dossier actuel. En dehors de cela, le reste ne touche pas le système de fichiers ou le réseau.
import java.util.*;
import java.util.regex.*;
import java.lang.reflect.*;
import java.text.*;
import java.io.*;
import java.nio.*;
import java.nio.charset.*;
import java.security.*;
class G19115 {
// The documentation says System.nanoTime() does not return actual time, but a relative
// time to some fixed origin.
private static int n = (int) ((System.nanoTime() % 40) + 40) % 40;
@SuppressWarnings("deprecation")
public static void main(String args[]) {
/**
* If the code is stated to be a bug, then it is only guaranteed to throw Exception on
* Oracle's JVM (or OpenJDK). Even if you are running Oracle's JVM, there is no
* guarantee it will throw Exception in all future releases future either (since bugs
* might be fixed, classes might be reimplemented, and an asteroid might hit the earth,
* in order from the least likely to most likely).
*/
System.out.println(n);
switch (n) {
case 0:
// Bug JDK-7080302
// https://bugs.openjdk.java.net/browse/JDK-7080302
// PatternSyntaxException
System.out.println(Pattern.compile("a(\u0041\u0301\u0328)", Pattern.CANON_EQ));
System.out.println(Pattern.compile("öö", Pattern.CANON_EQ));
// Leave this boring pattern here just in case
System.out.println(Pattern.compile("??+*"));
break;
case 1:
// Bug JDK-6984178
// https://bugs.openjdk.java.net/browse/JDK-6984178
// StringIndexOutOfBoundsException
System.out.println(new String(new char[42]).matches("(?:(?=(\\2|^))(?=(\\2\\3|^.))(?=(\\1))\\2)+."));
// Leave this boring code here just in case
System.out.println("".charAt(1));
break;
case 2:
// IllegalArgumentException
// Bug JDK-8035975
// https://bugs.openjdk.java.net/browse/JDK-8035975
// Should throw IllegalArgumentException... by documentation, but does not!
System.out.println(Pattern.compile("pattern", 0xFFFFFFFF));
// One that actually throws IllegalArgumentException
System.out.println(new SimpleDateFormat("Nothing to see here"));
break;
case 3:
// Bug JDK-6337993 (and many others...)
// https://bugs.openjdk.java.net/browse/JDK-6337993
// StackOverflowError
StringBuffer buf = new StringBuffer(2000);
for (int i = 0; i < 1000; i++) {
buf.append("xy");
}
System.out.println(buf.toString().matches("(x|y)*"));
// Leave this boring code here just in case
main(args);
break;
case 4:
// NumberFormatException
String in4 = "123\r\n";
Matcher m4 = Pattern.compile("^\\d+$").matcher(in4);
if (m4.find()) {
System.out.println(Integer.parseInt(in4));
} else {
System.out.println("Bad input");
}
// NotABug(TM) StatusByDesign(TM)
// $ by default can match just before final trailing newline character in Java
// This is why matches() should be used, or we can call m.group() to get the string matched
break;
case 5:
// IllegalStateException
String in5 = "123 345 678 901";
Matcher m5 = Pattern.compile("\\d+").matcher(in5);
System.out.println(m5.group(0));
// The Matcher doesn't start matching the string by itself...
break;
case 6:
// ArrayIndexOutOfBoundsException
// Who is the culprit?
String[] in6 = {
"Nice weather today. Perfect for a stroll along the beach.",
" Mmmy keeyboaardd iisss bbrokkkkeeen ..",
"",
"\t\t\t \n\n"};
for (String s: in6) {
System.out.println("First token: " + s.split("\\s+")[0]);
}
// Culprit is "\t\t\t \n\n"
// String.split() returns array length 1 with empty string if input is empty string
// array length 0 if input is non-empty and all characters match the regex
break;
case 7:
// ConcurrentModificationException
List<Integer> l7 = testRandom(42);
Integer prev = null;
// Remove duplicate numbers from the list
for (Integer i7: l7) {
if (prev == null) {
prev = i7;
} else {
if (i7.equals(prev)) {
l7.remove(i7);
}
}
}
System.out.println(l7);
// This is one of the typical mistakes that Java newbies run into
break;
case 8:
// ArithmeticException
// Integer division by 0 seems to be the only way to trigger this exception?
System.out.println(0/0);
break;
case 9:
// ExceptionInInitializerError
// Thrown when there is an Exception raised during initialization of the class
// What Exception will be thrown here?
Static s9 = null;
System.out.println(s9.k);
// A bit less interesting
Static ss9 = new Static();
// ----
// A class is only initialized when any of its method/field is
// used for the first time (directly or indirectly)
// Below code won't throw Exception, since we never access its fields or methods
// Static s;
// OR
// Static s = null;
break;
case 10:
// BufferOverflowException
short s10 = 20000;
ShortBuffer b10 = ShortBuffer.allocate(0).put(s10);
// Boring stuff...
break;
case 11:
// BufferUnderflowException
ShortBuffer.allocate(0).get();
// Another boring stuff...
break;
case 12:
// InvalidMarkException
ShortBuffer.allocate(0).reset();
// Boring stuff again...
// reset() cannot be called if mark() is not called before
break;
case 13:
// IndexOutOfBoundsException
System.out.println("I lost $m dollars".replaceAll("[$]m\\b", "$2"));
// $ needs to be escaped in replacement string, since it is special
break;
case 14:
// ClassCastException
Class c14 = Character.class;
for (Field f: c14.getFields()) {
System.out.println(f);
try {
int o = (int) f.get(c14);
// If the result is of primitive type, it is boxed before returning
// Check implementation of sun.reflect.UnsafeStaticIntegerFieldAccessorImpl
System.out.println(o);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
break;
case 15:
// NoSuchElementException
List<Integer> l15 = new ArrayList<Integer>();
Iterator i = l15.iterator();
System.out.println(i.next());
// Another boring one...
break;
case 16:
// ArrayStoreException
Object x[] = new String[3];
x[0] = new Integer(0);
// Straight from the documentation
// I don't even know that this exists...
break;
case 17:
// IllegalThreadStateException
Thread t17 = new Thread();
t17.start();
t17.setDaemon(true);
// setDaemon can only be called when the thread has not started or has died
break;
case 18:
// EmptyStackException
Stack<Integer> s18 = new Stack<Integer>();
s18.addAll(testRandom(43));
while (s18.pop() != null);
// Originally ThreadDeath, which works when running from Dr. Java but not when
// running on cmd line. Seems that Dr. Java provides its own version of
// Thread.UncaughtExceptionHandler that prints out ThreadDeath.
// Please make do with this boring Exception
break;
case 19:
// NegativeArraySizeException
Array.newInstance(Integer.TYPE, -1);
// Do they have to create such a specific Exception?
break;
case 20:
// OutOfMemoryError
Array.newInstance(Integer.TYPE, 1000, 1000, 1000, 1000);
break;
case 21:
// UnsupportedCharsetException
// UCS-2 is superseded by UTF-16
Charset cs21 = Charset.forName("UCS-2");
CharsetEncoder ce21 = cs21.newEncoder();
// Just in case...
cs21 = Charset.forName("o_O");
// "o_O" is a (syntactically) valid charset name, so it throws UnsupportedCharsetException
break;
case 22:
// IllegalCharsetNameException
boolean isSupported;
isSupported = Charset.isSupported("o_O");
isSupported = Charset.isSupported("+_+");
Charset cs22 = Charset.forName("MerryChristmas!Hohoho!");
// This is getting stupid...
break;
case 23:
// NoClassDefFoundError
File f = new File("ToBeRemoved.class");
f.delete();
ToBeRemoved o23 = new ToBeRemoved();
// This shows that class is loaded on demand
break;
case 24:
// InputMismatchException
Scanner sc = new Scanner("2987654321");
sc.nextInt();
// Out of range
break;
case 25:
// Formatter class has many RuntimeException defined
// DuplicateFormatFlagsException
System.out.printf("%0000000000000000000000000000000000000000000000000005%d\n", 42);
break;
case 26:
// FormatFlagsConversionMismatchException
System.out.printf("%,d\n", Integer.MAX_VALUE);
System.out.printf("%,x\n", Integer.MAX_VALUE);
// Thousand separator is only applicable to base 10
System.out.printf("%(5.4f\n", Math.PI);
System.out.printf("%(5.4f\n", -Math.PI);
System.out.printf("%(5.4a\n", -Math.PI);
// '(' flag is used to surround negative value with "( )" instead of prefixing with '-'
// '(' can't be used with conversion 'a'
break;
case 27:
// IllegalFormatCodePointException
System.out.printf("%c", Character.MAX_CODE_POINT + 1);
// Larger than current Unicode maximum code point (0x10FFFF)
break;
case 28:
// IllegalFormatConversionException
String i28 = "0";
System.out.printf("%d", i28);
// A boring example
break;
case 29:
// IllegalFormatFlagsException
System.out.printf("% d\n", Integer.MAX_VALUE);
System.out.printf("% d\n", Integer.MIN_VALUE);
System.out.printf("%+d\n", Integer.MAX_VALUE);
System.out.printf("%+d\n", Integer.MIN_VALUE);
System.out.printf("% +d\n", Integer.MIN_VALUE);
// Use either ' ' or '+ ' flag, not both, since they are mutually exclusive
break;
case 30:
// IllegalFormatPrecisionException
System.out.printf("%5.4f\n", Math.PI);
System.out.printf("%5.4a\n", Math.PI);
System.out.printf("%5.4x\n", Math.PI);
// Precision does not apply to 'x', which is integer hexadecimal conversion
// To print a floating point number in hexadecimal, use conversion 'a'
break;
case 31:
// IllegalFormatWidthException
System.out.printf("%3n");
// For conversion n, width is not supported
break;
case 32:
// MissingFormatArgumentException
System.out.printf("%s\n%<s", "Pointing to previous argument\n");
System.out.printf("%<s", "Pointing to previous argument");
// No previous argument
break;
case 33:
// MissingFormatWidthException
System.out.printf("%5d %<d\n", 42); // Pad left
System.out.printf("%-5d %<d\n", 42); // Pad right
System.out.printf("%-d\n", 42);
// Missing width
break;
case 34:
// UnknownFormatConversionException
System.out.printf("%q", "Shouldn't work");
// No format conversion %q
// UnknownFormatFlagsException cannot be thrown by Formatter class in
// Oracle's implementation, since the flags have been checked in the regex
// used to recognize the format string
break;
case 35:
// IllformedLocaleException
System.out.printf(new Locale("ja"), "%tA %<tB %<tD %<tT %<tZ %<tY\n", new Date());
System.out.printf(new Locale.Builder().setLanguage("ja").setScript("JA").setRegion("JA").build(), "%tA %<tB %<tD %<tT %<tZ %<tf\n", new Date());
// Thrown by Locale.Builder.setScript()
break;
case 36:
// NullPointerException
Pattern p36 = Pattern.compile("a(b)?c");
Matcher m36 = p36.matcher("ac");
if (m36.find()) {
for (int i36 = 0; i36 <= m36.groupCount(); i36++) {
// Use Matcher#end(num) - Matcher#start(num) for length instead
System.out.printf("%3d [%d]: %s\n", i36, m36.group(i36).length(), m36.group(i36));
}
}
break;
case 37:
// AccessControlException
System.setSecurityManager(new SecurityManager());
System.setSecurityManager(new SecurityManager());
break;
case 38:
// SecurityException
// Implementation-dependent
Class ϲlass = Class.class;
Constructor[] constructors = ϲlass.getDeclaredConstructors();
for (Constructor constructor: constructors) {
constructor.setAccessible(true);
try {
Class Сlass = (Class) constructor.newInstance();
} catch (Throwable e) {
System.out.println(e.getMessage());
}
// The code should reach here without any Exception... right?
}
// It is obvious once you run the code
// There are very few ways to get SecurityException (and not one of its subclasses)
// This is one of the ways
break;
case 39:
// UnknownFormatFlagsException
// Implementation-dependent
try {
System.out.printf("%=d", "20");
} catch (Exception e) {
// Just to show the original Exception
System.out.println(e.getClass());
}
Class classFormatter = Formatter.class;
Field[] fs39 = classFormatter.getDeclaredFields();
boolean patternFound = false;
for (Field f39: fs39) {
if (Pattern.class.isAssignableFrom(f39.getType())) {
f39.setAccessible(true);
// Add = to the list of flags
try {
f39.set(classFormatter, Pattern.compile("%(\\d+\\$)?([-#+ 0,(\\<=]*)?(\\d+)?(\\.\\d+)?([tT])?([a-zA-Z%])"));
} catch (IllegalAccessException e) {
System.out.println(e.getMessage());
}
patternFound = true;
}
}
if (patternFound) {
System.out.printf("%=d", "20");
}
// As discussed before UnknownFormatFlagsException cannot be thrown by Oracle's
// current implementation. The reflection code above add = to the list of flags
// to be parsed to enable the path to the UnknownFormatFlagsException.
break;
}
}
/*
* This method is used to check whether all numbers under d are generated when we call
* new Object().hashCode() % d.
*
* However, hashCode() is later replaced by System.nanoTime(), since it got stuck at
* some values when the JVM is stopped and restarted every time (running on command line).
*/
private static List<Integer> testRandom(int d) {
List<Integer> k = new ArrayList<Integer>();
for (int i = 0; i < 250; i++) {
k.add(new Object().hashCode() % d);
}
Collections.sort(k);
System.out.println(k);
return k;
}
}
class ToBeRemoved {};
class Static {
static public int k = 0;
static {
System.out.println(0/0);
}
}
Liste des exceptions et erreurs
Dans l'ordre comme déclaré dans l'instruction switch-case. Il y a 37 Exception
s et 3 Error
s au total.
- PatternSyntaxException (via bug in
Pattern
, avec un cas ennuyeux comme sauvegarde)
- StringIndexOutOfBoundsException (via bug in
Pattern
, avec casse ennuyeuse comme sauvegarde)
- IllegalArgumentException (m'aide à trouver un bogue dans
Pattern
, avec un cas ennuyeux comme sauvegarde)
- StackOverflowError (via une implémentation récursive dans
Pattern
, avec un cas ennuyeux comme sauvegarde)
- NumberFormatException (montre que
$
dans Pattern
peut correspondre avant le terminateur de ligne finale)
- IllegalStateException (via l'accès aux groupes correspondants
Matcher
sans effectuer de correspondance)
- ArrayIndexOutOfBoundsException (montre un comportement déroutant de
split(String regex)
)
- ConcurrentModificationException (via la modification d'une collection pendant une boucle pour chaque)
- ArithmeticException (via la division entière par 0)
- ExceptionInInitializerError (via une cause
Exception
lors de l'initialisation d'une classe)
- BufferOverflowException (
java.nio.*
Spécifiques Exception
)
- BufferUnderflowException (
java.nio.*
-specific Exception
)
- InvalidMarkException (
java.nio.*
-specific Exception
)
- IndexOutOfBoundsException (via une référence à un groupe de capture inexistant en remplacement)
- ClassCastException
- NoSuchElementException
- ArrayStoreException
- IllegalThreadStateException
- EmptyStackException (
java.util.Stack
Spécifiques Exception
)
- NegativeArraySizeException
- OutOfMemoryError (via une allocation ennuyeuse d'un grand tableau)
- UnsupportedCharsetException
- IllegalCharsetNameException (indique quand
Charset.isSupported(String name)
retourne false ou jette Exception
)
- NoClassDefFoundError (montre que les classes sont chargées lors du premier accès à la méthode / constructeur ou au champ)
- InputMismatchException (
java.util.Scanner
Spécifiques Exception
)
- DuplicateFormatFlagsException (d'ici à 35 sont
java.util.Formatter
spécifiques Exception
)
- FormatFlagsConversionMismatchException (avec un exemple intéressant de syntaxe de format)
- IllegalFormatCodePointException
- IllegalFormatConversionException
- IllegalFormatFlagsException
- IllegalFormatPrecisionException
- IllegalFormatWidthException
- MissingFormatArgumentException (avec un exemple intéressant de syntaxe de format)
- MissingFormatWidthException
- UnknownFormatConversionException
- IllformedLocaleException
- NullPointerException
- AccessControlException (montre que la valeur par défaut
SecurityManager
est utilisable)
- SecurityException (via l'appel du constructeur de
Class
classe)
- UnknownFormatFlagsException (montre que cela
Exception
ne peut pas être levé dans l'implémentation d'Oracle, pas de sauvegarde)