java基础学习之异常

java基础学习之异常

java异常概述

异常就是有问题的意思。

Throwable类下有两个子类:
Error和Exception
异常不是语法错误。

Exception:是异常
分为编译期异常和运行时异常(runtimeException)
编译期异常:编译的时候产生的异常。
必须处理,可以自己处理(try-catch语句块)或者自己不处理交给别人处理(throws关键字声明异常)。
运行时异常:运行的时候产生的异常。
异常处理完后后续代码会继续运行。可以不处理默认交给JVM处理。

import java.text.ParseException;
import java.text.SimpleDateFormat;

public class ExceptionTest {
    public static void main(String[] args)  {
        SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd");
        try {
            sd.parse("2012-1221");//java.text.ParseException
        } catch (ParseException e) {
            System.out.println(e);
        }
        int[] array = new int[]{1,2,3};
        try{
            System.out.println(array[3]);//java.lang.ArrayIndexOutOfBoundsException
        } catch (Exception e) {
            System.out.println(e);//java.lang.ArrayIndexOutOfBoundsException: 3
        }
        System.out.println("后续代码");//异常处理后后续代码正常输出
    }
}

Error:错误
Error无法预先处理,出现时必须修改代码。

例子:

public class ExceptionTest {
    public static void main(String[] args)  {
        int[] array = new int[1024*1024*1024];//Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        System.out.println("hello");
    }
}

异常的产生过程解析:

在这里插入图片描述
throw关键字:在指定的方法中抛出异常对象。
注意:
1、throw new XxxException();
throw后面只能new一个Exception类对象或者其子类对象。
2、throw关键字只能写在方法的内部。

throws关键字:声明异常
注意:
1、写在方法声明处
2、方法内部如果抛出了多个异常对象,throws声明时也必须声明多个异常,如果抛出的多个异常对象有父子关系,那么直接声明父类异常对象即可。
3、调用了一个声明抛出异常对象的方法,我们就必须处理声明的异常。要么继续使用throws声明抛出,交给方法的调用者处理,最终交给JVM处理,要么使用try-catch处理。

如果交由JVM来处理,JVM会进行中断处理,并打印异常信息(内容,原因,位置)。

try-catch处理异常举例;

public class ThrowsTest {
    public static void main(String[] args) {
        try{
            findFile("c:\\a.tx");//可能会产生异常的代码
        } catch (IOException e) {//捕获异常对象
            System.out.println("处理了");//做出处理
        }
        System.out.println("后续代码");//try-catch处理后后续代码会继续执行
    }

    private static void findFile(String fileName) throws IOException {
        if(!fileName.equals("c:\\a.txt")){
            throw new FileNotFoundException("找不到这个文件");//这是编译时异常,必须处理,有两个选择,自己处理,或者自己不处理,交给别人处理
        }
        if(!fileName.endsWith(".txt")){
            throw new IOException("文件后缀不对");
        }
        System.out.println("后续代码2");//抛出异常的方法,后续的代码不会继续执行
    }
}

Throwable类的3个异常处理的方法:
String getMessage() 返回异常的详细信息
String toString()返回异常的详细消息
void printStackTrace()打印异常的最详细信息,JVM打印异常信息时默认调用此方法

//            System.out.println(e.getMessage());//找不到这个文件
//            System.out.println(e.toString());//java.io.FileNotFoundException: 找不到这个文件
            e.printStackTrace();//java.io.FileNotFoundException: 找不到这个文件
//                                 at com.pan.demo12.ThrowsTest.findFile(ThrowsTest.java:21)
//                                  at com.pan.demo12.ThrowsTest.main(ThrowsTest.java:10)

如果一个try对应多个catch,catch中定义的异常变量存在父子类关系,子类异常变量应该定义在上面,否则会报错。
因为try中抛出的异常会从上往下进行匹配,如果父类异常变量在上面,子类异常会直接匹配到父类异常变量,下面的定义的子类异常变量就会毫无作用,报错。

public class ManyExceptionTest {
    public static void main(String[] args) {
        try{
            int[] array = new int[]{1,2,3};
            System.out.println(array[3]);
            ArrayList<Integer> arrayList = new ArrayList<>();
            arrayList.add(1);
            System.out.println(arrayList.get(1));
        } catch (ArrayIndexOutOfBoundsException e) {
            e.printStackTrace();
        }catch (IndexOutOfBoundsException e){
            e.printStackTrace();
        }
    }
}

finally代码块
有一些特定的代码无论异常是否发生,都需要执行,另外因为异常会引发程序跳转导致有些语句执行不到,而finally就是解决这个问题的,在finally代码块中存放的代码都是最终一定会执行的。
注意:finally不能单独使用。

那么什么时候的代码必须最终执行呢?
当我们在try语句块中打开了一些物理资源(磁盘文件/网络链接/数据库链接等),我们都得在使用完之后,最终关闭打开的资源。

