catalogue
Array subscript out of bounds exception
1. Abnormal background
Initial anomaly
In the previous study, we have actually been exposed to "exceptions" in Java.
Arithmetic anomaly
System.out.println(10 / 0); // results of enforcement // Exception in thread "main" java.lang.ArithmeticException: / by zero
Array subscript out of bounds exception
int[] arr = {1, 2, 3}; System.out.println(arr[100]); // results of enforcement // Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 100
Null pointer exception
public class Test { public int num = 10; public static void main(String[] args) { Test t = null; System.out.println(t.num); } } // results of enforcement // Exception in thread "main" java.lang.NullPointerException
An exception is a mechanism by which a program notifies the caller of an error at runtime
Keyword "runtime"
Some errors are like this. For example, misspell system.out.println and write it as system.out.println. At this time, errors will occur during the compilation process, which is a "compilation time" error
Runtime refers to the error that occurs when the program has been compiled to get the class file and then executed by the JVM
Defensive programming
Errors exist objectively in the code. Therefore, we should inform the program in time when there are problems in the program. We have two main ways:
- LBYL: Look Before You Leap
- EAFP: It's Easier to Ask Forgiveness than Permission
In fact, it's easy to understand. Take chestnuts for example:
For example, there is a girl you like very much. You want to pull her little hand.
- The first situation: first ask if you can pull her little hand, and then pull it with consent. (LBYL)
- The second situation: pull it directly. The big deal is to slap you and apologize . (EAFP)
Exceptional benefits
For example, let's use pseudo code to demonstrate the process of starting a game of King glory:
LBYL style code (no exceptions)
boolean ret = false; ret = Login game(); if (!ret) { Handling login game errors; return; } ret = Start matching(); if (!ret) { Processing matching errors; return; } ret = Game confirmation(); if (!ret) { Processing game confirmation errors; return; } ret = Select hero(); if (!ret) { Handling selection hero errors; return; } ret = Load game screen(); if (!ret) { Handling load game errors; return; } ......
EAFP style code (using exceptions)
try { Login game(); Start matching(); Game confirmation(); Select hero(); Load game screen(); ... } catch (Login game exception) { Handling login game exceptions; } catch (Start matching exception) { Processing start matching exception; } catch (Game confirmation exception) { Handling game confirmation exceptions; } catch (Select hero exception) { Handle select hero exception; } catch (Abnormal loading game screen) { Handling loading game screen exception; } ......
Comparing two different styles of code, we can find that using the first method, the normal process and error handling process code are mixed together,
The whole code is chaotic. The second way is that the normal process and error process are separated, which makes it easier to understand the code.
2. Basic usage of exceptions
Catch exception
Basic syntax:
try{ Statements with possible exceptions ; }catch (Exception type exception object) { } finally { Abnormal exit }
- The try code block contains the code that may cause exceptions
- The catch code block contains the handling behavior after an exception occurs
- finally, the code in the code block is used to deal with the aftermath and will be executed at the end
- catch and finally can be added or not according to the situation
Example 1 Do not handle exceptions :
int[] arr = {1, 2, 3}; System.out.println("before"); System.out.println(arr[100]); System.out.println("after"); // results of enforcement before Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 100
We found that once an exception occurs, the program terminates. after does not output correctly.
Example 2 Use try catch to handle exceptions:
int[] arr = {1, 2, 3}; try { System.out.println("before"); System.out.println(arr[100]); System.out.println("after"); } catch (ArrayIndexOutOfBoundsException e) { // Print the call stack with exception e.printStackTrace(); } System.out.println("after try catch"); // results of enforcement before java.lang.ArrayIndexOutOfBoundsException: 100 at demo02.Test.main(Test.java:10) after try catch
We found that once an exception occurs in try, the program in the try code block will not continue to execute, but will be executed by the code in catch. After catch is executed, it will continue to execute
Example 3 catch can only handle exceptions of the corresponding kind:
int[] arr = {1, 2, 3}; try { System.out.println("before"); arr = null; System.out.println(arr[100]); System.out.println("after"); } catch (ArrayIndexOutOfBoundsException e) { e.printStackTrace(); } System.out.println("after try catch"); // results of enforcement before Exception in thread "main" java.lang.NullPointerException at demo02.Test.main(Test.java:11)
At this time, the catch statement cannot catch the null pointer exception just now because the exception types do not match
Example 4 A catch can have multiple:
int[] arr = {1, 2, 3}; try { System.out.println("before"); arr = null; System.out.println(arr[100]); System.out.println("after"); } catch (ArrayIndexOutOfBoundsException e) { System.out.println("This is an array subscript out of bounds exception"); e.printStackTrace(); } catch (NullPointerException e) { System.out.println("This is a null pointer exception"); e.printStackTrace(); } System.out.println("after try catch"); // results of enforcement before This is a null pointer exception java.lang.NullPointerException at demo02.Test.main(Test.java:12) after try catch
A piece of code may throw many different exceptions, and different exceptions have different handling methods. Therefore, it can be combined with multiple catch code blocks
If multiple exceptions are handled in exactly the same way, it can also be written as follows:
catch (ArrayIndexOutOfBoundsException | NullPointerException e) { ... }
Example 5 You can also catch all exceptions with one catch (not recommended):
int[] arr = {1, 2, 3}; try { System.out.println("before"); arr = null; System.out.println(arr[100]); System.out.println("after"); } catch (Exception e) { e.printStackTrace(); } System.out.println("after try catch"); // results of enforcement before java.lang.NullPointerException at demo02.Test.main(Test.java:12) after try catch
Because the Exception class is the parent of all Exception classes, this type can be used to catch all exceptions.
Note: when catch performs type matching, it will not only match exception objects of the same type, but also catch subclass objects of the target exception type
As in the code just now, NullPointerException and ArrayIndexOutOfBoundsException are subclasses of Exception, so they can be caught
Example 6 finally indicates the final aftermath work, such as releasing resources:
int[] arr = {1, 2, 3}; try { System.out.println("before"); arr = null; System.out.println(arr[100]); System.out.println("after"); } catch (Exception e) { e.printStackTrace(); } finally { System.out.println("finally code"); } // results of enforcement before java.lang.NullPointerException at demo02.Test.main(Test.java:12) finally code
Whether there is an exception or not, the code in finally will be executed
Example 7 Use try to recycle resources:
try (Scanner sc = new Scanner(System.in)) { int num = sc.nextInt(); System.out.println("num = " + num); } catch (Exception e) { e.printStackTrace(); }
Create the Scanner object in the () of the try to ensure that the close method of the Scanner will be called automatically after the try is executed.
Example 8 If there is no proper way to handle exceptions in this method, it will be passed up the call stack
public static void main(String[] args) { try { func(); } catch (ArrayIndexOutOfBoundsException e) { e.printStackTrace(); } System.out.println("after try catch"); } public static void func() { int[] arr = {1, 2, 3}; System.out.println(arr[100]); } // Direct result java.lang.ArrayIndexOutOfBoundsException: 100 at demo02.Test.func(Test.java:18) at demo02.Test.main(Test.java:9) after try catch
Example 9 If there is no proper method to handle the exception all the time, it will eventually be handed over to the JVM for processing, and the program will terminate abnormally (the same as when we didn't use try catch at first)
public static void main(String[] args) { func(); System.out.println("after try catch"); } public static void func() { int[] arr = {1, 2, 3}; System.out.println(arr[100]); } // results of enforcement Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 100 at demo02.Test.func(Test.java:14) at demo02.Test.main(Test.java:8)
The program has terminated abnormally and is not executed to System.out.println("after try catch"); This line.
Exception handling process
- The program executes the code in try first
- If an exception occurs in the code in try, the code in try will be terminated to see if it matches the exception type in catch
- If a matching exception type is found, the code in catch is executed
- If no matching exception type is found, the exception is passed up to the upper caller
- The code in finally is executed to (before the end of the method) whether a matching exception type is found or not
- If the upper caller does not handle the exception, it continues to pass up
- Until the main method has no appropriate code to handle exceptions, it will be handed over to the JVM for processing, and the program will terminate abnormally
Throw exception
In addition to some exceptions thrown by Java built-in classes, you can also throw an exception manually. Use the throw keyword to complete this operation
public static void main(String[] args) { System.out.println(divide(10, 0)); } public static int divide(int x, int y) { if (y == 0) { throw new ArithmeticException("Throw exception except 0"); } return x / y; } // results of enforcement Exception in thread "main" java.lang.ArithmeticException: Throw exception except 0 at demo02.Test.divide(Test.java:14) at demo02.Test.main(Test.java:9)
We can throw the required exception according to the actual situation. We can specify some descriptive information when constructing the exception object
Exception description
When dealing with exceptions, we usually want to know what possible exceptions will appear in this code.
We can use the throws keyword to explicitly mark the possible exceptions in the position of the method definition, so as to remind the caller to pay attention to catching these exceptions.
public static int divide(int x, int y) throws ArithmeticException { if (y == 0) { throw new ArithmeticException("Throw exception except 0"); } return x / y; }
3. Java exception system
Java has built-in rich exception system to represent exceptions in different situations.
The following figure shows the inheritance relationship between Java built-in exception classes:
- Error refers to the Java runtime internal error and resource exhaustion error. The application does not throw such exceptions. Once this internal error occurs, it is powerless except to inform the user and terminate the program. This rarely occurs.
- Exception is the parent of the exception class.
- Exception has a subclass called RuntimeException, which derives many common exception classes
NullPointerException IndexOutOfBoundsException, etc .
Non checked exceptions: the Java language specification refers to all exceptions derived from the Error class or RuntimeException class as non checked exceptions.
Checked exceptions: all other exceptions are called checked exceptions.
If a piece of code may throw a checked exception, it must be handled explicitly (the program must display try..catch or throw it up):
public static void main(String[] args) { System.out.println(readFile()); } public static String readFile() { // Try opening the file and reading one line File file = new File("d:/test.txt"); // Use file objects to construct Scanner objects Scanner sc = new Scanner(file); return sc.nextLine(); } // Compilation error Error:(13, 22) java: Unreported exception error java.io.FileNotFoundException; It must be captured or declared in order to be thrown
Looking at the Scanner's construction method, we can find that there are exceptions such as FileNotFoundException. Description:
public Scanner(File source) throws FileNotFoundException { ... }
Exceptions such as FileNotFoundException are checked exceptions. If they are not explicitly handled, the compilation cannot pass
There are two ways of explicit processing:
- Wrap it with try catch
- Adding an exception description to the method is equivalent to handing over the processing action to the superior caller
4. Custom exception class
Although there are many built-in exception classes in Java, there may be some situations in our actual scene that require us to extend the exception class and create exceptions that meet our actual situation
For example, we implement a user login function:
public class Test { private static String userName = "admin"; private static String password = "123456"; public static void main(String[] args) { login("admin", "123456"); } public static void login(String userName, String password) { if (!Test.userName.equals(userName)) { // TODO processing user name error } if (!Test.password.equals(password)) { // TODO processing password error } System.out.println("Login successful"); } }
At this time, we may need to throw two kinds of exceptions when dealing with user name and password errors. We can extend (inherit) based on the existing exception classes and create exception classes related to our business
class UserError extends Exception { public UserError(String message) { super(message); } } class PasswordError extends Exception { public PasswordError(String message) { super(message); } }
At this point, our login code can be changed to:
public static void main(String[] args) { try { login("admin", "123456"); } catch (UserError userError) { userError.printStackTrace(); } catch (PasswordError passwordError) { passwordError.printStackTrace(); } } public static void login(String userName, String password) throws UserError,PasswordError { if (!Test.userName.equals(userName)) { throw new UserError("User name error"); } if (!Test.password.equals(password)) { throw new PasswordError("Password error"); } System.out.println("Login successful"); }
be careful:
- Custom exceptions usually inherit from Exception or RuntimeException
- Exceptions inherited from Exception are checked exceptions by default
- Exceptions inherited from RuntimeException are non checked exceptions by default