Java, 400
Java được ban phước (?) Với nhiều Exception
s và Error
s. Có nhiều Exception
s đặc trưng cho hoạt động của một lớp duy nhất. Như một ví dụ về một trong những trường hợp cực đoan nhất, có hơn 10 Exception
giây (tất cả đều là lớp con IllegalFormatException
) dành riêng cho Formatter
lớp và tôi đã dành thời gian để làm cho mã ném (gần như) tất cả chúng.
Câu trả lời hiện tại của tôi có 40 Exception
s / s khác nhau Error
và chúng được thực hiện ngẫu nhiên tùy thuộc vào modulo của System.nanoTime()
với một số nguyên.
Phương pháp này chỉ có thể được sử dụng để đo thời gian trôi qua và không liên quan đến bất kỳ khái niệm nào khác về thời gian của hệ thống hoặc đồng hồ treo tường. Giá trị được trả về đại diện cho nano giây do một số thời gian gốc cố định nhưng tùy ý (có thể trong tương lai, vì vậy giá trị có thể âm). Cùng một nguồn gốc được sử dụng bởi tất cả các yêu cầu của phương thức này trong một thể hiện của máy ảo Java; các trường hợp máy ảo khác có khả năng sử dụng một nguồn gốc khác.
Phương pháp trên phải được cho phép, vì nó rơi vào trường hợp "3. Không thể sử dụng số lượng tics hoặc chu kỳ cpu, trừ khi chúng được tính tương đối khi bắt đầu chuỗi chương trình chính" .
Hướng dẫn biên soạn
JRE / JDK hoặc OpenJDK của Oracle được khuyến khích mạnh mẽ để chạy mã. Mặt khác, một số Ngoại lệ có thể không bị ném, vì một số trong số chúng phụ thuộc vào các chi tiết nội bộ của việc triển khai tham chiếu và tôi không có dự phòng đáng tin cậy.
Mã dưới đây biên dịch thành công với javac 1.7.0_11
và tạo ra tất cả Ngoại lệ trên java 1.7.0_51
.
Để chạy mã này, bạn cần sao chép và dán mã bên dưới vào trình chỉnh sửa nhận biết Unicode (ví dụ: Notepad ++), lưu mã đó trong UTF-16 (Big-Endian hoặc Little-Endian không quan trọng miễn là BOM được viết) .
Thay đổi thư mục làm việc ( cd
) thành nơi lưu mã nguồn ( điều này rất quan trọng ).
Biên dịch mã bằng lệnh sau:
javac G19115.java -encoding "UTF-16"
Và chạy mã:
java G19115
Không có gì phá hủy trong mã của tôi, vì tôi cũng muốn thử chạy nó trên máy tính của mình. Mã "nguy hiểm" nhất là xóa ToBeRemoved.class
tệp trong thư mục hiện tại. Ngoài ra, phần còn lại không chạm vào hệ thống tệp hoặc mạng.
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);
}
}
Danh sách các trường hợp ngoại lệ và lỗi
Theo như tuyên bố trong trường hợp chuyển đổi tuyên bố. Có tổng cộng 37 Exception
giây và 3 Error
giây.
- PatternSyntaxException (thông qua lỗi trong
Pattern
, với trường hợp nhàm chán là sao lưu)
- StringIndexOutOfBoundException (thông qua lỗi trong
Pattern
, với trường hợp nhàm chán là sao lưu)
- IllegalArgumentException (giúp tôi tìm ra lỗi
Pattern
, với trường hợp nhàm chán là bản sao lưu)
- StackOverflowError (thông qua triển khai đệ quy trong
Pattern
, với trường hợp nhàm chán là sao lưu)
- NumberFormatException (cho thấy
$
trong Pattern
thể phù hợp trước khi dòng terminator thức)
- IllegalStateException (thông qua việc truy cập các nhóm phù hợp
Matcher
mà không thực hiện một trận đấu)
- ArrayIndexOutOfBoundException (hiển thị hành vi khó hiểu của
split(String regex)
)
- ConcurrencyModificationException (thông qua sửa đổi Bộ sưu tập trong một vòng lặp cho mỗi vòng lặp)
- Số học ngoại lệ (thông qua phép chia số nguyên cho 0)
- ExceptionInInialialError (thông qua việc gây ra
Exception
trong quá trình khởi tạo một lớp)
- BufferOverflowException (đặc
java.nio.*
biệt Exception
)
- BufferUnderflowException (
java.nio.*
cụ thể Exception
)
- InvalidMarkException (
java.nio.*
cụ thể Exception
)
- IndexOutOfBoundException (thông qua tham chiếu đến nhóm bắt giữ không tồn tại thay thế)
- ClassCastException
- NoSuchEuityException
- ArrayStoreException
- Bất hợp phápThreadStateException
- EmptyStackException (đặc
java.util.Stack
biệt Exception
)
- Tiêu cựcArraySizeException
- OutOfMemoryError (thông qua phân bổ nhàm chán của mảng lớn)
- Không được hỗ trợCharsetException
- IllegalCharsetNameException (hiển thị khi
Charset.isSupported(String name)
trả về false hoặc ném Exception
)
- NoClassDefFoundError (cho thấy các lớp được tải khi truy cập lần đầu vào phương thức / hàm tạo hoặc trường)
- InputMismatchException (đặc
java.util.Scanner
biệt Exception
)
- Sao chépFormatFlagsException (từ đây đến 35 là
java.util.Formatter
-specific Exception
s)
- FormatFlagsConversionMismatchException (với ví dụ thú vị về cú pháp định dạng)
- Bất hợp phápFormatCodePointException
- Bất hợp phápFormatConversionException
- Bất hợp phápFormatFlagsException
- Bất hợp phápFormatPrecisionException
- Bất hợp phápFormatWidthException
- MissingFormatArgumentException (với ví dụ thú vị về cú pháp định dạng)
- MissingFormatWidthException
- UnknownFormatConversionException
- IllformedLocaleException
- NullPulumException
- AccessControlException (cho thấy mặc định
SecurityManager
là có thể sử dụng được)
- SecurityException (thông qua việc gọi hàm tạo của
Class
lớp)
- UnknownFormatFlagsException (cho thấy rằng điều này
Exception
không thể được ném trong triển khai của Oracle, không có bản sao lưu)