IO--异常

异常引入

异常的概述、分类、举例

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

/*
       异常概述:异常就是Java程序在运行过程中出现的错误。

       Java中的异常:Throwable
            严重的问题:Error,一般情况下,我们解决不了这样的问题,
                举例今后会出现的情况:OOM(Out Of Memory)内存溢出的问题。

            异常:Exception
                运行时期异常:RuntimeException,这样的问题出现之前我们不处理(不易发现),因为这样类似的问题
                    一般情况下都是由于你的代码不够严谨导致的。

                编译时期异常:
                    除了不是RuntimeException的,都是编译时期异常,必须要处理,如果你不处理
                    编译不通过,无法运行。

      如果程序出现了问题,我们没有做任何处理,最终JVM会给出一个默认的处理方式,
      把异常类的名称,相关的原因,以及出现问题的相关信息和位置信息输出在控制台,同时
      java程序会结束,后面的代码不会执行。

*/
public class ExceptionDemo1 {
    public static void main(String[] args) {
//--------------运行时期异常举例-----------
       
//        int a = 10;
//        int b = 0;
//        //运行时期异常:编译时期没报错,运行时期报错了。
//        //ArithmeticException: / by zero          
//        System.out.println(a/b);
//        //当上面运行时出现异常之后之后的步骤就不会执行了,程序结束。
//        System.out.println("hello");
//
//        int[] arr = null;
//        //NullPointerException
//        System.out.println(arr.length);

//--------------编译时期异常举例-----------
      
//        //工具类----日期类--java.util
//        //创建日期类对象
//        Date date = new Date();        
//        System.out.println(date);//Fri Dec 24 19:14:03 CST 2021
//
//        //日期转换是我们开发中经常使用
//        
//        //SimpleDateFormat是做日期转换的,括号里放日期格式。
//        //日期格式:年:yyyy  月:MM  日:dd  时:HH(hh)  分:mm  秒:ss
//        //中间用 - 连接      
//        //HH大写的表示24小时制度
//        //hh小写的表示12小时制度
//        //将格式定下来之后我们需要去转格式
//        //该类中format()方法可以转格式,返回一个String类的值      
//        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//        String s = sdf.format(date);
//        System.out.println(s);

        //String --> Date
        //SimpleDateFormat类中parse()方法可以将String-->Date,返回Date类型的值
        String s = "2021-12-24";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //这样写编译时期会报错
//        Date date = sdf.parse(s);
//        System.out.println(date);
      
        //修改后
        Date date = null;
        //java.text.ParseException: Unparseable date: "2021-12-24"
        try {
            date = sdf.parse(s);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        //做了这样的处理之后
        //虽然还是会报错,但是能输出data的值
        System.out.println(date);//null
    }
}

