java学习-异常机制

Posted 懒佯佯大哥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java学习-异常机制相关的知识,希望对你有一定的参考价值。

异常

  • 什么是异常:

    • 程序运行过程中出现的错误
  • 异常总览:

  • Throwable:

    • java语言中所有异常或错误的超类
    • 两个子类:
      • Error:错误类:是指在程序中了严重问题,不改代码,运行不了
      • Exception:异常类:程序一般问题,可以通过处理规避掉
  • 常见的Exception:

    • NullPointerException:空指针异常
    • IndexOutOfBoundsException:越界异常
    • ClassCastException:类型转换错误
    • RuntimeException:运行期错误
    • ConcurrentModificationException:并发修改异常
  • 常见的Error:

    • OutOfMemoryError:内存超限:比如:int[] a = new int[1000000000];

Throwable详解:

  • java语言中所有异常或错误的超类
  • 所有继承自Throwable的子类(java自带),都默认使用Throwable的方法(子类基本不实现)
  • 其包括如下方法:
方法描述
public Throwable()默认构造函数
public Throwable(String message)指定消息构造函数,后面该message,可通过getMessage获取
public Throwable(String message,Throwable cause)可以由message+旧的Throwable对象,构造新的Throwable
public Throwable(Throwable cause)由老的构造,生成新的Throwable
public String getMessage()获取message(简易的)
public String getLocalizedMessage()创建本地化描述,如果不做任何子类实现,其等于getMessage
public Throwable getCause()返回cause
public Throwable initCause(Throwable cause)初始化cause,只能初始化一次
public String toString()详细描述(jdk文档说是简单描述)
public void printStackTrace()将throwable及其追踪输出至标准输出流
public void printStackTrace(PrintStream s)将此 throwable 及其追踪输出到指定的输出流。
public void printStackTrace(PrintWriter s)将此 throwable 及其追踪输出到指定的 PrintWriter。

JVM对异常的处理:

  • 示例,比如除0异常:
public class Test4 
    public static void main(String[] args) 
        int a = 1 / 0;
    

  • 输出:
