Java全栈学习day08(异常)

1、基本概念

异常指程序运行过程中出现的非正常现象,例如用户输入错误、除数为零、需要处理的文件不存在、数组下标越界等。

在Java的异常处理机制中,引进了很多用来描述和处理异常的类,称为异常类。异常类定义中包含了该类异常的信息和对异常进行处理的方法。

所谓异常处理,就是指程序在出现问题时依然可以正确的执行完。

Java是采用面向对象的方式来处理异常的。处理过程:

1. 抛出异常: 在执行一个方法时,如果发生异常,则这个方法生成代表该异常的一个对象,停止当前执行路径,并把异常对象提交给JRE。

2. 捕获异常: JRE得到该异常后,寻找相应的代码来处理该异常。JRE在方法的调用栈中查找,从生成异常的方法开始回溯,直到找到相应的异常处理代码为止。

2、异常分类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ksyoe6mL-1652341377654)(TyporaIMG/Java%E5%85%A8%E6%A0%88%E5%AD%A6%E4%B9%A0day08%EF%BC%88%E5%BC%82%E5%B8%B8%EF%BC%89/1495272017528669.png)]

  1. Error

    Error是程序无法处理的错误,表示运行应用程序中较严重问题。大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVM(Java 虚拟机)出现的问题。

    Error表明系统JVM已经处于不可恢复的崩溃状态中。我们不需要管它。

  2. Exception

    Exception是程序本身能够处理的异常,如:空指针异常(NullPointerException)、数组下标越界异常(ArrayIndexOutOfBoundsException)、类型转换异常(ClassCastException)、算术异常(ArithmeticException)等。

    Exception类是所有异常类的父类,其子类对应了各种各样可能出现的异常事件。 通常Java的异常可分为:

    1. RuntimeException 运行时异常

      注意:

      1. 在方法抛出异常之后,运行时系统将转为寻找合适的异常处理器(exception handler)。潜在的异常处理器是异常发生时依次存留在调用栈中的方法的集合。当异常处理器所能处理的异常类型与方法抛出的异常类型相符时,即为合适的异常处理器。

      2. 运行时系统从发生异常的方法开始,依次回查调用栈中的方法,直至找到含有合适异常处理器的方法并执行。当运行时系统遍历调用栈而未找到合适的异常处理器,则运行时系统终止。同时,意味着Java程序的终止。

    2. CheckedException 已检查异常

      这类异常在编译时就必须做出处理,否则无法通过编译。

  3. Error和Exception区别

    1. 我开着车走在路上,一头猪冲在路中间,我刹车。这叫一个异常。

    2. 我开着车在路上,发动机坏了,我停车,这叫错误。系统处于不可恢复的崩溃状态。发动机什么时候坏?我们普通司机能管吗?不能。发动机什么时候坏是汽车厂发动机制造商的事。

3、异常处理

  1. 捕获异常:获异常是通过3个关键词来实现的:try-catch-finally。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WZNR66TB-1652341377655)(TyporaIMG/Java%E5%85%A8%E6%A0%88%E5%AD%A6%E4%B9%A0day08%EF%BC%88%E5%BC%82%E5%B8%B8%EF%BC%89/1495273755315926.png)]

    1. try:

    try语句指定了一段代码,该段代码就是异常捕获并处理的范围。在执行过程中,当任意一条语句产生异常时,就会跳过该条语句中后面的代码。代码中可能会产生并抛出一种或几种类型的异常对象,它后面的catch语句要分别对这些异常做相应的处理。

    一个try语句必须带有至少一个catch语句块或一个finally语句块 。

    注意事项

    当异常处理的代码执行结束以后,不会回到try语句去执行尚未执行的代码。

    2. catch:

    每个try语句块可以伴随一个或多个catch语句,用于处理可能产生的不同类型的异常对象。

    • 常用方法,这些方法均继承自Throwable类 。
      toString ()方法,显示异常的类名和产生异常的原因
      getMessage()方法,只显示产生异常的原因,但不显示类名。
      printStackTrace()方法,用来跟踪异常事件发生时堆栈的内容。
    • catch捕获异常时的捕获顺序:
      ​ 如果异常类之间有继承关系,在顺序安排上需注意。越是顶层的类,越放在下面,再不然就直接把多余的catch省略掉。 也就是先捕获子类异常再捕获父类异常。

    2. finally:

    n-有些语句,不管是否发生了异常,都必须要执行,那么就可以把这样的语句放到finally语句块中。

    n-通常在finally中关闭程序块已打开的资源,比如:关闭文件流、释放数据库连接等。

    try-catch-finally语句块的执行过程:

    try-catch-finally程序块的执行流程以及执行结果比较复杂。

    基本执行过程如下:

    程序首先执行可能发生异常的try语句块。如果try语句没有出现异常则执行完后跳至finally语句块执行;如果try语句出现异常,则中断执行并根据发生的异常类型跳至相应的catch语句块执行处理。catch语句块可以有多个,分别捕获不同类型的异常。catch语句块执行完后程序会继续执行finally语句块。finally语句是可选的,如果有的话,则不管是否发生异常,finally语句都会被执行。

    注意:

    1. 即使try和catch块中存在return语句,finally语句也会执行。是在执行完finally语句后再通过return退出。
    2. finally语句块只有一种情况是不会执行的,那就是在执行finally之前遇到了System.exit(0)结束程序运行。
  2. 声明异常(throws子句)

    当CheckedException产生时,不一定立刻处理它,可以再把异常throws出去。

    注意事项

    1. 方法重写中声明异常原则:子类重写父类方法时,如果父类方法有声明异常,那么子类声明的异常范围不能超过父类声明的范围。

