Java异常

异常 是什么, 异常机制有什么作用

程序在执行过程中,发生了不正常的情况,这种情况就叫做异常
Java提供了异常处理的方法,程序执行过程中出现了不正常的情况,Java把该异常信息打印到控制太
程序员阔以根据异常信息对程序修改
异常增加了程序的健壮性
例如:

public class ExceptionTest01 {
    public static void main(String[] args) {
        int a=10;
        int b=0;
        //实际上JVM在执行到此处的时候new一个ArithmeticException类的对象: new ArithmeticException("/ by zero");
       int c=a/b;
       System.out.println(c);
    }
}

Exception in thread "main" java.lang.ArithmeticException: / by zero
//这个信息成为异常信息,是JVM打印的

异常是以什么形式存在的?
是以类的形式存在的
异常类都可以创建

import java.lang.String;
public class ExceptionTest02 {
    public static void main(String[] args) {
        //通过异常类实例化异常类对象
        NumberFormatException nfe = new NumberFormatException("数组格式化异常");
        System.out.println(nfe);

        //通过异常类实例化异常类对象
        NullPointerException npe= new NullPointerException("空指针异常发生了");
        System.out.println(npe);
    }

}
//输出 java.lang.NumberFormatException: 数组格式化异常
//输出java.lang.NullPointerException: 空指针异常发生了

与错误的区别:发生错误,java程序只能终止程序执行,退出JVM,错误是不能处理的

Object下有Throwable接口
Throwable下有两个分支:Error(不可处理,强制退出)和Exception(可处理)

编译时异常和运行时异常,都发生在运行时,因为运行时才会才会new对象
编译时异常是因为这种异常必须在编译阶段预先处理,如不处理编译器就会报错

编译时异常和运行时异常的区别:
编译时异常发生的概率比较高
对于发生概率较高的异常,需要在运行之前进行预处理
例如:下雨天,不打伞可能就会生病。而且这个异常发生的概率很高,所以出门前需要带一把伞
拿一把伞就是对生病异常的预处理
运行时异常发生的概率比较低
例:小明走在街上会被飞机轮子砸到
被飞机轮子砸到也算一种异常,但发生的概率很低
没必要对发生这种发生概率很低的异常进行预处理

异常处理两种方式
第一种:在方法声明的位置使用throw关键字,抛给上一级(异常上抛)
第二种:使用try…catch语句进行异常的捕捉

如果选择了上抛,抛给了调用者,那么调用者也需要对这个异常进行处理,也是同样的两种方式
如果一直上抛直到JVM,那么就会终止任务

运行时异常RuntimeException

所有RuntimeException及其子类,都属于运行时异常。在编译阶段可以处理也可以不处理。
RuntimeException子类:NullPointerException, ClassCastException, NumberFormatException …
例如:

public class ExceptionTest03 {
    public static void main(String[] args) {
        /*程序执行到此处ArithmeticException异常(运行时异常)
           底层new了一个ArithmeticException异常对象
           然后抛出,由于是main方法调用100/0,
           所以这个异常抛给了main方法,main方法没有处理,将这个异常抛给了JVM
           JVM最终终止了程序
        */
        System.out.println(100/0);
        System.out.println("hello");
    }
}

编译时异常ExceptionSubClass

所有ExceptionSubClass及其子类,都属于编译时异常。编译时异常是表示必须在编写程序的时候预先对这种异常进行处理
如果不处理,编译器报错。

/*
报错的原因是:doSome方法声明时用了throws ClassNotFoundException
而ClassNotFoundException是编译时异常,必须编写代码时进行处理,没有处理编译器报错
 */
public class ExceptionTest04 {
    public static void main(String[] args) {
        //调用doSome方法,因为doSome方法有throws ClassNotFoundException
        //我们在调用doSome方法的时候必须对这种异常进行预先的处理,如果不处理,编译就会报错
        //报错信息:Unhandled exception: java.lang.ClassNotFoundException
        //doSome();
    }
    /*
    在方法声明的地方使用throws ClassNotFoundException
    表示在doSome种可能会出现ClassNotFoundException异常(类没有找到)编译时异常

     */

    public static  void doSome()throws ClassNotFoundException{
        System.out.println("doSome");
    }
}

