7-Java异常

异常:
现实生活的病
现实生活中万物在发展和变化会出现各种各样不正常的现象。
1:例如:人的成长过程中会生病。
|——病
|——不可治愈(癌症晚期)
|——可治愈
|——小病自行解决(上火,牙痛)
|——去医院(感冒,发烧)
现实生活中的很多病况从面向对象的角度考虑也是一类事物,可以定义为类。

java中可以通过类对这一类不正常的现象进行描述,并封装为对象。
java的异常体系包含在java.lang这个包默认不需要导入。

java异常体系
|——Throwable (实现类描述java的错误和异常)
|——Error (错误)一般不通过代码去处理。
|——Exceprion (异常)
|——RuntimeException (运行时异常)
|——非运行时异常

常见的Error;

/*
  java虚拟机默认管理了64M的内存,一数组需要1G的内存,这样子就会造成内存溢出
byte[] but = new byte[1024*1024*1024]  //1K-->1M-->1G
System.out.println(buf);
*/
内存溢出,需要的内存超出了Java虚拟机管理的内存范围
找不到类文件

它指的是一个合理的应用程序不能截获的严重的问题。大多数都是反常的情况。错误是JVM的一个故障(虽然它可以是任何系统级的服务)。所以,错误是很难处理的,一般的开发人员(当然不是你)是无法处理这些错误的。比如内存溢出.

异常体系图的对应

class ExceptionDemo1{
    public static div(int a, int b){
       int c = a/b;
        System.out.printlin("----" + c);
    }
    public static void main(String args[]){
         ExceptionDemo1 demo1 = ExceptionDemo1();
          demo1.div(4,0);
    }
}
异常

异常

Throwable类
*toString() 输出该异常的类名。
getMessage() 输出异常的信息,需要通过构造方法传入异常信息(例如病态信息)。
printStackTrace() 打印栈信息。

人生病:流鼻涕,感冒,呼吸道感染,肺炎。。。最后体现的是肺炎。
医生要处理需要获知这些信息。从外到里处理。最后找病源

class Demo6 {

 public static void main(String[] args) {

   // Throwable able=newThrowable();
   Throwable able = new Throwable("想吐。。。");
   System.out.println(able.toString()); // 输出该异常的类名
   System.out.println(able.getMessage()); // 输出异常的信息
   able.printStackTrace(); // 打印栈信息
   }
}

程序中的异常处理
当除数是非0,除法运算完毕,程序继续执行。
当除数是0,程序发生异常,并且除法运算之后的代码停止运行。因为程序发生异常需要进行处理。

class Demo7 {

   public static void main(String[] args) {
   div(2, 0);
   System.out.println("over");
 }

 public static void div(int x, int y) {
        //该行代码的y值可能是0,程序会出现异常并停止
 System.out.println(x / y);
 System.out.println("除法运算");
 }
}
//ArithmeticException 

疑问: 出现异常如何处理?
自行处理
try{//可能发生异常的代码 }catch(异常类 变量名){//处理}。
案例除法运算的异常处理。
如果没有进行try catch处理,出现异常程序就停止。进行处理后,程序会继续执行。

多个异常
案例print方法,形参中增加数组。
在print方法中操作数组会发生新的异常
ArrayIndexOutOfBoundsException,NullPointerException),如何处理?
使用将可能发生异常的代码放入try语句中,添加多个catch语句即可。
可以处理多种异常,但是同时只能处理一种异常。
try中除0异常和数组角标越界同时出现,只会处理一种。

public class Demo8 {

   public static void main(String[] args) {

 System.out.println();
 int[] arr = { 1, 2 };
 arr = null;

 // print (1, 0, arr);
 print (1, 2, arr);

 System.out.println("over");
 } 

   public static void print(int x,int y, int[] arr) {

   try{
     System.out.println(arr[1]);
     System.out.println(x / y);
 } catch (ArithmeticException e) {
   e.toString();
   e.getMessage();
   e.printStackTrace();
 System.out.println("算术异常。。。");
 } catch (ArrayIndexOutOfBoundsException e) {
   e.toString();
   e.getMessage();
   e.printStackTrace();
   System.out.println("数组角标越界。。。");
 } catch (NullPointerException e) {
   e.toString();
   e.getMessage();
   e.printStackTrace();
   System.out.println("空指针异常。。。");
 }
   System.out.println("函数执行完毕");
 }
}