4、自定义异常

  1. 在程序中,可能会遇到JDK提供的任何标准异常类都无法充分描述清楚我们想要表达的问题,这种情况下可以创建自己的异常类,即自定义异常类。

  2. 自定义异常类只需从Exception类或者它的子类派生一个子类即可。

  3. 自定义异常类如果继承Exception类,则为受检查异常,必须对其进行处理;如果不想处理,可以让自定义异常类继承运行时异常RuntimeException类。

  4. 习惯上,自定义异常类应该包含2个构造器:一个是默认的构造器,另一个是带有详细信息的构造器。

使用异常机制的建议

  1. 要避免使用异常处理代替错误处理,这样会降低程序的清晰性,并且效率低下。

  2. 处理异常不可以代替简单测试—只在异常情况下使用异常机制。

  3. 不要进行小粒度的异常处理—应该将整个任务包装在一个try语句块中。

  4. 异常往往在高层处理(先了解!后面做项目会说!) 。

5、练习题

一、选择题

1.以下关于异常的代码的执行结果是( C)。(选择一项)

public class Test {
    public static void main(String args[]) {
        try {
            System.out.print("try");           
            return;
        } catch(Exception e){
            System.out.print("catch");
        }finally {
            System.out.print("finally");
        }
    }
}

A.try catch finally

B.catch finally

C.try finally

D.try

2.在异常处理中,如释放资源、关闭文件等由( C)来完成。(选择一项)

Atry子句

B.catch子句

C.finally子句

D.throw子句

3.阅读如下Java代码,其中错误的行是(AC )。(选择二项)

public class Student {
    private String stuId;
    public void setStuId(String stuId) throw Exception { // 1
        if (stuId.length() != 4) { // 2
            throws new Exception("学号必须为4位!"); // 3
        } else {
            this.stuId = stuId;     //4
        }
    }
}

A.1

B.2

C.3

D.全部正确

4.下面选项中属于运行时异常的是(BC )。(选择二项)

A.Exception和SexException

B.NullPointerException和InputMismatchException

C.ArithmeticException和ArrayIndexOutOfBoundsException

D.ClassNotFoundException和ClassCastException

5.阅读如下Java代码,在控制台输入"-1",执行结果是(B)。(选择一项)

public class Demo {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        System.out.print("请输入数字:");
        try {
            int num = input.nextInt();
            if (num < 1 || num > 4) {
                throw new Exception("必须在1-4之间!");
            }
        } catch (InputMismatchException e) {
            System.out.println("InputMismatchException");
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
}

A.输出:InputMismatchException

B.输出:必须在1-4之间!

C.什么也没输出

D.编译错误

二、简答题

  1. Error和Exception的区别。

    Error:
    Error(错误)是系统中的错误,程序员是不能改变的和处理的,是在程序编译时出现的错误,只能通过修改程序才能修正。一般是指与虚拟机相关的问题,如系统崩溃,虚拟机错误,内存空间不足,方法调用栈溢等。对于这类错误的导致的应用程序中断,仅靠程序本身无法恢复和和预防,遇到这样的错误,建议让程序终止。

    Exception:
    Exception(异常)表示程序可以处理的异常,可以捕获且可能恢复。遇到这类异常,应该尽可能处理异常,使程序恢复运行,而不应该随意终止异常。

  2. Checked异常和Runtime异常的区别。

    1、运行时异常:包括RuntimeException及其所有子类。不要求程序必须对它们作出处理,比如InputMismatchException、ArithmeticException、NullPointerException等。即使没有使用try-catch或throws进行处理,仍旧可以进行编译和运行。如果运行时发生异常,会输出异常的堆栈信息并中止程序执行。
    2、Checked异常(非运行时异常):除了运行时异常外的其他异常类都是Checked异常。程序必须捕获或者声明抛出这种异常,否则出现编译错误,无法通过编译。处理方式包括两种:通过try-catch捕获异常,通过throws声明抛出异常从而交给上一级调用方法处理。

  3. Java异常处理中,关键字try、catch、finally、throw、throws分别代表什么含义?

    try 用来指定一块预防所有“异常”的程序;