异常的处理

public class ExcepotionTest05 {
    /*第一种方式:使用异常上抛
    public static void main(String[] args)throws ClassNotFoundException {
        doSome();
    }
     */

    /*第二种方式:try..catch..进行捕捉
    捕捉是真正的把异常拦下来,把异常处理了
    
    public static void main(String[] args)throws ClassNotFoundException {
        try {
            doSome();
        }catch(ClassNotFoundException e){
            e.printStackTrace();
        }
    }
    
     */
    public static  void doSome()throws ClassNotFoundException{
        System.out.println("doSome");
    }
}

如果不处理编译时异常,就无法运行

import java.io.FileInputStream;

public class ExceptionTest06 {
    public static void main(String[] args) {
        private static void m1 () {
            System.out.println("main begin");
            m1();
            System.out.println("main end");
        }
    }
    private static void m1(){
        System.out.println("m1 begin");
        m2();
        System.out.println("m1 end");
    }

    private static void m2() {
        System.out.println("m2 begin");
        m3();
        System.out.println("m2 end");
    }

    private static void m3() {
        System.out.println("m3 begin");
        //创建一个输入流对象
        new FileInputStream("C:\\Users\\代涵\\Desktop\\java\\TestTXT.txt");
        //报错是因为public FileInputStream(String name) throws FileNotFoundException {
        //        this(name != null ? new File(name) : null);
        //    }
        //本身声明就有了throws FileNotFoundException(编译时异常)
        //编译时异常在编译时程序员必须对他进行处理
        System.out.println("m3 end");
    }
}

异常处理:

import java.io.FileInputStream;
import java.io.FileNotFoundException;

public class ExceptionTest06 {
    public static void main(String[] args) {
            System.out.println("main begin");
            m1();
            System.out.println("main end");
    }
    private static void m1(){
        System.out.println("m1 begin");
        m2();//是否出现异常,都不影响这里的执行,因为异常已经在m2处理完了
        System.out.println("m1 end");
    }

    private static void m2(){
        System.out.println("m2 begin");
        try {
            m3();
            //m3()出现异常之后,后面的语句不会执行
            System.out.println("hello World!");
        } catch (FileNotFoundException e) {
            //出现异常之后直接进入catch语句块
            System.out.println("文件不存在");
        }
        //catch语句块处理完异常之后接着执行下面的语句
        System.out.println("m2 end");
    }

    private static void m3() throws FileNotFoundException {
        System.out.println("m3 begin");
        //创建一个输入流对象
        new FileInputStream("C:\\Users\\代涵\\Desktop\\java\\TesTXT.txt");
        //出异常之后,会立即上抛,并且后面的语句不会执行
        System.out.println("m3 end");

    }
}

catch可以是具体异常也可以是父异常

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class ExceptionTest07 {
    public static void main(String[] args) {
        /*try {
            FileInputStream fis = new FileInputStream("C:\\Users\\代涵\\Desktop\\java\\TestTXT.txt");
        }catch (FileNotFoundException e) {
            e.printStackTrace();
            System.out.println("文件不存在");
        }
        System.out.println("hello world");
         */
        try {
            FileInputStream fis = new FileInputStream("C:\\Users\\代涵\\Desktop\\java\\TestTXT.txt");
        }catch (IOException e) { //多态,IOException是FileNotFoundException父类
            System.out.println("文件不存在");
        }
        System.out.println("hello world");
    }
}

一个try可以多个catch,建议catch精确的一个一个处理
各个catch顺序:必须要先写子类,后写父类,否者先写父类 子类就用不到了

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class ExceptionTest07 {
    public static void main(String[] args) {
        
        try {
            FileInputStream fis = new FileInputStream("C:\\Users\\代涵\\Desktop\\java\\TestTXT.txt");
            fis.read();//还有异常需要处理
        }catch (FileNotFoundException e) {
            e.printStackTrace();
            System.out.println("文件不存在");
        }catch(IOException 3){
            System.out.println("读文件错误");
        }
        System.out.println("hello world");
    }
}

JDK8之后允许
catch(FileNotFoundException | ArithmeticException e){

}

异常对象有两个重要方法

获取简单的描述信息

