【JavaSE】异常

尚硅谷JavaSE笔记合集

文章名链接
【JavaSE】异常文章地址
【JavaSE】常用类:String、LocalDateTime…文章地址
【JavaSE】枚举文章地址
【JavaSE】注解文章地址
【JavaSE】集合框架文章地址 | HashMap源码解析 | List相关实现类源码解析
【JavaSE】泛型文章地址
【JavaSE】IO流文章地址 | 字符编码详解
【JavaSE】网络编程,BIO需求演进文章地址
【JavaSE】反射文章地址
【JavaSE】jdk8新特性文章地址

前言

编译时异常只是运行时异常的一种处理方式

- 异常的处理其实都是为了避免或处理运行时异常,让程序正常工作。
	①运行时异常的**避免**是需要通过修改代码实现的。
	②运行时异常的**处理**通过catch实现,让运行时异常出现后,保证后续代码能够正常运行

运行时异常:
	- 对于一定出现的,修改代码。
	- 对于可能出现的,想避免就需要修改代码增加判断;想出现之后再进行处理就try或throws。
编译时异常:作为运行时异常的一种处理方式,即运行时异常出现之后做善后处理
	- 想自己善后就try
	- 交给别人善后就throws

一、概述与体系结构

1.1 概述

异常事件可分为两类:

  • Error:Java虚拟机无法解决的严重问题。如:JVM系统内部错误、资源耗尽等严重情况。比如:StackOverflowError和OOM。一般不编写针对性的代码进行处理。

    /**
     * 引出异常概念
     */
    public class DrawForth {
        @Test
        public void erroDemo(){
            //1.栈溢出:java.lang.StackOverflowError。递归调用,没有出口
            erroDemo();
            //2.数组内存溢出:java.lang.OutOfMemoryError
    //        String strs[]=new String[1024*1024*1024];
        }
    }
    
  • Exception:其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。例如:

    • 空指针访问:
    • 试图读取不存在的文件
    • 网络连接中断
    • 数组角标越界

常见的两种解决方法:

  • 一是遇到错误就终止程序的运行。
  • 另一种方法是由程序员在编写程序时,就考虑到错误的检测、错误消息的提示,以及错误的处理。捕获错误最理想的是在编译期间,但有的错误只有在运行时才会发生。比如:除数为0,数组下标越界等

1.2 体系结构

  • 运行时异常
    • 是指编译器不要求强制处置的异常。一般是指编程时的逻辑错误,是程序员应该积极避免其出现的异常。
    • 对于这类异常,可以不作处理,因为这类异常很普遍,若全处理可能会对程序的可读性和运行效率产生影响。
  • 编译时异常
    • 是指编译器要求必须处置的异常。即程序在运行时由于外界因素造成的一般性异常。编译器要求Java程序必须捕获或声明所有编译时异常。
    • 对于这类异常,如果程序不处理,可能会带来意想不到的结果。

在这里插入图片描述

二、常见异常

/*
 * java.lang.Throwable
 * 		|----java.lang.Error:一般不编写针对性的代码进行处理
 * 		|----java.lang.Exception:可以进行异常处理
 * 			|----编译时异常(checked)
 * 				|----IOEXception
 * 					|----FileNotFoundException
 * 				|----ClassNotFoundException
 * 			|----运行时异常(unchecked)
 * 				|----NullPointerException				//空指针异常
 * 				|----ArrayIndexOutOfBoundsException		//数组索引越界
 * 				|----StringIndexOutOfBoundsException	//字符串索引越界
 * 				|----ClassCaseException		//类型转换异常
 * 				|----NumberFormatException	//数字转换异常
 * 				|----InputMismatchException	//输入不匹配异常
 * 				|----ArithmaticException	//算术异常
 * 
 * 面试题:常见的异常有哪些?举例说明
 * 
 */
public class ExceptionTest {
	// ArithmaticException:算术异常
	@Test
	public void test6() {
		int a = 10/0;
	}
	// InputMismatchException:输入不匹配异常:输入a
	@Test
	public void test5() {
		Scanner scanner = new Scanner(System.in);
		int score = scanner.nextInt();
	}
	// NumberFormatException:数字转换异常
	@Test
	public void test4() {
		String str = "abc";
		int num = Integer.parseInt(str);
	}
	// ClassCaseException:类型转换异常
	@Test
	public void test3() {
		 Object o = new Date();
		 String str = (String)obj;
	}
}

三、异常处理

3.1 try-catch-finally

3.1.1 try-catch

/*
 * 异常的处理:抓抛模型
 * 
 * 过程一:“抛”:程序在正常执行过程中,一旦出现异常,就会在异常代码处生成并抛出(throw)一个对应异常类的对象。若异常没有catch,其后的代码就不再执行。
 * 
 * 过程二:“抓”:可以理解为异常的处理方式:
 * 		① try-catch-finally:catch后代码正常执行
 * 		② throws:异常所在后续代码不再执行
 * 
 */
  • 体会1:使用try-catch-finally处理编译时异常,是得程序在编译时就不再报错,但是运行时仍可能报错。
    • 即不是避免了异常,而是如果出现异常的善后处理。
    • 相当于出现运行时异常,而想要彻底解决则是修改代码。
  • 体会2:开发中,由于运行时异常比较常见,所以我们通常就不针对运行时异常编写try-catch-finally了。
    • 而想要彻底解决则是修改代码。

注意

  • catch中的异常类型如果满足子父类关系,则要求子类一定声明在父类的上面。否则,报错
  • 在try结构中声明的变量,出了try结构,就不能再被调用