 异常体系

异常处理方式、try...catch...finally

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

/*
        异常处理方式:
            1、try...catch...finally
            2、throws

      try...catch...finally处理格式:
          try{
            可能会出现问题的代码;
          }catch(异常的类名 变量名){
            针对问题的一些处理;
          }finally{
            无论报不报错都会执行的代码;
            (一般情况下,这里放的都是一些释放资源的代码)
          }

      变形格式:
        try{
            可能会出现问题的代码;
        }catch(异常的类名 变量名){
            针对问题的一些处理;
        }

     处理多个异常的格式:
        try{
            可能会出现问题的代码1;
            可能会出现问题的代码2;
        }catch(异常的类名1 变量名1){
            针对问题的一些处理;
        }catch(异常的类名2 变量名2){
            针对问题的一些处理;
        }

     多个catch注意事项:
        1、能明确异常类型的时候,尽量明确类型,不要用父类大的做处理
        2、catch与catch之间的异常是平级关系,多个catch异常之间没有先后顺序关系,一旦出现了一个
            父类继承关系,父类异常必须在最后
        3、一旦try里面的代码出现了问题,就会去匹配catch里面的异常,继续执行程序try...catch...后面的代码,
            try里面的代码就停在了报错的那一步,try中剩下的代码不会执行。

*/

public class ExceptionDemo2 {
    public static void main(String[] args) {
//运行时期异常
        //通常是我们的代码不够严谨
        int a = 10;
        int b = 0;
        //System.out.println(a/b);
        //所以解决办法:让我们的代码变得严谨
        if(b==0){
            System.out.println("除数不能为0");
        }else {
            System.out.println(a/b);
        }

//编译时期异常

//------------一个异常的情况--------------     
        String s = "2021-12-24 14";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");            
//        //使用try...catch...处理        
//        try {
//            Date date = sdf.parse(s);
//            System.out.println(date);
//        //catch后面的括号里可以放异常及异常的父类
//        }catch (Exception e){
//            System.out.println("日期转换出现错误啦!!!");
//        }
//        //使用try...catch...处理异常后,后面的代码可以执行
//        System.out.println("hello");

      
//--------------多个异常的情况------------------       

//注意事项
      
//1、能明确异常类型的时候,尽量明确类型,不要用父类大的做处理       
        int[] arr  = null;
        try {     
            System.out.println(arr.length);
        //能明确异常类型的时候,尽量明确类型
        }catch (NullPointerException e){  
        //不要用父类大的做处理
        //}catch (Exception e){
            System.out.println("空指针异常");
        }                
        System.out.println("hello");      

//2、catch与catch之间的异常是平级关系,没有先后顺序关系,一旦出现了一个父类继承关系,父类异常必须在最后   
        int[] arr  = null;
        String s = "2021-12-24 14";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            Date date = sdf.parse(s);
            System.out.println(date);
            System.out.println("world");
            System.out.println(arr.length);
        //catch与catch之间的异常是平级关系,没有先后顺序关系
        }catch (NullPointerException e){
            System.out.println("空指针异常");
        //一旦出现了一个父类继承关系,父类异常必须在最后
        }catch (Exception e){
            System.out.println("日期转换出现错误啦!!!");
        }
        System.out.println("hello");       

//3、如果在try里面的代码中间报错了,会直接匹配catch里面的异常,try中剩下的代码不会执行
        int[] arr = {1,2,3,4};
        String s = "2021-12-24 14";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            Date date = sdf.parse(s);
            //如果在try里面的代码中间报错了
            //会直接匹配catch里面的异常
            //try中剩下的代码不会执行
            System.out.println(date);
            System.out.println("world");
            System.out.println(arr[4]);
        }catch (Exception e){
            System.out.println("日期转换出现错误啦!!!");
        } 
        System.out.println("hello");
      
      
//----或者可以分开写,但是这样程序臃肿,不建议-----      
        try {
            Date date = sdf.parse(s);
        }catch (ParseException e){
            System.out.println("日期转换出现错误啦!!!");
        }

        try {
            System.out.println(arr.length);
        }catch (NullPointerException e){
            System.out.println("空指针异常");
        }
    }
}

JDK1.7之后try...catch...针对多个异常处理新的处理方式

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

/*
    JDK1.7之后针对多个异常处理新的处理方式:
        try{
            可能会出现问题的代码;
        }catch(异常类名1 | 异常类名2 | ...  变量名){
            处理异常的提示;
        }

    注意事项:
        1、处理方式是一致的,这个方法虽然比较简洁,但是不够好,针多种类型的问题,
           只给出了一种解决方案
        2、catch括号中多个异常类型之间的关系必须是平级关系,不能存在继承关系

*/

public class ExceptionDemo3 {
    public static void main(String[] args) {
      
        int[] arr  = null;
        //String -- Date
        String s = "2021-12-24 14";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            Date date = sdf.parse(s);
            System.out.println(date);
            System.out.println("world");
            System.out.println(arr.length);
        //针多种类型的问题,只给出了一种解决方案,  
        //括号里不能存在继承关系    
        }catch (ParseException|NullPointerException e){
            System.out.println("报错了");
        }
        System.out.println("hello");
    }
}

 Throwable中需要掌握的方法

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

/*
    异常中需要掌握的方法:
        getMessage()
            获取异常信息,返回字符串。
        toString()
            获取异常类名和异常信息,返回字符串。
        printStackTrace()
            获取异常类名和异常信息,以及异常出现在程序中的位置。返回值void。

*/

