Java-异常

异常概述

异常就是Java程序在运行过程中出现的错误。

Java中的异常类都继承自java.lang.Throwable。

这里写图片描述

  • Error类称为错误类,它表示Java运行时产生的系统内部错误或资源耗尽的错误,是比较严重的,仅靠程序本身是不能恢复执行的。
  • Exception类称为异常类,它表示程序本身可以处理的错误,在开发Java程序中进行的异常处理,都是针对Exception类及其子类。在Exception类的众多子类中有一个特殊的RuntimeException类,该类及其子类用于表示运行时异常,除了此类,Exception类下所有其他的子类都用于表示编译时异常。

JVM默认处理异常的方式:

main函数遇到问题时,有两种处理方式:自己将该问题处理,然后继续运行。自己没有针对的处理方式,只有交到调用main的JVM来处理。JVM有一个默认的异常处理机制,就将该异常处理,并将该异常的名称,异常信息,异常出现的位置打印在了控制台上,同时将程序停止运行。

package com.first;

public class HelloWorld {

    public static void main(String[] args) {

        int result = 0;
        result = 4 / 0;
        System.out.println(result);

    }

}

控制台显示的内容为

Exception in thread "main" java.lang.ArithmeticException: / by zero
    at com.first.HelloWorld.main(HelloWorld.java:8)

Throwable的常见方法

  • getMessage():获取异常信息,返回字符串
  • toString():获取异常类名和异常信息,返回字符串
  • printStackTrace():获取异常类名和异常信息,以及异常出现在程序中的位置。返回值void

这些方法用于获取异常信息。由于Error和Exception继承自Throwable类,所以它们都拥有这些方法。

try…catch

由于发生了异常,程序立即终止,无法继续向下执行。为了解决这样的问题,Java中提供了一种对异常进行处理的方式—异常捕获。

try:用来检测异常。

catch:用来捕获异常。

try{
  //程序代码块
}catch(ExceptionType(Exception类及其子类) e){
  //对ExceptionType的处理
}

在try代码中编写可能发生异常的Java语句,catch代码块中编写针对异常进行处理的代码。当try代码块中发生了异常,系统会将这个异常的信息封装成一个异常对象,并将这个对象传递给catch代码块。catch代码块需要一个参数指明它所能够接受的异常类型,这个参数必须是Exception类或其子类。

package com.first;

public class HelloWorld {

    public static void main(String[] args) {

        int result = 0;
        try {
            result = 4 / 0;
            System.out.println("-----");
        } catch (Exception e) {         //Exception e=new ArithmeticException();

            System.out.println("进入到catch中");
            System.out.println(e.getMessage());
            System.out.println(e.toString());
            e.printStackTrace();
        }
        System.out.println(result);

    }

}

控制台的内容为

进入到catch中
/ by zero
java.lang.ArithmeticException: / by zero
java.lang.ArithmeticException: / by zero
    at com.first.HelloWorld.main(HelloWorld.java:9)
0

在try代码块中发生被0除异常,程序会转而执行catch的代码。catch代码块对异常处理完毕后,程序仍会向下执行,而不会异常终止。

需要注意的是,在try代码块中,发生异常语句后面的代码是不会被执行的。本例中第10行代码的打印语句就没有执行。并且如果try中没有发生异常,不会走catch代码块。

try…跟多个catch

package com.first;

public class HelloWorld {

    public static void main(String[] args) {

        int a = 10;
        int b = 0;
        int[] arr = { 11, 22, 33, 44 };

        try {
            System.out.println(a / b);                //除0异常
            System.out.println(arr[10]);              //索引越界异常
            arr = null;
            System.out.println(arr[0]);               //空指针异常
        } catch (ArithmeticException e) {             //ArithmeticException e=new ArithmeticException();
            System.out.println("除数不能为零");
        } catch (ArrayIndexOutOfBoundsException e) {  //ArrayIndexOutOfBoundsException e=new ArrayIndexOutOfBoundsException();
            System.out.println("索引越界了");
        } catch (Exception e) {                       //Exception e=new NullPointerException();
            System.out.println("出错了");
        }
        System.out.println("over");

    }

}

运行结果为

除数不能为零
over

第12行代码出错之后,第一个catch就会执行,后面的catch不会执行。

如果把13行代码注释掉,会执行第二个catch。

如果把第12,13行代码注释掉,会执行最后一个catch,Exception可以接收所有异常。多态的应用

JDK7有个新特性,可以一次catch多种异常,但好像也没什么卵用。

try {
            System.out.println(a / b);                //除0异常
            System.out.println(arr[10]);              //索引越界异常
            arr = null;
            System.out.println(arr[0]);               //空指针异常
        } catch (ArithmeticException|ArrayIndexOutOfBoundsException e) {             //ArithmeticException e=new ArithmeticException();
            System.out.println("除数不能为0或索引越界异常");
        } catch (Exception e) {                       //Exception e=new NullPointerException();
            System.out.println("出错了");
        }

throws关键字

如果调用自己的方法,应该很清楚该方法可能会发生异常。但如果去调用一个别人写的方法时,无法判断是否会有异常。针对这种情况,Java中允许在方法的后面使用throws关键字对外声明该方法可能发生的异常,这样调用者在调用方法时,就明确地知道该方法有异常,并且必须在程序中对异常进行处理,否则编译无法通过。

修饰符 返回值类型 方法名([参数1,参数2···]) throws ExceptionType1[,ExceptionType2···]{
}