/*
 * try{
 * 		//可能出现异常的代码
 * }catch(异常类型1 变量名1){
 * 		//处理异常的方式1
 * }catch(异常类型2 变量名2){
 * 		//处理异常的方式2
 * }catch(异常类型3 变量名3){
 * 		//处理异常的方式3
 * }
 * ...
 * finally{
 * 		//一定会执行的代码
 * }
 */

3.1.2 finally

  • 作用:一定会被执行的代码
    • 即使catch中又出现异常了
    • try 或 catch 中有 return 语句等情况。
  • 场景:
    • 像数据库连接、输入输出流、网络编程Socket等资源,JVM是不能自动的回收的,我们需要自己手动的进行资源的释放。此时的资源释放,就需要声明在finally中。

3.2 throws

  • 体会1:
    • try-catch-finally:真正的将异常给处理了,让后续代码能够继续运行
    • throws:该方法产生了异常,只是将异常抛给了方法的调用者。异常代码后续的代码不再执行!
  • 关于异常对象的产生:
    • 系统自动生成的异常对象
    • 手动生成一个异常对象,并抛出(throw)

3.3 方法重写异常throws

/*
 * 方法重写的规则之一:
 * 		子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型。
 * 
 */
public class OverrideTest {
    public static void main(String[] args) {
        OverrideTest overrideTest=new OverrideTest();
        overrideTest.doSomething(new Child());
    }
    public void doSomething(Super s){
        try {
            s.demo();
        } catch (IOException e) {			//如果是子类引用,且异常类型大于父类的异常类型。那么该catch起不到作用。所以有了重写对应的规则
            e.printStackTrace();
        }
    }
}
class Super{
    public void demo()throws IOException {

    }
}
class Child extends Super{
    public void demo(){

    }
}

3.4 如何选择?

/* 开发中如何选择使用try-catch-finally 还是使用throws?
 *   1 如果父类中被重写的方法没有throws方式处理异常,则子类重写的方法也不能使用throws,意味着如果
 *     子类重写的方法中有异常,必须使用try-catch-finally方式处理。
 *   2 执行的方法a中,先后又调用了另外的几个方法,这几个方法是递进关系执行的。我们建议这几个方法使用throws
 *     的方式进行处理。而执行的方法a可以考虑使用try-catch-finally方式进行处理。
 */

四、手动抛出异常

关于异常对象的产生:

  • 系统自动生成的异常对象
  • 手动生成一个异常对象,并抛出(throw)
    • 编译时异常:除RuntimeException及其子类
public class ThrowTest {
    public static void main(String[] args) {
        ThrowTest throwTest=new ThrowTest();
        throwTest.doSomething(new ThrowDemo());
    }
    public void doSomething(ThrowDemo throwDemo){
//        try {
            throwDemo.demo();
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
    }
}
class ThrowDemo{
    public void demo(){
        Scanner in=new Scanner(System.in);
        System.out.println("请输入不小于0的数:");
        int next = in.nextInt();//可能出现运行时异常:输入类型异常
        if(next<0){
            //运行时异常
//            throw new Exception("输入的数小于0!");
            throw new RuntimeException("输入的数小于0!");
        }else {
            System.out.println("输入正确!");
        }
    }
}

五、自定义异常类

  • 用户自定义异常类一般都是RuntimeException
  • 通常需要编写几个重载的构造器
  • 需要提供serialVersionUID
  • 自定义异常最重要的是异常类的名字,当异常出现时,可以根据名字判断异常类型。
/*
 * 如何自定义异常类?
 * 1.继承于现有的异常结构:RuntimeException 、Exception
 * 2.提供全局常量:serialVersionUID
 * 3.提供重载的构造器
 * 
 */
public class NumberLessThanZeroException extends RuntimeException{
    static final long serialVersionUID = -7034897199819366939L;

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

在这里插入图片描述

六、练习

/*
 * 编写应用程序TestDemo.java,接收命令行的两个参数,要求:不能输入负数,计算两数相除
 * 		输入负数:NumberLessThanZeroException
 * 		数字类型不一致:NumberFormatException(int a= Integer.parseInt(args[0]);)
 * 		缺少命令行参数:ArrayIndexOutOfBoundsException
 * 		除0:ArithmeticException
 *
 */
public class TestDemo {
    //    (1)在主类(TestDemo)中定义异常方法(ecm)完成两数相除功能。a/b
    public static int ecm(int a,int b){
        if(a<0 || b<0){
            throw new NumberLessThanZeroException("输入小于0");
        }
        return a/b;
    }
    //     (2)在main()方法中使用异常处理语句进行异常处理。
    public static void main(String[] args) {
        try {
            int a= Integer.parseInt(args[0]);
            int b= Integer.parseInt(args[1]);
            int ecm = ecm(a, b);
            System.out.println(a+"/"+b+"="+a/b);
        } catch (NumberFormatException e) {
            System.out.println("数字类型不一致");
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("缺少命令行参数");
        } catch (ArithmeticException e) {
            System.out.println("被除数为0");
        } catch (NumberLessThanZeroException e){
            System.out.println(e.getMessage());
        }

    }

}
//(3)在程序中,自定义对应输入负数的异常类(NumberLessThanZeroException)。
class NumberLessThanZeroException extends RuntimeException{
    static final long serialVersionUID = -7034897199819366939L;

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

    public NumberLessThanZeroException() {
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

愿你满腹经纶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值