public class ExceptionDemo4 {
    public static void main(String[] args) {
        int a = 10;
        int b = 0;

        //ArithmeticException
        try{
            System.out.println(a/b);
        //方法是如何调用的呢?
        //将来try里面的代码报错了
        //Java底层JVM会生成一个异常对象给我们
        //然后去匹配catch后面的异常类型
        //如果匹配到的话相当于new了一下。
        //ArithmeticException e = new ArithmeticException();
        }catch (ArithmeticException e){ 
          
            //打印的是出现异常的原因--/ by zero
            //System.out.println(e.getMessage()); 
                                
            //异常的类名: 产生问题的原因
            //java.lang.ArithmeticException:/ by zero
            //System.out.println(e.toString());

            //通过观察发现,和我们之前不做任何处理的时候,JVM自动默认处理的打印异常结果是一样的
            //我们不能不处理,如果不处理一旦发生异常,后面的代码不会运行
            //我们做了处理之后,后面的代码才会正常运行
            e.printStackTrace();
        }
    }
}

 throws

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

/*
        在今后的开发过程中,有些情况我们根本没有权限去做一些处理异常
        或者说,我们根本就处理不了,干脆就不处理。
        为了解决这样的问题,并且还能保证程序正常运行的情况下
        Java针对这种情况,提供了另外一个解决异常的方式:throws抛出(跟在方法后面)

        格式:
            throws 异常类名
            在哪里写呢?在方法小括号后面,左大括号之前

        注意事项:
            1、main方法上尽量不要进行异常抛出,因为程序会停止,后面代码不会执行
            2、编译时期的异常抛出,方法内部不需要做处理,是由将来调用该方法的调用者处理
            3、运行时期异常可以不抛出,但是一旦调用,出错后,后面的代码依旧不会执行
            4、最好抛出一个具体的异常类型,也是推荐这么做的,可以抛出多个异常,用逗号隔开

 */
public class ExceptionDemo5 {
    public static void main(String[] args) throws ParseException {
        //方法中没有处理异常,调用者必须处理
        //方式1、try...catch...
//        try {
//            fun();
//        } catch (ParseException e) {
//            e.printStackTrace();
//        }
//      //这时会执行输出hello      
//        System.out.println("hello");      
      
        //方式2、在main()方法后面用throws抛出异常
        //抛给Java虚拟机了
//        fun();
//      //这时不会执行输出hello
        //因为执行到上一步的时候,并没有处理异常,而是将异常抛给虚拟机了
        //程序结束了。
//        System.out.println("hello");
      
        //运行时期异常可以不抛出,
        //但是一旦调用,出错后,
        //后面的代码依旧不会执行
        try {
            fun1();
        }catch (NullPointerException e){
            e.printStackTrace();
        }

        System.out.println("hello");

    }
    //在哪里写呢?在方法小括号后面,左大括号之前
    //编译时期异常
    //可以抛出多个异常,用逗号隔开
    public static void fun() throws ParseException,NullPointerException {
        String s = "2021-12-24 14";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = sdf.parse(s);
        System.out.println(date);
    }
    //运行时期异常
    public static void fun1() throws NullPointerException{
        int[] arr = null;
        System.out.println(arr.length);
    }
}

 throw、throws和throw的区别

/*
        throw
            用在方法体内,跟的是异常对象名
            只能抛出一个异常对象名
            表示抛出异常,由方法体内的语句处理
            throw则是抛出了异常,执行throw则一定抛出了某种异常 


        throws和throw的区别:

        throws:
            用在方法的声明后面,跟的是异常的类名
            可以跟多个异常类名,用逗号隔开
            表示的是可能会发生的异常,抛出给调用者处理,表示的是一种可能性,
            不一定会发生这种异常

        throw:
            用在方法体内,跟的是异常对象名
            只能抛出一个异常对象名
            表示抛出异常,由方法体内的语句处理
            throw则是抛出了异常,执行throw则一定抛出了某种异常 
        
*/