throws关键字需要写在方法声明的后面,throws后面需要声明方法中发生异常的类型,通常将这种做法称为方法声明抛出一个异常。

package com.first;

public class HelloWorld {

    public static void main(String[] args) {

        int result=divide(4,2);
        System.out.println(result);

    }

    private static int divide(int x,int y) throws Exception{

        int result=x/y;
        return result;
    }

}

其中第7行代码int result=divide(4,2);,调用divide()方法时传入的第二个参数为2,程序在运行时不会发生被0除的异常,但是由于定义divide()方法时声明抛出了异常,调用者在调用divide()方法时就必须进行处理,否则就会发生编译错误。

package com.first;

public class HelloWorld {

    public static void main(String[] args) {

        try {
            int result=divide(4,2);
            System.out.println(result);
        } catch (Exception e) {

            e.printStackTrace();
        }

    }

    private static int divide(int x,int y) throws Exception{

        int result=x/y;
        return result;
    }

}

这样处理后就不会报错了,运行结果为2

当在调用divide()方法时,如果不知道如何处理声明抛出的异常,也可以使用throws关键字继续将异常抛出,,这样程序也能编译通过,但需要注意的是,程序一旦发生异常,如果没有被处理,程序就会被非正常终止。

编译时异常和运行时异常

在Java中,Exception类中除了RuntimeException类及其子类都是编译时异常。编译时异常的特点是Java编译期会对其进行检查,如果出现异常就必须对异常进行处理,否则程序无法通过编译。用try…catch语句进行捕获或用throws关键字声明抛出异常,调用者对其处理。

RuntimeException类及其子类都是运行时异常。运行时异常的特点是Java编译器不会对其进行检查,也就是说,当程序中出现这类异常时,即使没有处理,程序也能编译通过。

FileInputStream fis=new FileInputStream("test.txt");

这句话就会发生编译时异常,必须要对其进行处理。因为到时候可能找不到这个文件。

自定义异常

为什么需要自定义异常?

方便查找错误。如果报的异常都显示为Exception,我哪儿知道是啥错误。

现在自定义一个异常,如果被除数为负数,就抛出异常。

package com.first;

public class HelloWorld {

    public static void main(String[] args) {
            try {
                int result=divide(4,-2);
                System.out.println(result);
            } catch (DivideByMinusException e) {

                e.printStackTrace();
            }


    }
    public static int divide(int x,int y)throws DivideByMinusException{
        if (y<0) {
            throw new DivideByMinusException("被除数是负数");
        }
        return x/y;
    }

}

class DivideByMinusException extends Exception{
    public DivideByMinusException() {
        super();
    }

    public DivideByMinusException(String message) {
        super(message);
    }
}

运行结果为

com.first.DivideByMinusException: 被除数是负数
    at com.first.HelloWorld.divide(HelloWorld.java:18)
    at com.first.HelloWorld.main(HelloWorld.java:7)

throw关键字用于在方法中声明抛出异常的实例对象,在一个方法内使用throw关键字抛出异常对象时,需要使用try…catch语句对抛出的异常进行处理,或者在方法上使用throws关键字声明抛出异常,由该方法的调用者负责处理。

finally关键字

有时候我们希望有些语句无论程序是否发生异常都要执行,这时就可以在try···catch语句后,加一个finally代码块。

public class HelloWorld {

    public static void main(String[] args) {
        try {
            int result=divide(4,0);
            System.out.println(result);
        } catch (Exception e) {
            System.out.println("捕获的异常信息为"+e.getMessage());
            return;
        }finally{
            System.out.println("进入finally代码块");
        }

        System.out.println("程序继续向下执行···");
    }

    private static int divide(int x, int y) {
        int result=x/y;
        return result;
    }

}

运行结果为

捕获的异常信息为/ by zero
进入finally代码块

在catch代码块中增加了一个return语句,用于结束当前方法,此时程序第14行代码就不会执行了,而finally中的代码仍会执行,并不会被return语句所影响,也就是说无论程序是发生异常还是使用return语句结束,finally中的语句都会执行,在程序设计时,经常会在try···catch后使用finally代码块来完成必须做的事情,例如释放系统资源。

需要注意的是,finally中的代码有一种情况下是不会执行的,那就是在try···catch中执行了System.exit(0)语句。System.exit(0)表示退出当前的Java虚拟机,Java虚拟机停止了,任何代码都不能再执行了。

一般finally用于释放资源,在IO流操作和数据库操作中会经常用到。

总结

加try,catch并不是为了解决bug问题,如果你在调试阶段,不加try,反而更容易找到bug在哪里,编译器就会自动断点在出问题的代码行上,省了你自己翻日志还找不到具体的原因。

而如果真正运行,很多情况都会导致底层抛出异常,这些一般都是IO操作引起的,比如写文件失败,连接数据库失败,连接以太网失败,以太网读取数据超时。所有IO操作,都依赖于外部设备,跟你自己的代码关系不大(除非有严重BUG),在通信之前,没法预测本次通信到底能不能通的上。类似这种问题,就应该通过try捕获异常,然后程序自动进行重试,而不是遇到啥P大的问题都给用户弹出个对话框,用户看不懂,也不知道该如何解决,这种异常写进文件也没用.因为是很正常的现象,而不是什么bug

能够预知到错误发生的类型,但是无法预知到什么时候会出现问题,所以需要加try,在catch里代码解决能预测的类型,当然最后无法预知的类型也要捕获,这部分可能就需要通过弹出错误信息,写日志,事后来补救了。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 13
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值