异常-try...catch...finally、Throwable、throws、finally、自定义异常、注意事项

  • 我们接下来的主要内容是 io 流。但是在讲流之前先要讲一下 文件 和 异常。
  • 为什么?
    因为 主要就是用来操作文件的(文件的上传和下载)所以我们要先学习 文件。
    在操作文件的过程中,有可能会出现问题。出现问题之后,我们就需要做出对应的处理。
    所以我们还要学习 异常

1,异常

1.1 概述

-就是java程序的不正常情况

1.2 为什么有异常类?异常类的由来?

  • 不正常的情况(问题)也是现实生活中一个真实存在的具体事物,所以java也用类的形式进行了描述,封装了对象。
  • 这个对象就是java对不正常的情况描述后的具体体现。
  • 我们在写代码的时候,会经常出现的异常
    空指针异常
    索引越界异常
    类型转换异常

1.3 异常的分类

异常:Throwable

严重问题:Error
	我们不处理,这种问题一般都很严重,我们解决不了。不是我们自己的问题。
		内存不够。。。
问题:Exception
	编译期问题:非RuntimeException	
		这种问题我们必须改代码。不改代码编译都不能通过。	
	运行期问题:RuntimeException	
		出现这样的问题,大部分都是因为代码写的不够严谨,需要改成代码
  • Throwable
      Error
       子类
      Exception
        非RuntimeException
          子类
        RuntimeException
          子类

  • 举例:
    过年了,我打算带着家人开车出去旅游。
    问题一:打算出门的时候,突然下起了大雪,不能出去了 — 严重的问题
    问题二:刚准备上车的时候,发现车没气了,给车打个气 — 出发前就因该检查的问题
    问题三:开车出门了,正在正常行驶,突然路边出现了一个美女,吸引了我的眼睛。没有注意开车,
    看美女了,然后车撞了— 过程中出现的问题。

  • 如果程序出现了问题,我们没有做任何处理。最终jvm会做出默认的处理。

1.4 jvm默认处理是如何处理的?

把异常的名字,原因和出现的问题,位置等信息输出到控制台上。
同时程序会结束,后面的代码不会执行。
	当代码执行到System.out.println(1/0);这一步的时候,jvm发现这个元素已经违反了数学运算规则,
	java把类似这种常见的问题都进行了描述,并封装成了类---ArithmeticException
	当除0运算发生后,jvm就会把该问题打包成一个异常对象,并且会把对象抛给调用者main
	方法,new ArithmeticException("/ by zero");
	
	main方法接收到这个问题对象时,有2种处理方式:
		第一种:我们自己处理,程序可以继续运行。
		第二种:我们不处理(或者我们无法处理),最终就只能交给main方法的调用者 jvm 来处理
			jvm会走它的默认处理机制。
			
Exception in thread "main" java.lang.ArithmeticException: / by zero
at com.momo.demo.Demo24.main(Demo24.java:12)

2 异常的处理方案

2.1 异常处理方式由两大类

  • try…catch…finally
  • throws

2.2 try…catch…finally

try{
	可能出现问题的代码
}catch(异常类名 变量名){
	针对问题处理方式
}finally{
	无论代码有没有问题,都必须执行的代码
	释放资源
}
  • 注意:try中的代码越少越好。尽可能只把有可能会出现问题的代码放进去,
    确定不会出问题的代码尽量不要往里面放。
    catch里面必须有内容。哪怕只是一个提示语句都行。
  • 又有很多变形格式
    try…catch
    try…catch…catch…
    try…catch…catch…finally
    try…finally

2.3 try…catch处理方式

  • 又分为:
      一个异常
      多个异常
        平级关系
        子父级关系
    在这里插入图片描述