public class ExceptionDemo6 {
    public static void main(String[] args) {
        try {
            fun();
        //ArithmeticException e = new ArithmeticException()
        }catch (ArithmeticException e){ //throw new ArithmeticException()
            e.printStackTrace();
        }
      
        System.out.println("hello");
    }

    public static void fun(){
        int a = 10;
        int b = 0;

        if(b==0){
            System.out.println("报错,除数不能为0");
            //用在方法体内,跟的是异常对象名
            throw new ArithmeticException();
        }else {
            System.out.println(a/b);
        }
    }
}

 我们到底该如何处理异常呢

/*
    原则:
      如果该功能内部可以将问题处理,用try,如果处理不了,交由调用者处理,这是用throws
    区别:
      后续程序需要继续运行就try
      后续程序不需要继续运行就throws
    举例:
      感冒了就自己吃点药就好了,try
      吃了好几天药都没好结果得了新冠,那就的得throws到医院
      如果医院没有特效药就变成Error了
*/

finally的特点作用

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

/*

    finally: 最终的意思
        在try...处理异常的时候,末尾通常情况下会添加一个finally
        被它控制的语句体,一定会执行,一般情况下,里面放的是与释放资源相关的代码

    try...catch...finally
    
*/

public class ExceptionDemo7 {
    public static void main(String[] args) {
        String s = "2021-12-24 14:32:12";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        try {
            Date date = sdf.parse(s);
            System.out.println(date);
        }catch (ParseException e){
            e.printStackTrace();
        }finally {
            //无论报不报错都会执行
            System.out.println("这里的代码一定会执行!!!");
        }
    }
}

finally的面试题 

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

/*

    面试题:
        final,finally和finalize的区别

        final:最终的意思,可以修饰类,成员变量,成员方法,
              局部内部类定义的局部范围中的局部变量默认被final修饰
            修饰类:类不能被继承
            修饰成员变量:变量变常量
            修饰成员方法:方法不能被重写
        finally:是异常处理的一部分,一般情况下用于释放资源的作用,一般情况下都会执行
            特殊情况下: System.exit(0);
        finalize: 是Object类中的一个方法名,用于手动垃圾回收,但是不一定调用就开始回收。

*/

public class ExceptionDemo8 {
    public static void main(String[] args) throws ParseException{
      
      //finally特殊情况下

//        int a = 10;
//        int b = 0;
//        int c = 0;
      
//        //首先
//        try {
//            //让程序停止的代码
////            System.exit(0);
//            c = a/b;
//        }catch (ArithmeticException e){
//            e.printStackTrace();
             //程序直接停了,所以finally语句不会执行
//        }finally {
//            System.out.println("这是finally中的内容");
//        }
      
      
          //把前面注释掉之后
          //并在main()方法之后添加throws抛出异常
          //但是异常并没有处理,所以程序执行到这一步后报错,程序停止
//          fun();
    }
  
