Deep Exploration of Exceptions and Error Handling in Java

Posted by jonsjava on Tue, 02 Jul 2019 18:21:46 +0200

The exception handling mechanism in Java is mature, and our Java programs are full of exceptions. If these exceptions are not handled in advance, there will be no debugging for future program crashes and it is difficult to find the location of exceptions.This article will discuss how exceptions and errors are handled in Java, so let's take a look.

Exceptions and errors:

Exception:

Program errors in Java are mainly syntax and semantics errors. A program error that occurs during compilation and run is collectively referred to as an exception. It is a way for VM to notify you that you have made a mistake and now you have a chance to modify itIt.Java uses exception classes to represent exceptions, and different exception classes represent different exceptions.But all exceptions in Java have a base class called Exception.

Error:

It refers to a serious problem that a reasonable application cannot intercept.Most of them are abnormal.An error is a failure of the VM (although it can be any system-level service).So errors are hard to handle, and the average developer (not you, of course) can't handle them, such as memory overflow.As with exceptions, errors are represented by error classes in Java, and different error classes represent different errors.But all errors in Java have a base class called Error.

In summary, we can see that the essential difference between exceptions and errors is that when exceptions can be handled by developers and errors are made by the system itself, they are generally not handled or need not be handled by our programmers.

1. An exception is an event that occurs during the execution of a program and interrupts the operation of normal instructions.

2. Error, an action or instance that deviates from acceptable code behavior

Structural classification of anomalies:

1. Runtime exceptions (no exceptions checked)

2. Compile-time exceptions (exceptions checked)

RuntimeException is the runtimeException; all others are compiled exceptions

Exception s and Error s have a common parent Throwable in Java.

Error Exception

Several subclasses of runtimeException

1, java.lang.ArrayIndexOutOfBoundsException

Array index out of bounds exception.Thrown when the index value on an array is negative or greater than or equal to the size of the array.

2,java.lang.ArithmeticException

Arithmetic condition is abnormal.For example: integer divided by zero, etc.

3,java.lang.NullPointerException

Null pointer exception.The exception is thrown when the application attempts to use null where an object is required.For example, calling instance methods of null objects, accessing null objects

Properties, calculating the length of a null object, throwing nulls with a throw statement, and so on

4,java.lang.ClassNotFoundException

No class exceptions were found.Thrown when the application attempts to construct a class based on a string of class names and cannot find a class file with the corresponding name after traversing CLASSPAH

The exception.

Handling exceptions:

try{}catch{}

try{}catch{}finally{} executes with or without an exception finally block

try{}finally{} can also be combined, but catch{}finally{} cannot

Note: In an inheritance relationship, a child class overrides the parent class's method and cannot throw an exception more broadly than the parent class

Use of Exceptions

This part of the use of exceptions is mainly a demonstration code, which we usually encounter in the process of writing code (of course, only a small part). Do you want to start with something?

Example 1. This example mainly demonstrates the code execution process after an exception has occurred by comparing two methods.

public static void testException1() {
     int[] ints = new int[] { 1, 2, 3, 4 };
     System.out.println("Before the exception");
     try {
          System.out.println(ints[4]);
          System.out.println("Am I lucky to do it?");// After an exception occurs, subsequent code cannot be executed
     } catch (IndexOutOfBoundsException e) {
          System.out.println("Array out of bounds error");
     }
     System.out.println("After the exception");
}

/*output:

Before the exception

Array out of bounds error

After frequent occurrence

*/

public static void testException2() {
     int[] ints = new int[] { 1, 2, 3, 4 };
     System.out.println("Before the exception");
     System.out.println(ints[4]);
     System.out.println("Am I lucky to do it?");// After the exception, the code behind him could not be executed
}

First, point out the shortcomings in the example. IndexOutofBoundsException is a non-checked exception, so try is not needed...catch...Show capture, but my goal is to treat the same exception differently and see what happens to it (and that's all I can do here).When an exception occurs, the first method simply jumps out of the try block, but the code behind it executes as it does.However, the second one is not the same and jumps out of the way directly, which is harder.As we can see from the first method, try...catch...It is a "transactional" guarantee that the program runs in exceptional circumstances and informs the programmer of the details of the error in the program, which sometimes depends on the programmer's design.

Example 2. Rethrow the exception

public class Rethrow {
     public static void readFile(String file) throws FileNotFoundException {
     try {
          BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));
     } catch (FileNotFoundException e) {
          e.printStackTrace();
          System.err.println("Do not know how to handle the exception or do not want to handle it at all, but it is inappropriate not to handle it. This is to re-throw the exception to a higher level for processing");
          //Rethrow Exception
          throw e;
     }
}
public static void printFile(String file) {
     try {
          readFile(file);
     } catch (FileNotFoundException e) {
          e.printStackTrace();
     }
}
     public static void main(String[] args) {
          printFile("D:/file");
     }
}

The intent of the exception is good. Let's try to fix the program, but in reality we have a very small chance of fixing it. We use it most of the time to record errors.If you're tired of dealing with exceptions all the time, throwing them back might be a good relief for you.Throw the exception to the next level unchanged, to the person calling the method, and let him have a brainstorm.In this way, java exceptions (which of course refer to checked exceptions) add a lot of trouble to us, even though their starting point is good.