package com.momo.demo;
/*多个异常:
*   每一个异常写一个try...catch
*   另一种方式用try...catch...catch.....
* 注意:2中方式的区别:
*   一旦try里面的代码出现问题,就会在这里把问题抛出去,
* 然后和catch里面的问题类型进行匹配,一旦匹配成功,就会执行对应catch里面的处理方式。
* try..catch就结束了。然后代码会继续向下执行。 不会回头。
* */
public class Demo5 {
    public static void main(String[] args) {
        System.out.println("开始执行");

       //一起处理
       int a = 5;
        int b = 1;
        int[] arr = {1,2,3,4};
        try {
            System.out.println(a / b);
            System.out.println(arr[5]);
        }catch (ArrayIndexOutOfBoundsException ai){
            System.out.println("数组索引越界了");
        }catch (ArithmeticException ae){
            System.out.println("除数不能是0");
        }


        //分开处理
       /* int a = 5;
        //int b = 1;
        int b = 0;
        try {
            System.out.println(a / b);
        }catch (ArithmeticException ae){
            System.out.println("除数不能是0");
        }

        int[] arr = {1,2,3,4};
        try {
           System.out.println(arr[5]);
        }catch (ArrayIndexOutOfBoundsException ai){
            System.out.println("数组索引越界了");
        }*/

        System.out.println("执行结束");
    }
}

  • jdk7之后出现了一种新的异常处理方式:
package com.momo.demo;
/*
 *jdk7之后出现了一种新的异常处理方式:
 *  try{
 *  ...
 * }catch(异常类名一|异常类名二|....  变量名){
 *  ....
 * }
 *
 * 注意:这种方式虽然看起来简单一点。但是不太好。
 *      多种异常的处理方式是一致的。(实际应用比较方便。开发中很多时候就是针对多种问题,给一个处理方式。)
 *      多个异常之间必须是平级关系,不能出现子父级关系。
 * */
public class Demo7 {
    public static void main(String[] args) {
        System.out.println("开始");
        int a = 5;
        int b = 0;
        int[] arr = {1,2,3,4};

        try{
            System.out.println(a/b);
            System.out.println(arr[5]);
            System.out.println("假设我这里还有其他代码,也有可能会出现问题。" +
                    "但是我不知道它到底会出现什么问题,怎么呢?" +
                    "");
        }catch (ArithmeticException|ArrayIndexOutOfBoundsException e){
            System.out.println("出问题了。。。");
        }

        System.out.println("结束");
    }
}

3 编译期异常和运行期异常的区别

java中异常分为2大类:

  • 编译期异常:
    非RuntimeException的异常都是编译期异常
    必须修改代码,否则程序报错,编译不通过。
  • 运行期异常:
    所有的RuntimeException以及它的子类都是运行期异常
    可以和编译期异常一样去处理,也可以不处理。

4 Throwable中的方法

  • String getMessage() 以字符串的形式返回异常信息
  • void printStackTrace() 获取异常类名和信息,以及异常所出现的位置。
  • void printStackTrace(PrintStream s) 这个方法一般用来把异常信息保存到日志文件中,方便查阅。
  • String toString() 以字符串的形式返回异常类名以及信息
package com.momo.demo;

import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/*
* try里面发现问题后,jvm会帮我们创建一个异常对象,然后把对象抛出去
*  和catch里面的类进行匹配。
* 如果有类型匹配上了,那么就会执行对应catch里面的处理方式。
* */
public class Demo9 {
    public static void main(String[] args)  {
        System.out.println("开始");
        String s = "2020-05-05";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date date = null;
        try {
            date = sdf.parse(s);//一但出错,已经产生了一个具体的错误。
            // 它就会创建具体的 new ParseException();然后把这个对象抛出去了
            //和catch中进行匹配。
        } catch (ParseException e) {
            //ParseException e = new ParseException();
           // e.printStackTrace();
        /*
        * java.text.ParseException: Unparseable date: "2020-05-05"
        at java.text.DateFormat.parse(DateFormat.java:366)
        at com.momo.demo.Demo9.main(Demo9.java:15)
        * */

            //String message = e.getMessage();
            //System.out.println(message);
            //Unparseable date: "2020-05-05"

            //String s1 = e.toString();
            //System.out.println(s1);
            //java.text.ParseException: Unparseable date: "2020-05-05"

           /* try {
                e.printStackTrace(new PrintStream("log.txt"));
            } catch (FileNotFoundException ex) {
                ex.printStackTrace();
            }*/
        }

        System.out.println(date);

        System.out.println("结束");
    }
}

5 throws

5.1 概述

定义方法时,有可能在使用的时候会出现问题,但是这个问题我无法处理,或者说我没有权限处理。我们就需要把问题暴漏出来交给调用者去处理。
我们就需要使用throws在方便上标记。

