JAVA04-exception handling

Exceptions are some errors in the program, but not all errors are abnormal, and errors can sometimes be avoided.
For example, if your code is missing a semicolon, then the result is that the error is java.lang.Error; if you use System.out.println (11/0), then you are dividing by 0 , An exception of java.lang.ArithmeticException will be thrown.
There are many reasons for anomalies, which usually include the following categories:

  • The user entered illegal data.
  • The file to be opened does not exist.
  • The connection was interrupted during network communication, or the JVM memory overflowed.

Some of these exceptions are caused by user errors, some are caused by program errors, and others are caused by physical errors. -
To understand Java exception handling is how it works, we need to grasp the following three types of exceptions:

  • Checkable anomalies: The most representative checkable anomalies are those caused by user errors or problems, which are unforeseeable by programmers. For example, when you want to open a file that does not exist, an exception occurs. These exceptions cannot be simply ignored during compilation.
  • Run-time exceptions: Run-time exceptions are exceptions that may be avoided by programmers. In contrast to checked exceptions, runtime exceptions can be ignored at compile time.
  • Errors: Errors are not exceptions, but problems that are out of programmer control. Errors are usually ignored in the code. For example, when the stack overflows, an error occurs and they are not detected during compilation.

Java exception

Java has a built-in exception handling mechanism that always uses exceptions to indicate errors.
Insert picture description here
It can be seen from the inheritance relationship: Throwable is the root of the abnormal system, which inherits from Object. Throwable has two systems: Error and Exception. Error represents a serious error, and the program is generally helpless, for example:

  • OutOfMemoryError: Out of memory
  • NoClassDefFoundError: Unable to load a Class
  • StackOverflowError: Stack overflow
    and Exception is a runtime error, it can be caught and handled.
    Some exceptions are part of the logical processing of the application and should be caught and handled. E.g:
  • NumberFormatException: Format error of numeric type
  • FileNotFoundException: File not found
  • SocketException: Failed to read the network

Some exceptions are caused by incorrect programming of the program logic, and the program itself should be repaired. E.g:

  • NullPointerException: Call a method or field on a null object
  • IndexOutOfBoundsException: array index out of bounds

Exception is divided into two categories: 1. RuntimeException
and its subclasses;
2. Non-RuntimeException (including IOException, ReflectiveOperationException, etc.)

Java stipulates:
Exceptions that must be caught include Exception and its subclasses, but not RuntimeException and its subclasses. This type of exception is called Checked Exception.
Exceptions that do not need to be caught include Error and its subclasses, RuntimeException and its subclasses.

The following table lists Java's unchecked exceptions.
Insert picture description here
The following table lists Java's checked exception classes defined in the java.lang package.
Insert picture description here
The following list is the main methods of the Throwable class:
Insert picture description here

Catch exception

To catch exceptions, use the try ... catch statement, put the code where the exception may occur in try {...}, and then use catch to catch the corresponding Exception and its subclasses:

// try...catch
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
public class Main {
    public static void main(String[] args) {
        byte[] bs = toGBK("中文");
        System.out.println(Arrays.toString(bs));
    }

    static byte[] toGBK(String s) {
        try {
            // 用指定编码转换String为byte[]:
            return s.getBytes("GBK");
        } catch (UnsupportedEncodingException e) {
            // 如果系统不支持GBK编码,会捕获到UnsupportedEncodingException:
            System.out.println(e); // 打印异常信息
            return s.getBytes(); // 尝试使用用默认编码
        }
    }
}

The following example declares an array with two elements. When the code tries to access the third element of the array, an exception is thrown.

// 文件名 : ExcepTest.java
import java.io.*;
public class ExcepTest{
 
   public static void main(String args[]){
      try{
         int a[] = new int[2];
         System.out.println("Access element three :" + a[3]);
      }catch(ArrayIndexOutOfBoundsException e){
         System.out.println("Exception thrown  :" + e);
      }
      System.out.println("Out of the block");
   }
}

A case where a try code block is followed by multiple catch code blocks is called multiple capture.
The syntax of the multiple capture block is as follows:

try{
   // 程序代码
}catch(异常类型1 异常的变量名1){
  // 程序代码
}catch(异常类型2 异常的变量名2){
  // 程序代码
}catch(异常类型2 异常的变量名2){
  // 程序代码
}

finally statement

Java's try ... catch mechanism also provides finally statements, and finally statement blocks are guaranteed to be executed with or without errors.

public static void main(String[] args) {
    try {
        process1();
        process2();
        process3();
    } catch (UnsupportedEncodingException e) {
        System.out.println("Bad encoding");
    } catch (IOException e) {
        System.out.println("IO error");
    } finally {
        System.out.println("END");
    }
}

Note that finally has several characteristics:
1. The finally statement is not necessary and can be written or not written;
2. finally is always executed last.
If no exception occurs, execute the try {…} statement block normally, then execute finally. If an exception occurs, the execution of the try {…} statement block is interrupted, then the execution of the matching catch statement block is skipped, and finally the final execution is executed.
It can be seen that finally is used to ensure that some code must be executed.
In some cases, there is no catch, only try ... finally structure. E.g

void process(String file) throws IOException {
    try {
        ...
    } finally {
        System.out.println("END");
    }
}

Use assertions

Assertion is a way to debug a program. In Java, use the assert keyword to implement assertions.

public static void main(String[] args) {
    double x = Math.abs(-123.45);
    assert x >= 0;
    System.out.println(x);
}

The statement assert x> = 0; is an assertion, and the assertion condition x> = 0 is expected to be true. If the calculation result is false, the assertion fails and AssertionError is thrown.
The characteristics of Java assertions are: AssertionError will be thrown when the assertion fails, causing the program to exit. Therefore, assertions cannot be used for recoverable program errors, and should only be used for development and testing.

JDK Logging

The Java standard library has a built-in logging package java.util.logging, which can be used directly. First look at a simple example:

// logging
import java.util.logging.Level;
import java.util.logging.Logger;
public class Hello {
    public static void main(String[] args) {
        Logger logger = Logger.getGlobal();
        logger.info("start process...");
        logger.warning("memory is running out...");
        logger.fine("ignored.");
        logger.severe("process will be terminated...");
    }
}
运行上述代码,得到类似如下的输出:
Mar 02, 2019 6:32:13 PM Hello main
INFO: start process...
Mar 02, 2019 6:32:13 PM Hello main
WARNING: memory is running out...
Mar 02, 2019 6:32:13 PM Hello main
SEVERE: process will be terminated...

JDK's Logging defines 7 log levels, from severe to normal:

  • SEVERE
  • WARNING
  • INFO
  • CONFIG
  • FINE
  • FINER
  • FINEST
    because the default level is INFO, so logs below the INFO level will not be printed. The advantage of using the log level is that by adjusting the level, you can mask out many debug-related log outputs.
    The use of the built-in Logging in the Java standard library has the following limitations: The
    Logging system reads the configuration file and completes the initialization when the JVM starts. Once the main () method is started, the configuration cannot be modified; the
    configuration is not convenient, and the parameters need to be passed when the JVM starts
-Djava.util.logging.config.file=<config-file-name>

Therefore, the Logging built into the Java standard library is not very widely used.

Commons Logging

Commons Logging is a third-party logging library, which is a logging module created by Apache.
The feature of Commons Logging is that it can be connected to different logging systems, and the logging system can be specified through the configuration file. By default, Commons Loggin automatically searches for and uses Log4j (Log4j is another popular logging system). If Log4j is not found, then JDK Logging is used.
Because Commons Logging is a library provided by a third party, it must be downloaded first. After downloading, unzip it, find the file commons-logging-1.2.jar, and put the Java source code Main.java in a directory.
The compilation command is as follows:

javac -cp commons-logging-1.2.jar Main.java

To execute this Main.class, use the java command, you must also specify the classpath, the command is as follows:

java -cp .;commons-logging-1.2.jar Main