打印异常追踪的堆栈信息

/*异常对象有两个重要方法
        获取简单的描述信息
        String msg = exception.getMessage();
        打印异常追踪的堆栈信息
        exception.printStackTrace();
    */
public class ExceptionTest08 {
    public static void main(String[] args) {
        //new了异常对象,但是没有抛出,JVM会认为这是一个简单的java对象
        NullPointerException e = new NullPointerException("空指针异常");
        //throw e;手动抛异常
        String msg=e.getMessage();
        System.out.println(msg);

        //打印异常信息是在另一个线程
        e.printStackTrace();
        System.out.println("hello World");
    }
}

例如:

import java.io.FileInputStream;
import java.io.FileNotFoundException;

public class ExceptionTest09 {
    public static void main(String[] args) {
        try {
            m1();
        } catch (FileNotFoundException e) {
            //IDEA自动生成会是打印堆栈信息
            //实际开发中建议这个
            e.printStackTrace();
        }
    }
    private static void m1() throws FileNotFoundException {
        m2();
    }

    private static void m2() throws FileNotFoundException {
        m3();
    }

    private static void m3() throws FileNotFoundException {
        new FileInputStream("C:\\Users\\Desktop\\java\\TestTXT.txt");
    }
}

try catch finally 重点

try 、catch 和 finally
try…catch中的finally子句:
finally子句代码是最后执行的,并且一定会执行,即使try语句块中的代码出现了异常
finally子句必须和try一起出现

通常使用在:
资源的释放/关闭。因为即使try中的语句出现异常,finally中的语句也能执行

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

/*
finally子句中的代码是最后执行的,并且一定会执行,即使try语句块中的代码出现了异常
通常使用在:
 */
public class ExceptionTest10 {
    public static void main(String[] args) {
        FileInputStream fis=null;
        try {
            //创建输入流对象
            fis=new FileInputStream("C:\\Users\\代涵\\Desktop\\java\\TestTXT.txt");
            //。。。
            //出现空指针异常
            String s=null;
            s.toString();
            //。。。
            //流使用完毕,需要关闭
            //即使以上代码出现问题,流也需要关闭。但是放在这里流就有可能关不了
            fis.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }catch(IOException e){
            e.printStackTrace();
        }catch(NullPointerException e) {
            e.printStackTrace();
        }finally {
            //流的关闭放在这里比较保险
            //即使try中出现了异常,也会执行
            //由于fis是在try语句块中声明的,所以访问不了,应该在外面声明
            if(fis!=null) {
                try {
                    //close方法有异常,采用捕捉的方式
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

可以只有try finally没有catch

public class ExceptionTest11 {
    public static void main(String[] args) {
        //只有try和finally没有catch
        //try不能单独使用
        try{
            System.out.println("try...");
            return;
        }finally {
            System.out.println("finally...");
        }
        //以上代码,先执行try再执行finally最后return
        System.out.println("hello"); //这里不能写,执行不到
    }
}

退出JVM之后finally子句不执行

public class ExceptionTest11 {
    public static void main(String[] args) {
        try{
            System.out.println("try...");
            System.exit(0);//退出JVM
        }finally {
            System.out.println("finally...");//不会再执行了
        }
    }
}

自定义异常

实际开发中的异常,JDK中很多都是没有的,和业务相关,这是需要我们自定义

步骤

1、编写一个类继承Exception(编译时,高频)或者RuntimeException(运行时,低频)
2、提供无参构造和带String 的构造方法

public class MyExcepotion extends Exception{
    public MyExcepotion(String message) {
        super(message);
    }

    public MyExcepotion() {
    }
}

异常与方法覆盖

重写之后的方法不能比重写之前的方法抛出更多(更广泛)的异常

//不能这么写
class Animals{
	public void doSome(){
	
	}
}

public class Cat extends Animals{
	public void doSome() throws Exception{
	}
}

可以这么写

class Animals{
	public void doSome() throw Exception{
	
	}
}

public class Cat extends Animals{
	public void doSome(){ //抛不抛出都可以,也可以抛出比父类所抛出异常类范围更小的异常
	}
}

throws和throw

throws在方法声明位置使用
throw手动抛出异常

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值