package com.momo.demo;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/*
* 有些时候,我们可以对异常进行处理。
* 又有些时候,我们没办法处理某个异常
* 为了解决出错问题,java就提供了另一种处理方式:抛出去
*
* 格式:throws 异常类名
* 注意:这个格式必须跟在方法的() 后面。
*
* 注意:尽量不要在main方法上抛,最后就走jvm的默认处理机制了
*       后面上课的时候为了方便我就直接抛了
*
* 编译期异常的抛出:将来调用者必须处理
* 运行期异常的抛出:将来调用者可以不处理
* */
public class Demo10 {
    public static void main(String[] args) {
        System.out.println("程序开始");

       /* try {
            fun1();
        } catch (ParseException e) {
            e.printStackTrace();
        }*/

       fun2();

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

    //运行期异常的抛出
    public static void fun2() throws ArithmeticException{
        System.out.println(5/0);
    }

    //编译期异常的抛出
    public static void fun1() throws ParseException {
        String s = "2020-05-05";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        Date date = sdf.parse(s);
        System.out.println(date);
    }
}

package com.momo.demo;
/*
* thorw:如何抛异常
* 问:throw和throws的区别?
*   throws:
*       在方法声明后,跟的时异常的类名,如果又多个异常,用逗号隔开。
*       表示的是抛出异常,将来由调用者来处理
*       表示的是一种可能性,不一定会发生这些问题。
*   throw:
*       在方法内部,跟的是异常的对象
*       只能抛除一个异常对象
*       表示抛出异常,throw一旦执行表示一定抛出了某个异常对象。
* */
public class Demo11 {
    public static void main(String[] args) {
        System.out.println("aaaa");
       /* try {
            fun2();
        }catch (Exception e){
            //Exception e = new ArithmeticException();
            e.printStackTrace();
        }*/

        fun1();

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

    public static void fun1(){
        int a = 5;
        int b = 0;
        if(b==0){
            throw new ArithmeticException();
        }else{
            System.out.println(a/b);
        }
    }

    public static void fun3() throws ArithmeticException{
        int a = 5;
        int b = 0;
        if(b==0){
            throw new ArithmeticException();
        }else{
            System.out.println(a/b);
        }
    }

    public static void fun2() throws ArithmeticException,ArrayIndexOutOfBoundsException{
        int a = 5;
        int b = 0;
        System.out.println(a/b);

        int[] arr = {1,2,3,4,5};
        System.out.println(arr[6]);
    }
}

5.2 我们遇到异常的时候到底该如何处理呢?

  • 原则:如果在写方法的时候,能通过改代码提高程序安全性的时候就改代码
    如果改代码解决不了,能用try就用try处理。
    如果try处理不了,就交给调用者用throws
  • 区别:如果出现问题,后面的代码还想继续执行就用try
    如果出现问题,后面的代码不想继续执行就用throws

6 finally

6.1 finally的特点

  • 写在finally中的代码一定会执行
  • 注意:有一种特殊情况,在执行到finally之前,jvm退出了。

6.2 2finally的作用

  • 主要作用是用来释放资源的,后面的学习慢慢会见到。
package com.momo.demo;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Demo12 {
    public static void main(String[] args) {
        System.out.println("start");
        String s = "2020-05-05";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
       // SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date date = null;
        try {
            date = sdf.parse(s);
            System.out.println(5/1);
        } catch (ParseException e) {
            e.printStackTrace();
            //System.exit(0);

            return;

        } catch (ArithmeticException e) {
            e.printStackTrace();
        } finally {
            sdf = null;
            System.out.println("我是finally");
        }
        System.out.println(date);
        System.out.println("end");
    }
}

6.3 finally的相关问题

  • 问:final,finally,finalize的区别?
  • 问:如果catch语句中有return语句,请问,finally中的代码还会执行吗?
    retrun的作用:结束方法,把结果返回给调用者。
    会执行。 到底是怎么执行的?是在return之前执行的吗?还是在return之后?
    是在return之前执行。
    其实更像是在中间执行的
package com.momo.demo;

public class Demo13 {
    public static void main(String[] args) {
        System.out.println(get());
    }