总结

**程序中有多个语句可能发生异常,可以都放在try语句中。并匹配对个catch语句处理。
如果异常被catch匹配上,接着执行try{}catch(){} 后的语句。没有匹配上程序停止。
try中多个异常同时出现,只会处理第一条出现异常的一句,剩余的异常不再处理。
使用多态机制处理异常。
程序中多态语句出现不同异常,出现了多个catch语句。简化处理(相当于急诊)。
使用多态,使用这些异常的父类进行接收。(父类引用接收子类对象)
**

public static void div(int x, int y, int[] arr, Father f) {
    try {

        System.out.println(arr[1]); // 数组越界
        System.out.println(x / y); // 除零
        Son s = (Son) f; // 类型转换

      } catch (Exception e) {
            
            e.toString();
            e.getMessage();
            e.printStackTrace();
            System.out.println("出错啦");

        }

        System.out.println("函数执行完毕");

    }

多个catch语句之间的执行顺序。
是进行顺序执行,从上到下。
如果多个catch 内的异常有子父类关系。
子类异常在上,父类在最下。编译通过运行没有问题
父类异常在上,子类在下,编译不通过。(因为父类可以将子类的异常处理,子类的catch处理不到)。
多个异常要按照子类和父类顺序进行catch

class Father {

}

class Son extends Father {

}
public class Demo8 {
    public static void main(String[] args) {



        System.out.println();

        int[] arr = { 1, 2 };

        arr = null;

        Father f = new Father();

        div(1, 0, arr, f);

        

        System.out.println("over");

    }



    public static void div(int x, int y, int[] arr, Father f) {



        try {

            System.out.println(arr[1]);

            System.out.println(x / y);

            Son s = (Son) f;



        } catch (ArithmeticException e) {

            e.toString();

            e.getMessage();

            e.printStackTrace();

            System.out.println("算术异常。。。");

        } catch (ArrayIndexOutOfBoundsException e) {

            e.toString();

            e.getMessage();

            e.printStackTrace();

            System.out.println("数组角标越界。。。");

        } catch (NullPointerException e) {

            e.toString();

            e.getMessage();

            e.printStackTrace();

            System.out.println("空指针异常。。。");

        } catch (Exception e) {

            e.toString();

            e.getMessage();

            e.printStackTrace();

            System.out.println("出错啦");

        }

        System.out.println("函数执行完毕");

    }

}

总结

*处理异常应该catch异常具体的子类,可以处理的更具体,不要为了简化代码使用异常的父类。
疑惑:感觉异常没有作用.

抛出处理

定义一个功能,进行除法运算例如(div(int x,int y))如果除数为0,进行处理。
功能内部不想处理,或者处理不了。就抛出使用throw new Exception("除数不能为0"); 进行抛出。抛出后需要在函数上进行声明,告知调用函数者,我有异常,你需要处理如果函数上不进行throws 声明,编译会报错。例如:未报告的异常 java.lang.Exception;必须对其进行捕捉或声明以便抛出throw new Exception("除数不能为0");

public static void div(int x, int y) throws Exception { // 声明异常,通知方法调用者。



        if (y == 0) {

    throw new Exception("除数为0"); // throw关键字后面接受的是具体的异常的对象

        }

        System.out.println(x / y);

        System.out.println("除法运算");

    }

main方法中调用除法功能
调用到了一个可能会出现异常的函数,需要进行处理。

1:如果调用者没有处理会编译失败。
如何处理声明了异常的函数。

  • try{}catch(){}
public static void main(String[] args) {



        try {

            div(2, 0);

        } catch (Exception e) {

            e.printStackTrace();

        }

        System.out.println("over");



    }



    public static void div(int x, int y) throws Exception { // 声明异常,通知方法调用者。



        if (y == 0) {

    throw new Exception("除数为0"); // throw关键字后面接受的是具体的异常的对象

        }

        System.out.println(x / y);

        System.out.println("除法运算");

    }

}

2:继续抛出throws

class Demo9 {