To use Commons Logging, you only need to deal with two classes, and there are only two steps: the
first step is to obtain the Log class instance through LogFactory; the second step is to use the Log instance method to log.

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class Main {
    public static void main(String[] args) {
        Log log = LogFactory.getLog(Main.class);
        log.info("start...");
        log.warn("end.");
    }
}

Mar 02, 2019 7:15:31 PM Main main
INFO: start...
Mar 02, 2019 7:15:31 PM Main main
WARNING: end.

Commons Logging defines 6 log levels:

  • FATAL
  • ERROR
  • WARNING
  • INFO
  • DEBUG
  • The
    default level of TRACE is INFO.

Log4j

Log4j is a very popular logging framework, the latest version is 2.x.
Log4j is a component-designed log system. Its architecture is roughly as follows:

When using Log4j to output a log, Log4j automatically outputs the same log to different destinations through different Appenders. E.g:

  • console: output to the screen;
  • file: output to file;
  • socket: output to a remote computer through the network;
  • jdbc: Output to the database.
    In the process of outputting logs, Filter is used to filter which logs need to be output and which logs do not need to be output. For example, only logs of ERROR level are output.
    Finally, format the log information through Layout, for example, automatically add the date, time, method name and other information.
    Although the above structure is complicated, when we actually use it, we don't need to care about the Log4j API, but configure it through the configuration file.
    Taking XML configuration as an example, when using Log4j, we put a log4j2.xml file in the classpath to allow Log4j to read the configuration file and output the log according to our configuration. The following is an example of a configuration file:
<?xml version="1.0" encoding="UTF-8"?><Configuration>
	<Properties>
        <!-- 定义日志格式 -->
		<Property name="log.pattern">%d{MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36}%n%msg%n%n</Property>
        <!-- 定义文件名变量 -->
		<Property name="file.err.filename">log/err.log</Property>
		<Property name="file.err.pattern">log/err.%i.log.gz</Property>
	</Properties>
    <!-- 定义Appender,即目的地 -->
	<Appenders>
        <!-- 定义输出到屏幕 -->
		<Console name="console" target="SYSTEM_OUT">
            <!-- 日志格式引用上面定义的log.pattern -->
			<PatternLayout pattern="${log.pattern}" />
		</Console>
        <!-- 定义输出到文件,文件名引用上面定义的file.err.filename -->
		<RollingFile name="err" bufferedIO="true" fileName="${file.err.filename}" filePattern="${file.err.pattern}">
			<PatternLayout pattern="${log.pattern}" />
			<Policies>
                <!-- 根据文件大小自动切割日志 -->
				<SizeBasedTriggeringPolicy size="1 MB" />
			</Policies>
            <!-- 保留最近10-->
			<DefaultRolloverStrategy max="10" />
		</RollingFile>
	</Appenders>
	<Loggers>
		<Root level="info">
            <!-- 对info级别的日志,输出到console -->
			<AppenderRef ref="console" level="info" />
            <!-- 对error级别的日志,输出到err,即上面定义的RollingFile -->
			<AppenderRef ref="err" level="error" />
		</Root>
	</Loggers></Configuration>

Although configuring Log4j is cumbersome, once it is configured, it is very convenient to use. For the above configuration file, all INFO level logs will be automatically output to the screen, and ERROR level logs will be output to the screen, as well as to the file. And, once the log file reaches the specified size (1MB), Log4j will automatically cut the new log file, and retain up to 10 copies.

It is not enough to have a configuration file, because Log4j is also a third-party library, you need to download Log4j, unzip it, and put the following 3 jar packages into the classpath:

  • log4j-api-2.x.jar
  • log4j-core-2.x.jar
  • log4j-jcl-2.x.jar
    Because Commons Logging will automatically discover and use Log4j, so put the commons-logging-1.2.jar downloaded in the previous section into the classpath.
    To print the log, just write it according to Commons Logging, without changing any code, you can get the log output of Log4j, similar to:
03-03 12:09:45.880 [main] INFO  com.itranswarp.learnjava.MainStart process...
Published 23 original articles · praised 7 · 1002 views

Guess you like

Origin blog.csdn.net/qq_34356768/article/details/105082089