Example 3. Use of abnormal chains and loss of abnormalities

ExceptionA,ExceptionB,ExceptionC
public class ExceptionA extends Exception {
     public ExceptionA(String str) {
          super();
     }
}
public class ExceptionB extends ExceptionA {
     public ExceptionB(String str) {
          super(str);
     }
}
public class ExceptionC extends ExceptionA {
     public ExceptionC(String str) {
          super(str);
     }
}

Exceptional loss:

public class NeverCaught {
     static void f() throws ExceptionB{
          throw new ExceptionB("exception b");
     }
     static void g() throws ExceptionC {
          try {
               f();
          } catch (ExceptionB e) {
               ExceptionC c = new ExceptionC("exception a");
               throw c;
          }
     }
     public static void main(String[] args) {
          try {
               g();
          } catch (ExceptionC e) {
               e.printStackTrace();
          }
     }
}
/*
exception.ExceptionC
at exception.NeverCaught.g(NeverCaught.java:12)
at exception.NeverCaught.main(NeverCaught.java:19)
*/

Why did you print out ExceptionC instead of ExceptionB? Let's analyze this for yourself!

The above situation is equivalent to one less exception, which is very detrimental in our troubleshooting process.So what do we do when we encounter the above? That's where the exception chain is used: to keep the exception information and not lose the original exception while throwing another one.

public class NeverCaught {
     static void f() throws ExceptionB{
           throw new ExceptionB("exception b");
     }
     static void g() throws ExceptionC {
          try {
                f();
          } catch (ExceptionB e) {
                ExceptionC c = new ExceptionC("exception a");
                //Abnormal connection
                c.initCause(e);
                throw c;
          }
     }
     public static void main(String[] args) {
          try {
                g();
          } catch (ExceptionC e) {
                e.printStackTrace();
          }
     }
}
/*
exception.ExceptionC
at exception.NeverCaught.g(NeverCaught.java:12)
at exception.NeverCaught.main(NeverCaught.java:21)
Caused by: exception.ExceptionB
at exception.NeverCaught.f(NeverCaught.java:5)
at exception.NeverCaught.g(NeverCaught.java:10)
... 1 more
*/

This exception chain is characterized by all exceptions because the initCause() method is inherited from Throwable.

Example 4. Cleanup

Cleanup is essential for us, because if there are resource-consuming operations such as IO,JDBC.If we don't shut down properly in time after we've run out, the consequences are serious, which means memory leaks.The emergence of exceptions requires that we design a mechanism wherever resources can be cleaned up in a timely and correct manner.This is finally.

public void readFile(String file) {
     BufferedReader reader = null;
     try {
           reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
           // do some other work
     } catch (FileNotFoundException e) {
           e.printStackTrace();
     } finally {
           try {
                 reader.close();
           } catch (IOException e) {
                 e.printStackTrace();
           }
     }
}

The example is very simple, an example of reading a file.Such examples are also common in JDBC operations.(So, I think timely and correct cleanup of resources is one of the basic qualities of a programmer.)

Try...The finally structure is also a means of ensuring that resources are properly closed.If you don't know what exceptions will occur during code execution that will result in resources not being cleaned up, then wrap this "suspect" code in try and clean up the resources in finally.For example:

public void readFile() {
     BufferedReader reader = null;
     try {
           reader = new BufferedReader(new InputStreamReader(new FileInputStream("file")));
           // do some other work
           //close reader
           reader.close();
     } catch (FileNotFoundException e) {
           e.printStackTrace();
     } catch (IOException e) {
           e.printStackTrace();
     }
}

Let's note the difference between this method and the previous one. The next person may get used to it a little better and turn off the reader sooner.This is often not the case because exceptions are always possible before reader.close(), and such a code structure cannot prevent any exceptions.Because the program will jump out in the unexpected place, subsequent code cannot be executed (this should be proven by an example above).Then we can try...finally to transform:

public void readFile() {
     BufferedReader reader = null;
     try {
           try {
                 reader = new BufferedReader(new InputStreamReader(new FileInputStream("file")));
                 // do some other work
                 // close reader
           } finally {
                 reader.close();
           }
      } catch (FileNotFoundException e) {
           e.printStackTrace();
      } catch (IOException e) {
           e.printStackTrace();
      }
}

Closing resources early is a good behavior because the longer it takes, the more likely you will forget to close.So try it together...finally guarantees that nothing will go wrong (don't worry, java is such a good rule).

In another case, suppose I want to open a file in a construction method or create a JDBC connection, because we want to use this resource in other methods, we can't close it early in the construction method.Are we all right? The answer is No.Take a look at the following examples:

public class ResourceInConstructor {
     BufferedReader reader = null;
     public ResourceInConstructor() {
          try {
                reader = new BufferedReader(new InputStreamReader(new FileInputStream("")));
          } catch (FileNotFoundException e) {
                e.printStackTrace();
          }
     }
     public void readFile() {
          try {
                 while(reader.readLine()!=null) {
                      //do some work
                 }
          } catch (IOException e) {
                 e.printStackTrace();
          }
      }
      public void dispose() {
           try {
                reader.close();
           } catch (IOException e) {
                e.printStackTrace();
           }
      }
}

This section talks a little more, but the exception is really something that looks easy and difficult to use. There are still many things to dig deep in java.

Topics: Java JDBC less