try{
可能会出现异常的代码
}catch(Exception e){
异常的处理逻辑,异常对象产生后怎么处理异常,一般在工作中,会把异常信息记录到一个日志中

}finally{
无论是否抛出异常,finally代码块内的语句都会执行
finally一般用于资源释放,无论程序是否出现异常,程序都要资源释放。
}
:自身不但需要处理异常,最终还得关闭资源。

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

public class ThrowsTest {
    public static void main(String[] args) {
        try{
            findFile("c:\\a.tx");//可能会产生异常的代码
        } catch (IOException e) {//捕获异常对象
            e.printStackTrace();//java.io.FileNotFoundException: 找不到这个文件
        }finally{
            System.out.println("资源释放");
        }
        System.out.println("后续代码1");//try-catch处理后后续代码会继续执行
    }

    private static void findFile(String fileName) throws IOException {
        if(!fileName.equals("c:\\a.txt")){
            throw new FileNotFoundException("找不到这个文件");//这是编译时异常,必须处理,有两个选择,自己处理,或者自己不处理,交给别人处理
        }
        if(!fileName.endsWith(".txt")){
            throw new IOException("文件后缀不对");
        }
        System.out.println("后续代码2");//抛出异常的方法,后续的代码不会继续执行
    }
    /*
    执行结果:
    java.io.FileNotFoundException: 找不到这个文件
	at com.pan.demo12.ThrowsTest.findFile(ThrowsTest.java:25)
	at com.pan.demo12.ThrowsTest.main(ThrowsTest.java:10)
    资源释放
    后续代码1
     */
}

如果finally中有return语句,因为无论异常是否出现,finally都一定会执行,所以最后返回的一定是finally中的内容,要避免这种情况,除非你原本就想返回在finally中的内容。

public class FinallyTest {
    public static void main(String[] args) {
        int method = method();
        System.out.println(method);
    }

    private static int method() {
        int a;
        try{
            a= 10;
            return a;
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            a = 100;
            return a;
        }
    }
    /*
    执行结果:
        100
     */
}

子父类的异常:

  • 如果父类抛出了多个异常,子类重写父类方法时,抛出和父类相同的异常或者是父类异常的子类异常或者不抛出异常。
  • 父类方法没有抛出异常,子类重写该方法时也不可抛出异常,此时子类产生该异常,只能捕获处理,不能声明抛出。

注意:
子类重写父类的方法抛出的异常范围不能比父类大。

这个就和java重写规则有关了。

public class ZiFuException {
    public void method1() throws IndexOutOfBoundsException{}
    public void method2() throws IndexOutOfBoundsException{}
    public void method3() throws IndexOutOfBoundsException{}
    public void method4(){}
}
class zi extends ZiFuException{
    //父类方法抛出异常,子类重写该方法时可以抛出相同的异常
    @Override
    public void method1() throws IndexOutOfBoundsException{
        super.method1();
    }
    //父类方法抛出异常,子类重写该方法时可以抛出父类异常的子类异常
    @Override
    public void method2() throws ArrayIndexOutOfBoundsException {
        super.method2();
    }
    //父类方法抛出异常,子类重写该方法时可以不抛出异常
    @Override
    public void method3() throws IndexOutOfBoundsException {
        super.method3();
    }
    //父类方法没有抛出异常,子类重写该方法时也不可以抛出异常,如果此时方法内部抛出异常,只能用try-catch处理。
    @Override
    public void method4() {
        super.method4();
        try{
            throw new IndexOutOfBoundsException("try-catch处理异常");
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

自定义异常类
Java提供的异常类,不够我们使用,需要自己定义一些异常类
格式:
public class XxxException extends Exception / RuntimeException{

}

注意:
1、自定义异常类一般都是以Exception结尾,说明该类是一个异常类
2、自定义异常类,必须继承Exception 或者RuntimeException
继承Exception:那么自定义异常类就是一个编译期异常,如果方法内部抛出了编译期异常,就必须处理这个异常,要么throws,要么try-catch处理。
继承RuntimeException:那么自定义的异常类就是一个运行期异常,无需处理,交给虚拟机处理(终端处理)

自定义异常类举例如下:

public class RegisterException extends Exception {
    public RegisterException(){
        super();
    }
    /*
    添加一个带异常信息的构造方法
    查看源码发现,所有的异常类都会有一个带异常信息的构造方法,方法内部会调用父类带异常信息的构造方法,让父类来处理这个异常信息
     */
    public RegisterException(String string){
        super(string);
    }
}

添加一个带异常信息的构造方法
查看源码发现,所有的异常类都会有一个带异常信息的构造方法,方法内部会调用父类带异常信息的构造方法,让父类来处理这个异常信息

以IndexOutOfBoundsException源码为例:

class IndexOutOfBoundsException extends RuntimeException {
    private static final long serialVersionUID = 234122996006267687L;

    /**
     * Constructs an <code>IndexOutOfBoundsException</code> with no
     * detail message.
     */
    public IndexOutOfBoundsException() {
        super();
    }

    /**
     * Constructs an <code>IndexOutOfBoundsException</code> with the
     * specified detail message.
     *
     * @param   s   the detail message.
     */
    public IndexOutOfBoundsException(String s) {
        super(s);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值