   public static void main(String[] args) throws Exception {

       div(2, 0);

       System.out.println("over");

   }



   public static void div(int x, int y) throws Exception { // 声明异常,通知方法调用者。

   if (y == 0) {

       throw new Exception("除数为0"); // throw关键字后面接受的是具体的异常的对象

   }



       System.out.println(x / y);

       System.out.println("除法运算");

   }

}

throw和throws的区别

相同:都是用于做异常的抛出处理的。
不同点:

//throws 处理

public static void main(String[] args) throws InterruptedException {

        Object obj = new Object();

        obj.wait();



    }

public static void main(String[] args) {



        //try catch 处理

        Object obj = new Object();

        try {

            obj.wait();

        } catch (InterruptedException e) {

            

            e.printStackTrace();

        }



    }

**使用的位置: throws 使用在函数上,throw使用在函数内
后面接受的内容的个数不同:
throws 后跟的是异常类,可以跟多个,用逗号隔开。
throw 后跟异常对象。
**

总结

  • try语句不能单独存在,可以和catch、finally组成 try...catch...finally、try...catch、try...finally三种结构。
  • catch语句可以有一个或多个,finally语句最多一个,try、catch、finally这三个关键字均不能单独使用。
  • try、catch、finally三个代码块中变量的作用域分别独立而不能相互访问。如果要在三个块中都可以访问,则需要将变量定义到这些块的外面。
  • 多个catch块时候,Java虚拟机会匹配其中一个异常类或其子类,就执行这个catch块,而不会再执行别的catch块。(子类在上,父类在下)。
  • throw语句后不允许有紧跟其他语句,因为这些没有机会执行。
  • 如果一个方法调用了另外一个声明抛出异常的方法,那么这个方法要么处理异常,要么声明抛出。

自定义异常

问题:现实中会出现新的病,就需要新的描述。
分析: java的面向对象思想将程序中出现的特有问题进行封装。
案例: 定义功能模拟凌波登录。(例如:lb(String ip))需要接收ip地址
当没有ip地址时,需要进行异常处理。

  1. 当ip地址为null是需要throw new Exception("无法获取ip");
    • 但Exception是个上层父类,这里应该抛出更具体的子类。
/*

 自定义异常  

 */

class NoIpException extends Exception {



    NoIpException() {



    }



    NoIpException(String message) {

        super(message);

    }



}



class Demo10 {



    public static void main(String[] args) throws NoIpException {



        System.out.println();

        String ip = "192.168.10.252";

        ip = null;

        try {

            Lb(ip);

        } catch (NoIpException e) {

            System.out.println("程序结束");

        }



    }






    public static void Lb(String ip) throws NoIpException {

        if (ip == null) {

            // throw new Exception("没插网线吧,小白");

            throw new NoIpException("没插网线吧,小白");

        }



        System.out.println("醒醒了,Jarret.Yang开始上课了。");

    }
  • 可以自定义异常
    自定义描述没有IP地址的异常(NoIpException)。
  1. 和sun的异常体系产生关系。继承Exception类,自定义异常类名也要规范,结尾加上Exception,便于阅读

*案例:模拟吃饭没带钱的问题
定义吃饭功能,需要钱。(例如:eat(double money))
如果钱不够是不能吃放,有异常。
自定义NoMoneyException();继承Exception 提供有参无参构造,调用父类有参构造初始化。at 方法进行判断,小于10块,throw NoMoneyException("钱不够");
eat 方法进行声明,throws NoMoneyException
如果钱不够老板要处理。调用者进行处理。try{}catch(){} 。

class NoMoneyException extends Exception {



    NoMoneyException() {



    }



    NoMoneyException(String message) {

        super(message);

    }

}



class Demo11 {



    public static void main(String[] args) {



        System.out.println();

        try {

            eat(0);

        } catch (NoMoneyException e) {

            System.out.println("跟我干活吧。");

        }

    }



    

    public static void eat(double money) throws NoMoneyException {

        if (money < 10) {

            throw new NoMoneyException("钱不够");

        }

        System.out.println("吃桂林米粉");

    }

}

运行时异常和非运行时异常

RuntimeException

RunntimeException的子类:

  • ClassCastException
    多态中,可以使用Instanceof 判断,进行规避