    public static void fun() throws ParseException,NullPointerException {
        String s = "2021-12-24 14";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = sdf.parse(s);
        System.out.println(date);

 catch里面有return语句的情况

/*
    面试题:
        如果catch里面有return语句,请问finally的代码还会执行吗?
               //finally一般情况下都会执行,除非程序停止
        如果会,请问是在return前还是return后。
               //更形象的理解为在在return之间
        
        1、如果finally中有return语句,永远返回finally中的结果,避免该情况
        2、在return之间,return更形象的被理解为一个返回通道

*/

//-----如果finally中有return语句,永远返回finally中的结果,避免该情况-----

public class ExceptionDemo {
    public static void main(String[] args) {
      //1、如果finally中有return语句,永远返回finally中的结果,避免该情况
      int a = getA();
      System.out.println(a);//100
      
      //
    }
  //定义一个方法,返回变量a的值
  public static int getA(){
    int a = 10;
    try{
      return a ;
    }catch(Exception e){
      System.out.println(e);
    }finally{
      a = 100;
      return a;
    }
  }
  
  
//---------------------在return之间---------------------
  
public class ExceptionDemo8 {
    public static void main(String[] args) throws ParseException{   
      System.out.println(fun());
      //情况1:70  情况2:50
  }
  
  //----情况1:
  public static int fun() {
        int a = 10;
        String s = "2021-12-24 14";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            a =30;
            Date date = sdf.parse(s);
            //假如我程序报错,那么try里面剩下的两句语句一定不会执行
            System.out.println(date);
            a = 40;
        }catch (ParseException e){
            a = 50;
            return a;//此时返回通道形成,返回 a = 50 ,但不会立刻返回。
          
        //一般来说return可以结束一个方法,但是这里情况特殊
        //try...catch...语句里面的finally语句,除非程序骤停,不然都会执行。
        //所以return会在finally语句执行完毕之后,结束方法
        }finally {
          
          //此时a的值发生改变 a = 70 。
            a = 70;
            return a;//此时这里的return是将返回通道里的a的值覆盖掉了。
        }
    }//⬅如果finally中或者try...catch...语句外没有return
     //会报错因为异常可能会发生,也可能不发生,取决于你上面定义的 s 。
     //如果不发生那么该方法就没有返回值了。会报错
  
  //----情况2:
  public static int fun() {
        int a = 10;
        String s = "2021-12-24 14";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            a =30;
            Date date = sdf.parse(s);
            //假如我程序报错,那么try里面剩下的两句语句一定不会执行
            System.out.println(date);
            a = 40;
        }catch (ParseException e){
            a = 50;
            return a;//此时返回通道形成,返回 a = 50 。
          
        //一般来说return可以结束一个方法,但是这里情况特殊
        //try...catch...语句里面的finally语句,除非程序骤停,不然都会执行
        //所以return会在finally语句执行完毕之后,结束方法
        }finally {
          
          //此时a的值发生改变 a = 70 。
          //但是这个70并没有return去改变返回通道里的值
            a = 70;
        }
    
          //执行完finally语句之后方法结束,下面的语句没有执行。
          return a ;//但是这个return不加会报错,原因如下。
    
    }//⬅如果finally中或者try...catch...语句外没有return
     //会报错因为异常可能会发生,也可能不发生,取决于你上面定义的 s 。
     //如果不发生那么该方法就没有返回值了。会报错  
}

异常注意事项

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

/*
    异常注意事项:
        1、子类重写父类方法时,子类的方法必须抛出相同的异常或父类异常的子类。
        
        2、如果父类抛出了多个异常,子类重写父类时,子类不能单独抛出父类没有的异常
            
        3、编译时期异常时如果被重写的方法没有异常抛出,那么子类的方法绝对不可以抛出异常,
           此时子类方法内有编译时期异常发生,那么子类只能try,不能throws

*/
//----------子类重写父类方法时,子类的方法必须抛出相同的异常或父类异常的子类--------
class A{
    public void fun() throws NullPointerException{

    }
}

class B extends A{
    @Override
    //子类的方法必须抛出相同的异常或父类异常的子类
    public void fun() throws NullPointerException{
    //public void fun() throws Exception {---报错
       super.fun();
    }
}

//----------子类不能单独抛出父类没有的异常--------
class A{
    public void fun() throws NullPointerException , ParseException {

    }
}

class B extends A{
    @Override
    //子类不能单独抛出父类没有的异常
    //public void fun() throws ArithmeticException{
    //不单独抛出的时候可以
    public void fun() throws NullPointerException,ParseException,ArithmeticException {
       super.fun();
    }
}

//----------如果子类方法内有编译时期异常发生,那么子类只能try,不能throws--------
class A{
    public void fun(){

    }
}

class B extends A{
    @Override
    //编译时期异常时如果被重写的方法没有异常抛出,那么子类的方法绝对不可以抛出异常,
    //public void fun() throws ParseException{---报错不能throws,抛出异常
    public void fun(){
    String s = "2021-12-24 14";
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    //子类只能try,不能throws
    try {
         Date date = sdf.parse(s);
        }catch (ParseException e){
         e.printStackTrace();
        }
    }
}


public class ExceptionDemo9 {
    public static void main(String[] args) throws NullPointerException,ParseException,ArithmeticException {
        B b = new B();
        b.fun();
    }
}
posted @ 2021-12-24 22:59  赤兔胭脂小吕布  阅读(79)  评论(0编辑  收藏  举报