// 异常的类,以及原因
Exception in thread "main" java.lang.ArithmeticException: / by zero
//出现异常的位置(行)
    at Test3.testZero(Test3.java:27)  
  • 说明:
    • 异常也是对象(万物皆对象),JVM发现发生了“除法的除0异常”,将异常封装为java.lang.ArithmeticException:new ArithmeticException(“/ by zero")
    • 异常向外抛出,抛到main方法的调用者,即:JVM,此时JVM停止程序,并将异常打印到控制台

异常的详细程度:

  • e.printStackTrace() > e.toString() > e.getMessage()
public class Test4 
    public static void main(String[] args) 
        try 
            div(1, 0);
         catch (Exception e) 
            System.out.println("==================== e.getMessage:简要 ====================");
            System.out.println(e.getMessage());
            System.out.println("==================== e.toString:较详细 ====================");
            System.out.println(e.toString());
            System.out.println("==================== e.getMessage:非常详细 ====================");
            e.printStackTrace();
        
    

    private static int div(int a, int b)
        return a / b;
    

  • 输出:
==================== e.getMessage:简要 ====================
/ by zero
==================== e.toString:较详细 ====================
java.lang.ArithmeticException: / by zero
==================== e.getMessage:非常详细 ====================
java.lang.ArithmeticException: / by zero
    at Test4.div(Test4.java:16)
    at Test4.main(Test4.java:4)

异常的继承:

  • 一般继承如下:并且,基本都使用RuntimeException
/**
 * 一般继承时,都覆写空构造器、以及带有message的构造器
 */
class YRuntimeException extends RuntimeException 
    public YRuntimeException() 
        super();
    

    public YRuntimeException(String message) 
        super(message);
    



异常的捕获:

  • 多个异常:
private void testExp() 
    // 方式1:
    try 
        method();
     catch (NullPointerException | ArithmeticException e) 
        System.out.println(e.toString());
    
    // 方式2:
    try 
        method();
     catch (ArithmeticException e) 
        System.out.println(e.toString());
     catch (NullPointerException e) 
        System.out.println(e.toString());
    

  • 如果多个异常,并且这些异常有父子关系,则父类需要写到最后,否则编译失败
class ExceptionParent extends Exception 


class ExceptionSon extends  ExceptionParent 


class TestException 
    public static void main(String[] args) 
        try 
            throw new ExceptionParent();
         catch (ExceptionParent e) 
            // 这样写,编译器会报错,因为parent异常已经可以捕获了
         catch (ExceptionSon e) 

        
    


Error的捕获

  • 因为Error的Exception是两个不同的实现类,故捕获的方式不一样:
class TestY 
    public static void main(String[] args) 
        try 
            int[] a = new int[1000000000];
            // 这里会报OutOfMemoryError,只能用Error或者Throwable捕获
         catch (Error e) 
            System.out.println("捕获到异常了");
            System.out.println(e.toString());
        
    


异常抛出:

  • throw:方法内部,手动抛出异常
  • throws:方法上,声明本方法抛出的异常类型,调用此方法的必须进行处理
  • 运行时异常:RuntimeException或者其子类:
    • 特点:运行时异常,方法上不需要throws声明,调用者也不需要处理
class XException extends Exception 

class YRuntimeException extends RuntimeException 


class TestE 
    // 只需要抛出XEception即可,RuntimeException及其子类不需要抛出
    public void show(int a) throws XException
        if (a == 0) 
            throw new XException();
         else 
            throw new YRuntimeException();
        
    


finally

  • finally中代码快一定会执行,格式:
    • try catch finally
    • try finally
  • 正常场景:try catch finally都有返回
class TestFinally1 
    public static void main(String[] args) 
        System.out.println(show());  // 输出为3
    

    private static int show() 
        try 
            return 1;
         catch (Exception e) 
            return 2;
         finally 
            return 3;   // finally最终返回的是3
        
    

* 过程分析:执行到return 1;时,jvm先预留,不直接返回。等到finlly执行完成后,再返回。此时发现finally里有返回,则按照finally返回,故输出为3.
  • 正常场景:finally无返回:
class TestFinally1 
    public static void main(String[] args) 
        System.out.println(show1());   // 返回为1
    

    private static int show1() 
        try 
            return 1;              // 最后返回这里
         catch (Exception e) 
            return 2;
         finally 
            System.out.println("no return);   // 首先,会打印这里
        
    

输出:

no return
1
  • 异常场景:无finally,最终按照catch中返回
private static int showException() 
    try 
        int a = 1 / 0;
        return 1;
     catch (Exception e) 
        return 2;              // 最终方法返回的是这里
     

  • 异常场景:有finally:则按照finally中返回
private static int showException() 
    try 
        int a = 1 / 0;
        return 1;
     catch (Exception e) 
        return 2;
     finally 
        return 3;           // 最终返回的是这里:3
    

注意:这里逻辑比较绕,但最好不要在finally中写return

继承关系中方法的异常处理:

  • 父类方法没有异常,则子类继承的方法也不能有:
class A 
    public void show() 
    


class B extends A 
    // 正确写法:
    @Override
    public void show() 
    
    // 错误写法:
//    @Override
//    public void show() throws ExceptionSon
//    

  • 父类方法有异常,则子类:
    • 可以不写
    • 或者声明为该异常的子类(异常的父类会报错)
class AException extends Exception 


class BException extends AException 


class A 
    public void show() throws AException
    


class B extends A 
    // 正确写法1:不抛异常
//    @Override
//    public void show() 
//    
    // 正确写法2:抛出为父类异常的子类
    @Override
    public void show() throws BException
    
    // 错误写法:抛出的异常比父类要高
//    @Override
//    public void show() throws Exception
//    


以上是关于java学习-异常机制的主要内容,如果未能解决你的问题,请参考以下文章

java中的异常 try catch

java异常处理的机制 java 架构师学习 java北京

[学习笔记]Java异常机制

java学习笔记—— 异常机制

java学习笔记—— 异常机制

JAVA学习笔记-异常机制