  • ArithmeticException
    进行if判断,如果除数为0,进行return

  • NullPointerException
    进行if判断,是否为null

  • ArrayIndexOutOfBoundsException
    使用数组length属性,避免越界

  • 这些异常时可以通过程序员的良好编程习惯进行避免的
    1:遇到运行时异常无需进行处理,直接找到出现问题的代码,进行规避。
    2:就像人上火一样牙疼一样,找到原因,自行解决即可
    3:该种异常编译器不会检查程序员是否处理该异常
    4:如果是运行时异常,那么没有必要在函数上进行声明。

案例
1:除法运算功能(div(int x,int y))
2:if判断如果除数为0,throw new ArithmeticException();
3:函数声明throws ArithmeticException
4:main方法调用div,不进行处理
5:编译通过,运行正常
6:如果除数为0,报异常,程序停止。
7:如果是运行时异常,那么没有必要在函数上进行声明。

Object类中的wait()方法,内部throw了2个异常 IllegalMonitorStateException InterruptedException

1:只声明了一个(throws) IllegalMonitorStateException是运行是异常没有声明。

class Demo12 {



    public static void main(String[] args){

        div(2, 1);

    }



    public static void div(int x, int y) {

        if (y == 0) {

            throw new ArithmeticException();  

        }

        System.out.println(x / y);

    }

}
非运行时异常(受检异常)

如果出现了非运行时异常必须进行处理throw或者try{}catch(){}处理,否则编译器报错。
1;IOException 使用要导入包import java.io.IOException;
2:ClassNotFoundException
2;例如人食物中毒,必须进行处理,要去医院进行处理。

案例
1:定义一测试方法抛出并声明ClassNotFoundException(test())
2:main方法调用test
3:编译报错

  • 未报告的异常 java.lang.ClassNotFoundException;必须对其进行捕捉或声明以便抛出
public void isFile(String path){

        try

        {

            /*

            根据文件的路径生成一个文件对象,如果根据该路径找不到相应的文件,

            则没法生成文件对象。

            */

            File file = new File(path);

            //读取文件的输入流

            FileInputStream input = new FileInputStream(file);

            //读取文件

            input.read();

        }

        catch (NullPointerException e)

        {

            System.out.println("读取默认的文件路径..");

        }

        

    }

4:Sun 的API文档中的函数上声明异常,那么该异常是非运行是异常,
调用者必须处理。
5:自定义异常一般情况下声明为非运行时异常

  • 函数的重写和异常
    • 运行时异常
      1:案例定义Father类,定义功能抛出运行是异常,例如(test() throw
      ClassCastException)
      2:定义Son类,继承Father类,定义test方法,没有声明异常
      3:使用多态创建子类对象,调用test方法
      4:执行子类方法
      • 函数发生了重写,因为是运行时异常,在父类的test方法中,可以声明throws 也可以不声明throws
class Father {

    void test() throws ClassCastException { // 运行时异常

        System.out.println("父类");

        throw new ClassCastException();

    }

}



class Son extends Father {

    void test() {

        System.out.println("子类");

    }

}

class Demo14 {



    public static void main(String[] args) {

        Father f = new Son();

        f.test();

    }

}

2:非运行时异常
1:定义父类的test2方法,抛出非运行时异常,例如抛出ClassNotFoundException

  • 1:此时父类test2方法必须声明异常,因为是非运行时异常
  • 2:Son类定义test2 方法,抛出和父类一样的异常,声明异常
  • 3:使用多态创建子类对象,调用test方法,调用test2方法,

1:声明非运行时异常的方法,在调用时需要处理,所以在main方法调用时throws
2:实现了重写,执行子类的test2方法
3:总结子类重写父类方法可以抛出和父类一样的异常,或
者不抛出异常。

//  1 子类覆盖父类方法父类方法抛出异常,子类的覆盖方法可以不抛出异常

class Father {

    void test() throws ClassNotFoundException { // 非运行时异常

        System.out.println("父类");

        throw new ClassNotFoundException();

    }

}



class Son extends Father {

    void test() {

        System.out.println("子类");

        // 父类方法有异常,子类没有。

    }

}

class Demo14 {