    catch 子句紧跟在 try 块后面,用来指定你想要捕捉的“异常”的类型;

    throw 语句用来明确地抛出一个“异常”;

    throws 用来标明一个成员函数可能抛出的各种“异常”;

    Finally 为确保一段代码不管发生什么“异常”都被执行一段代码;

  4. throws和throw的区别。

    throw语句用在方法体内,表示抛出异常,由方法体内的语句处理。
    throws语句用在方法声明后面,表示再抛出异常,由该方法的调用者来处理。

    throws主要是声明这个方法会抛出这种类型的异常,使它的调用者知道要捕获这个异常。
    throw是具体向外抛异常的动作,所以它是抛出一个异常实例。

    throws说明你有那个可能,倾向。
    throw的话,那就是你把那个倾向变成真实的了。

三、编码题

  1. 编写程序接收用户输入分数信息,如果分数在0—100之间,输出成绩。如果成绩不在该范围内,抛出异常信息,提示分数必须在0—100之间。

要求:使用自定义异常实现。

package com.zry.day08.lx;

import java.util.Scanner;

public class Test1 {
	public static void main(String[] args) {
		Scanner scanner=new Scanner(System.in);
		System.out.println("请输入用户分数:");
		double grade=scanner.nextDouble();
		Grade g=new Grade();
		try {
			g.setGrade(grade);
			g.printGrade();
		} catch (IllegalGradeException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
class IllegalGradeException extends Exception{
	public IllegalGradeException() {
		super();
		// TODO Auto-generated constructor stub
	}
	 //带有详细信息的构造器,信息存储在message中
    public IllegalGradeException(String message) {
        super(message);
    }
}
class Grade{
	private double grade;

	public double getGrade() {
		return grade;
	}

	public void setGrade(double grade) throws IllegalGradeException {
		if(grade<0 || grade>100) {
			throw new IllegalGradeException("分数必须在0-100之间");
		}
		this.grade=grade;
	}
	public void printGrade() {
		System.out.println("成绩为:"+grade);
		
	}	
}
  1. 写一个方法void isTriangle(int a,int b,int c),判断三个参数是否能构成一个三角形, 如果不能则抛出异常IllegalArgumentException,显示异常信息 “a,b,c不能构成三角形”,如果可以构成则显示三角形三个边长,在主方法中得到命令行输入的三个整数, 调用此方法,并捕获异常。

    package com.zry.day08.lx;
    
    import java.util.Scanner;
    
    public class Test2 {
    	public static void main(String[] args) {
    		Scanner sc=new Scanner(System.in);
    		System.out.print("请输入边长a:");
    		int a=sc.nextInt();
    		System.out.print("请输入边长b:");
    		int b=sc.nextInt();
    		System.out.print("请输入边长c:");
    		int c=sc.nextInt();
    		isTriangle(a, b, c);
    	}
    	public static void isTriangle(int a ,int b,int c) {
    		if(a<=0 ||b<=0 ||c<=0) {
    			throw new IllegalArgumentException("a,b,c不能构成三角形(a,b,c可能为0或者负数)");
    		}else {
    			if(a+b<=c || a+c<=b || b+c<=a) {
    				throw new IllegalArgumentException("a,b,c不能构成三角形");
    			}else {
    				System.out.printf("三角形边长:a=%d,b=%d,c=%d",a,b,c);
    			}		
    		}
    	}
    }
    
  2. 编写一个计算N个学生分数平均分的程序。程序应该提示用户输入N的值,如何必须输入所有N个学生分数。如果用户输入的分数是一个负数,则应该抛出一个异常并捕获,提示“分数必须是正数或者0”。并提示用户再次输入该分数。

package com.zry.day08.lx;

import java.util.Scanner;

public class Test3 {
	public static void main(String[] args) {
		System.out.println("请输入学生人数:");
		Scanner sc=new Scanner(System.in);
		int n=sc.nextInt();
		GradeAvg g=new GradeAvg(n);
		g.avgGrade();
	}
}
class IllegalGradeException extends Exception{
	public IllegalGradeException() {
		super();
		// TODO Auto-generated constructor stub
	}
	public IllegalGradeException(String message) {
		super(message);
		// TODO Auto-generated constructor stub
	}
}
class GradeAvg{
	int num;
	double sum;
	double avg;
	public GradeAvg(int num) {
		super();
		this.num = num;
	}
	public void avgGrade() {
		int n=num;
		while(n!=0) {
			System.out.println("请输入一个成绩:");
			Scanner s=new Scanner(System.in);
			double temp=s.nextDouble();
			if(temp<0) {
				try {
					throw new IllegalGradeException("分数必须是正数或者0");
				} catch (IllegalGradeException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}else {
				n--;
				sum+=temp;
			}
		}
		avg=sum/num;
		System.out.printf("%d个学生的平均分为:%.2f",num,avg);
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值