非常详细! 记录java中的异常和日志处理.

非常详细! 记录java中的异常和日志处理._第1张图片

暑假充电计划开启中-------------------

异常/日志:

  • 异常:
    • java中常见的异常:
    • 简单捕获异常:
    • 多个catch语句捕获异常:
    • finally 语句,一定会执行的语句:
    • 抛出异常:
    • 关于NullPointerException的处理:
  • 断言:
  • 日志:
    • JDK Logging:
    • Commons Logging:

异常:

java中常见的异常:

​ ———— 错误 ——————-

  • OutOfMemoryError:内存耗尽

  • NoClassDefFoundError:无法加载某个Class

  • StackOverflowError:栈溢出


常见异常图表

Exception
│
├─ RuntimeException
│  │
│  ├─ NullPointerException   对某个`null`的对象调用方法或字段
│  │
│  ├─ IndexOutOfBoundsException   数组索引越界
│  │
│  ├─ SecurityException
│  │
│  └─ IllegalArgumentException   参数检查不合法
│     │
│     └─ NumberFormatException  数值类型的格式错误
│
├─ IOException
│  │
│  ├─ UnsupportedCharsetException
│  │
│  ├─ FileNotFoundException   未找到文件
│  │
│  └─ SocketException   读取网络失败
│
├─ ParseException
│
├─ GeneralSecurityException
│
├─ SQLException
│
└─ TimeoutException

Java规定:

  • 必须捕获的异常,包括Exception及其子类,但不包括RuntimeException及其子类,这种类型的异常称为Checked Exception。
  • 不需要捕获的异常,包括Error及其子类,RuntimeException及其子类。

简单捕获异常:

使用 try ... catch ... 进行捕获

public class error {
    public static void main(String[] args) {
        byte[] bs = toGBK("中文");
        System.out.println(Arrays.toString(bs));

    }
    static byte[] toGBK(String s) {
        try {
            return s.getBytes("GB");
        } catch (UnsupportedEncodingException e) {
            // 如果系统不支持GBK编码,会捕获到 UnsupportedEncodingException:
            // 异常的寻找 查看 getBytes 源码, 看看会抛出什么异常, 就知道这里接受什么异常
            // 实在不是很清楚异常是什么, 直接用 Exception 接受, 这也是最后办法。
            System.out.println(e); 
            e.printStackTrace();  // 打印异常栈
            return s.getBytes();  // 返回默认编码
        }
    }
}

在Java中,凡是可能抛出异常的语句,都可以用try ... catch捕获。把可能发生异常的语句放在try { ... }中,然后使用catch捕获对应的Exception及其子类。


多个catch语句捕获异常:

可以使用多个catch语句,每个catch分别捕获对应的Exception及其子类。捕获到异常后,会从上到下匹配catch语句,匹配到某个catch后,执行catch代码块,然后不再继续匹配。

简单地说就是:多个catch语句只有一个能被执行

  • 这里注意一点, 多个catch语气的时候, 顺序很重要, 异常的子类必须写在前面,否则异常捕获不到。
  • 例如:
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");
    }
}
// UnsupportedEncodingException 是 IOException 异常的子类 , 所以需要放在前面

这里需要考虑一点, 如果异常不是子类的关系,那我们在编写多个catch 语句的时候, 如果下方代码是一样的, 就可以用 | 把这二个语句合并起来,就像这样 catch (IOException | NumberFormatException e) ,就可以少编写一些相同的代码, 避免造成冗余。


finally 语句,一定会执行的语句:

  • finally 语句 – -- – -- 不管有没有产生异常,或者异常有没有被捕获, 规定finally 下的语句一定会被执行. 例如:
public static void main(String[] args) {
    try {
        System.out.println("捕获异常")
    } catch (UnsupportedEncodingException e) {
        System.out.println("Bad encoding");
    } catch (IOException e) {
        System.out.println("IO error");
    }finally{
        System.out.println("我一定会被执行的!")
    }
}

注意几点:

  1. finally语句不是必须的,可写可不写;
  2. finally总是最后执行。
  3. finally 总是确保一些语句一定会被执行

抛出异常:

  • 简单的抛出异常:

throw Exception e — (Exception 代表异常类型)

  • 异常的多级传播,以及如何正确的抛出并且抓住:
public class throwError {
    public static void main(String[] args){
        try {
            fun1();
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    static void fun1(){
        try {
            fun2();
        }catch (NullPointerException e){
            throw new IllegalStateException(e);
        }
    }
    static void fun2(){
        throw new NullPointerException();
    }
}
// 这样模拟了,异常是如何转换的, 我们在fun1中调入函数fun2抛出了一个异常, 然后又fun1, 去接受并且转换这个异常类型,
// 但这里要注意点, 在fun1 中, 如果不把这个原始异常向上抛出的话, 那么打印异常栈 就可能会出错, 就找不到错误的最终原因。

捕获到异常并再次抛出时,**一定要留住原始异常 ! **

异常栈 是最后打印的, 如果有finally 也是先打印 finally 之后,在打印异常栈。


关于NullPointerException的处理:

  • 如果我们操作的对象中,存在空值, 那就会抛出这个异常, 他是异常中很常见的, 也是我们最要去避免的。
  • 在java中, 尤其要谨慎使用 Null 值, 能用 空字符串 或者空数组返回最好,尽量不要用 null 值 来返回参数.

如果产生了如何去捕获这个异常

// 比如我们在这个反面代码中, 我们定义了 a  b 空值。 这一定会报错。 
public class throwError {
 public static void main(String[] args) {
     ss  a = new ss();
     System.out.println(a.b.toUpperCase());

 }

}
class ss{
 String a;
 String b;
}

return    Exception in thread "main" java.lang.NullPointerException
      at random.throwError.main(throwError.java:6)
 
// 这个异常栈无法判断到底是谁产生了空值。 在JDK14中, 我们可以开启一个新的功能,就能捕获这种异常: 如下:
 
return   Exception in thread "main" java.lang.NullPointerException:          Cannot invoke "String.toUpperCase()" because "a.b" is null
     at random.throwError.main(throwError.java:6)

那再IDEA中,如何向JDK添加参数呢? 这个方法我也是询问别人才知道的, 哎。

第一步:

非常详细! 记录java中的异常和日志处理._第2张图片

第二步:

非常详细! 记录java中的异常和日志处理._第3张图片

参数: -XX:+ShowCodeDetailsInExceptionMessages


断言:

断言(Assertion)是一种调试程序的方式。在Java中,使用assert关键字来实现断言。

呃呃, 基本没啥用处, 懒得写笔记了, 最气人的还是这个功能现在默认都是关闭的, 代码运行到assert 就会直接忽略掉。


日志:

日志用来记录程序中出现的各种错误, 一般在容易出问题的代码下面加上日志语句,java中关于日志的类很多, 我总结一下。

好处:

  1. 可以设置输出样式,避免自己每次都写"ERROR: " + var
  2. 可以设置输出级别,禁止某些级别输出。例如,只输出错误日志;
  3. 可以被重定向到文件,这样可以在程序运行结束后查看日志;
  4. 可以按包名控制日志级别,只输出某些包打的日志;

JDK Logging:

public class Hello {
    public static void main(String[] args) {
        Logger logger = Logger.getGlobal();
        System.out.println("The main is starting!")
        logger.info("start process...");
     //   logger.warning("warning ");
     //   logger.fine("ignored.");
     //   logger.severe("severe...");
    }
}

return  --->   The main is starting!
           信息:  start process 

JDK的 Logging定义了7个日志级别,从严重到普通:

  • SEVERE
  • WARNING
  • INFO
  • CONFIG
  • FINE
  • FINER
  • FINEST

默认级别是INFO,因此,INFO级别以下的日志,不会被打印出来。使用日志级别的好处在于,调整级别,就可以屏蔽掉很多调试相关的日志输出, 但是这个Loggging是由局限性的,反正不是很好用, 这里介绍一下,作为一个了解就行了,使用其他方法更好!


Commons Logging:

Commons Logging是一个第三方日志库,它是由Apache创建的日志模块。

Commons Logging的特色是,它可以挂接不同的日志系统,并通过配置文件指定挂接的日志系统。默认情况下,Commons Loggin自动搜索并使用Log4j(Log4j是另一个流行的日志系统),如果没有找到Log4j,再使用JDK Logging.

这个库需要安装 !

Commons Logging定义了6个日志级别:

  • FATAL
  • ERROR
  • WARNING
  • INFO
  • DEBUG
  • TRACE

引用方法:

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

// 实例方法引用
public class Person {
    protected final Log log = LogFactory.getLog(getClass());
    // 实例方法使用getClass()  继承的子类可以直接使用该log, 直接就能是用log的方式
    void fun() {
        log.info("The error tell me !");
    }
}

// 静态方法引用
class Animal{
	 static final Log logs = LogFactory.getlog(Animal.Class);
    // 静态方式只能使用 类 . Class 的方式去调用类名
    
   static void fun(){
       logs.info("The error not tell me!")
   }
}

Commons Logging是使用最广泛的日志模块;
Commons Logging的API非常简单;
Commons Logging可以自动检测并使用其他日志模块。

你可能感兴趣的:(java学习,java)