    public static void main(String[] args) throws ClassNotFoundException  {

        Father f = new Son();

        f.test();



    }

}

4:子类抛出并声明比父类大的异常例如子类test2方法抛出Exception
1:编译失败,无法覆盖
2:子类不能抛出父类异常的父类。
3:总结子类不能抛出比父类的异常更大的异常。

//2:子类覆盖父类方法不能比父类抛出更大异常

class Father {

    void test() throws Exception {

        // 非运行时异常

        System.out.println("父类");

        throw new Exception();

    }

}



class Son extends Father {

    void test() throws ClassNotFoundException { // 非运行时异常

        System.out.println("子类");

        throw new ClassNotFoundException();

    }

}

class Demo14 {



    public static void main(String[] args) throws Exception {

        Father f = new Son();

        f.test();



    }

}

3:总结
1:子类覆盖父类方法是,父类方法抛出异常,子类的覆盖方法可以不抛
出异常,或者抛出父类方法的异常,或者该父类方法异常的子类。
2:父类方法抛出了多个异常,子类覆盖方法时,只能抛出父类异常的子

3:父类没有抛出异常子类不可抛出异常

  • 子类发生非运行时异常,需要进行try{}catch的(){}处理,不能
    抛出。

4:子类不能比父类抛出更多的异常

finally

  • 实现方式一:
    try{ // 可能发生异常的代码 } catch( 异常类的类型 e ){ // 当发生指定异常的时候的处理代码 }catch...
    比较适合用于专门的处理异常的代码,不适合释放资源的代码。
  • 实现方式二:
    try{ } catch(){} finally{ // 释放资源的代码 }
    finally块是程序在正常情况下或异常情况下都会运行的。
    比较适合用于既要处理异常又有资源释放的代码
  • 实现方式三
    try{ }finally{ // 释放资源 }
    比较适合处理的都是运行时异常且有资源释放的代码。
    • finally:关键字主要用于释放系统资源。
    • 在处理异常的时候该语句块只能有一个。
    • 无论程序正常还是异常,都执行finally。
    • finally是否永远都执行?
      1:只有一种情况,但是如果JVM退出了System.exit(0),finally就不执行。
      2:return都不能停止finally的执行过程。

案例使用流

  • 使用FileInputStream加载文件。
    导包import java.io.FileInputStream;
  • FileNotFoundException
    导入包import java.io.FileNotFoundException;
  • IOException
    import java.io.IOException;
public class FinallyDemo {

    // 本例子使用finally 关闭系统资源。

    public static void main(String[] args) {



        FileInputStream fin = null;

        try {

            System.out.println("1创建io流可能出现异常");

            fin = new FileInputStream("aabc.txt"); // 加载硬盘的文本文件到内存,通过流

            // System.out.println(fin);

        } catch (FileNotFoundException e) {

            System.out.println("2没有找到abc.txt 文件");

            System.out.println("3catch 了");

            // System.exit(0);

            // return;

        }

        // finally

        finally {

            System.out.println("4fianlly执行");

            if (fin != null) { // 如果流对象为null 流对象就不存在,没有必要关闭资源

                try {

                    fin.close();

                } catch (IOException e) {

                    e.printStackTrace();

                    System.out.println("close 异常");

                }



            }

            System.out.println("5finally over");

        }

        System.out.println("6mainover");

    }

}
// 2:无论程序正常还是异常,都执行finally。 但是遇到System.exit(0); jvm退出。

// finally用于必须执行的代码, try{} catch(){}finally{}

// try{}finally{}

思考:

为什么要将一个类定义成内部类?
匿名内部类的使用和细节(面试题)
异常的思想和体系特点?
throws和throw的如何使用?
什么时候try 什么时候throws?
编译时被检测异常和运行时异常的区别?
异常的所有细节?
finally的应用?
包的作用,名称空间的定义和理解?
jar包的基本使用。只要将类和包都存储到jar中,方便于使用。只要将jar配置到classpath路径下。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,219评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,363评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,933评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,020评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,400评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,640评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,896评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,597评论 0 199
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,327评论 1 244
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,581评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,072评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,399评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,054评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,083评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,849评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,672评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,585评论 2 270

推荐阅读更多精彩内容