    public static int get(){
        int a = 5;
        //System.out.println(a);
        try {
            System.out.println(a / 0);
            a = 55;
          //  System.out.println(a);
        }catch (ArithmeticException ae){
            a = 555;
           // System.out.println(a);
            return a;
            /*
            * 当代码走到这里的时候已经该返回了,这个时候a是555;
            * 所以在这里已经不是return a了,是return 555;
            * 但是发现后面有fianlly,所以就去执行了finally中的代码
            * 虽然在finally中给a赋值5555,但是对我的返回结果已经没有影响了
            * 执行完成finally之后,会再次回到return 555返回,结束。
            * */
        } finally {
            a = 5555;
           // System.out.println(a);
            return a;
        }
      //  return a;
    }
}

6.4 要记住try…catch…finally的常见的变型格式

  • try…catch…finally
  • try…catch…
  • try…catch…catch…
  • try…catch…catch…finally
  • try…finally 就是为了释放资源
package com.momo.demo;

import java.util.Scanner;

public class Demo14 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        try{
            System.out.println(5/0);
        }finally {
            sc.close();
            System.out.println("释放资源");
        }
    }
}

7 自定义异常

7.1 概述

  • java不可能考虑到所有的异常情况。所以在实际开发的时候,我们需要自定义异常。
  • 比如:我自定义的逻辑。判断成绩是否在1-100之间。像这种情况我们就需要自定义异常类来处理自定义逻辑的异常。

7.2 我们随意写的一个类不能直接作为异常类来处理异常的。

要想使我们定义的类是一个异常类,可以处理异常。那么这个类就必须继承 Exception 或者 RuntimeException。

  • 继承Exception: 编译期异常
  • 继承RuntimeException:运行期异常
package com.momo.myexception;

public class My1 extends Exception {
}

package com.momo.myexception;

public class My2 extends RuntimeException {
}

package com.momo.demo;

import com.momo.myexception.My;
import com.momo.myexception.My1;
import com.momo.myexception.My2;

public class Demo15 {
    public static void main(String[] args){
       // fun();
        fun2();
    }

    public static void fun() throws My1{}

    public static void fun2() throws My2 {}
}

package com.momo.myexception;

/*public class MyException extends Exception {
    public MyException(){}
    public MyException(String message){
        super(message);
    }
}*/

public class MyException extends RuntimeException {
    public MyException(){}
    public MyException(String message){
        super(message);
    }
}

package com.momo.domain;

import com.momo.myexception.MyException;

public class Tea {
    public void check(int score) throws MyException {
        if(score>100||score<1){
            throw new MyException("分数不合法,1-100之间。");
        }else{
            System.out.println("成绩合法");
        }
    }
}

package com.momo.demo;

import com.momo.domain.Tea;
import com.momo.myexception.MyException;

import java.util.Scanner;

public class Demo16 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入成绩:");
        int i = sc.nextInt();

        Tea t = new Tea();
       /* try {
            t.check(i);
        } catch (MyException e) {
            e.printStackTrace();
        }*/

       t.check(i);
    }
}

8 异常的注意事项

  1. 子类重写父类方法时,子类的方法只能抛出和父类一样的异常或者是父类异常的子类。
  2. 子类重写父类方法时,如果父类方法抛出了多个异常,子类只能抛出相同的异常或者是父类异常的子集,不能抛出父类没有的异常。
  3. 类重写父类方法时,如果父类方法没有抛异常,子类重写的时候也不能抛异常。
    如果子类重写的时候出现了异常,就只能try,不能throws
  • 儿子不能不父亲更坏
package com.momo.domain;

import org.omg.CORBA.portable.ApplicationException;

import java.rmi.AlreadyBoundException;
import java.rmi.activation.ActivationException;
import java.security.acl.AclNotFoundException;
import java.text.ParseException;

public class Father {
    public void show() throws Exception
    {

    }

    public void fun(){}
}
package com.momo.domain;

import org.omg.CORBA.portable.ApplicationException;

import java.rmi.AlreadyBoundException;
import java.rmi.activation.ActivationException;
import java.security.acl.AclNotFoundException;
import java.text.ParseException;
import java.text.SimpleDateFormat;

public class Son extends Father {
    public void show() throws NullPointerException,ArrayIndexOutOfBoundsException,ArithmeticException {
        System.out.println("zishow");
    }

    public void fun (){
        SimpleDateFormat sdf = new SimpleDateFormat("");
        try {
            sdf.parse("");
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值