From 243babc68ed0a4d5b4ca9757a89cd96a78218a49 Mon Sep 17 00:00:00 2001 From: OrangeCat <73102364+tensorflow-jumao@users.noreply.github.com> Date: Thu, 22 Jul 2021 12:58:54 +0800 Subject: [PATCH] Add files via upload --- Java/练习题:异常处理.md | 212 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 212 insertions(+) create mode 100644 Java/练习题:异常处理.md diff --git a/Java/练习题:异常处理.md b/Java/练习题:异常处理.md new file mode 100644 index 0000000..90069c2 --- /dev/null +++ b/Java/练习题:异常处理.md @@ -0,0 +1,212 @@ +## 实例1: 顾客购买650克西红柿需支付的金额 +在主方法中使用 try-catch 代码块将可能出现的异常语句进行异常处理。代码如下∶ +```java +public class Tomato { // 创建西红柿类 + public static void main(String[] args) { + try { // 把可能产生异常的Java代码放在try中 + String message = "西红柿:2.99元/500克"; // 西红柿的售价信息 + String[] strArr = message.split(":"); // 使用":"拆分字符串 + String unitPriceStr = strArr[2].substring(0, 4); // 截取西红柿单价:2.99 + double weight = 650; // 顾客购买西红柿的重量 + // 将String类型的西红柿单价转换为double类型 + double unitPriceDou = Double.parseDouble(unitPriceStr); + // 输出顾客购买1.3斤的西红柿需支付的金额 + System.out.println(message + ",顾客买了" + weight + "克的西红柿,须支付" + + (float) (weight / 500 * unitPriceDou) + "元"); + } catch (Exception e) { // 捕捉与已产生的异常类型相匹配的异常对象 + e.printStackTrace(); // 打印异常信息 + } + System.out.println("程序执行完毕!"); // 输出提示信息 + } +} +``` + +**注意∶** Exception是 try 代码块传递给catch代码块的异常类型,e是与已产生的异常类型相匹配的异常对象。 + + +运行结果中,程序仍然输出最后的提示信息"程序执行完毕!",这说明程序的执行没有因为产生异常被中断。由此可知,使用 try-catch代码块捕捉并处理异常时,不会因为产生异常影响程序的执行。 + +实例中,在catch代码块中使用了Exception 对象的printStackTrace()方法输出了异常信息,除此之外,Exception 对象还提供了其他的方法用于获取异常的相关信息∶ +- getMessage()方法: 获取有关异常事件的信息。 +- toString()方法: 获取异常的类型与性质。 + + +**注意∶** 有时为了编程简单会忽略catch代码块中的代码,这样trv-catch语句就成了一种摆设,一旦程序在运行过程中出现了异常,这个异常将很难查找。因此要养成良好的编程习惯∶ 在catch代码块中写入处理异常的代码. + +思考: + +#### 练习1 +在控制台上简述一个整型数组,如int a[] ={1,2,3,4 }; 数组遍历的过程,并体现出当i的值为多少时,会产生异常,异常的种类是什么? +#### 练习2 +模拟一个简单的整数计算器(只能计算两个整数之间的加、减、乘、除的运算),并用try-catch捕捉InputMismatchException(控制台输入的不是整数)异常。 + + +## 实例2: 捕捉控制台输入西红柿单价后的异常 +西红柿的单价不是一成不变的,修改上面的实例,首先实现控制台输入单价的功能,然后在finally代码块中关闭控制台输入对象。 +```java +import java.util.Scanner; + +public class Tomato { // 创建西红柿类 + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); // 创建控制台输入对象 + System.out.println("今天的西红柿单价(单价格式为“3.00”):"); // 控制台输出提示信息 + String dayPrice = sc.next(); // 把控制台输入的西红柿单价赋值给变量dayPrice + if (dayPrice.length() == 4) { // 控制台输入的字符串长度为4时 + try { // 把可能产生异常的Java代码放在try中 + String message = "西红柿:" + dayPrice + "元/500克"; // 西红柿的售价信息 + String[] strArr = message.split(":"); // 使用":"拆分字符串 + String unitPriceStr = strArr[2].substring(0, 4); // 截取西红柿单价:2.99 + double weight = 650; // 顾客购买西红柿的重量 + // 将String类型的西红柿单价转换为double类型 + double unitPriceDou = Double.parseDouble(unitPriceStr); + // 输出顾客购买650克的西红柿需支付的金额 + System.out.println(message + ",顾客买了" + weight + "克的西红柿,须支付" + + (float) (weight / 500 * unitPriceDou) + "元"); + } catch (ArrayIndexOutOfBoundsException aiobe) {// 捕捉数组元素下标越界异常对象 + aiobe.printStackTrace(); + } catch (Exception e) { // 捕捉与已产生的异常类型相匹配的异常对象 + e.printStackTrace(); + } finally { + sc.close(); // 关闭控制台输入对象 + System.out.println("控制台输入对象被关闭。"); // 输出提示信息 + } + } else { // 控制台输入的字符串长度不为4时 + // 输出提示信息 + System.out.println("违规操作:" + "输入西红柿单价时小数点后须保留两位有效数字(如3.00)!"); + } + } +} +``` + +从结果中可以看出厂程序在捕捉完异常信息之后,会执行finally代码块中的代码。另外,在以下3种特殊情况下finally块不会被执行∶ +- 在 finally 代码块中产生了异常。 +- 在前面的代码中使用System.exit()退出程序。 +- 程序所在的线程死亡。 + + +#### 练习3 +银行账号中现有余额 1023.79 元。模拟取款,当在控制台上输入的取款金额不是整数时,会引起数字格式转换异常。 + +#### 练习4 +新买了一台电脑,这台电脑与其他的电脑不一样,无法正常启动开机(电脑品牌未声明)。使用继承来体现这个事件,并尝试利用"电脑品牌"引出空指针异常。 + + +## 实例3: 规定西红柿单价不得超过7元 +当某种商品的价格过高时,国家会对这种商品采取宏观调控,进而使得这种商品的价格趋于稳定编写一个程序,规定西红柿单价不得超过7元,超过7元的情况作为异常抛出。 +```java +import java.util.Scanner; + +class PriceException extends Exception { // 自定义价格异常类,并继承异常类 + public PriceException(String message) { // 创建价格异常类有参构造方法 + super(message); // 调用异常类的有参构造方法 + } +} + +public class Tomato { // 创建西红柿类 + private double price; // 西红柿单价 + + public double getPrice() { // 获取西红柿单价 + return price; + } + + // 设置西红柿单价,如果产生价格异常,那么就抛出价格异常 + public void setPrice(double price) throws PriceException { + if (price > 7.0) { // 如果西红柿单价大于7元 + throw new PriceException("国家规定西红柿单价不得超过7元!!!"); // 抛出价格异常 + } else { // 如果西红柿单价不大于7元 + this.price = price; // 为西红柿类的price属性赋值 + } + } + + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); // 创建控制台输入对象 + System.out.println("今天的西红柿单价(单价格式为“3.00”):"); // 控制台输出提示信息 + String dayPrice = sc.next(); // 把控制台输入的西红柿单价赋值给变量dayPrice + if (dayPrice.length() == 4) { // 控制台输入的字符串长度为4时 + // 将String类型的西红柿单价转换为double类型 + double unitPriceDou = Double.parseDouble(dayPrice); + Tomato tomato = new Tomato(); // 创建西红柿对象 + try { // 把可能产生异常的Java代码放在try中 + tomato.setPrice(unitPriceDou); // 西红柿对象调用设置西红柿单价的方法 + } catch (Exception e) { // 捕捉数组元素下标越界异常对象 + System.out.println(e.getMessage()); // 输出异常信息 + } finally { + sc.close(); // 关闭控制台输入对象 + } + } else { // 控制台输入的字符串长度不为4时 + // 输出提示信息 + System.out.println("违规操作:" + "输入西红柿单价时小数点后须保留两位有效数字(如3.00)!"); + } + } +} + +``` + +## 实例4: 抛出控制台输入西红柿单价后的异常 +修改上面实例2,在西红柿类Tomato中,创建支付方法pay(String dayPrice, double weight), 在支付方法中抛出 ArrayIndexOutOfBoundsException异常。 +```java +import java.util.Scanner; + +public class Tomato {// 创建西红柿类 + // 参数为西红柿单价和西红柿重量的支付方法,且支付方法抛出了数组元素下标越界异常 + public void pay(String dayPrice, double weight) throws ArrayIndexOutOfBoundsException { + String message = "西红柿:" + dayPrice + "元/500克"; // 西红柿的售价信息 + String[] strArr = message.split(":"); // 使用":"拆分字符串 + String unitPriceStr = strArr[2].substring(0, 4); // 截取西红柿单价:2.99 + // 将String类型的西红柿单价转换为double类型 + double unitPriceDou = Double.parseDouble(unitPriceStr); + // 输出顾客购买650克的西红柿需支付的金额 + System.out.println(message + ",顾客买了" + weight + "克的西红柿,须支付" + + (float) (weight / 500 * unitPriceDou) + "元"); + } + + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); // 创建控制台输入对象 + System.out.println("今天的西红柿单价(单价格式为“3.00”):"); // 控制台输出提示信息 + String dayPrice = sc.next(); // 把控制台输入的西红柿单价赋值给变量dayPrice + if (dayPrice.length() == 4) { // 控制台输入的字符串长度为4时 + double weight = 650; // 顾客购买西红柿的重量 + try { // 把可能产生异常的Java代码放在try中 + Tomato tomato = new Tomato(); + tomato.pay(dayPrice, weight); + } catch (ArrayIndexOutOfBoundsException aiobe) {// 捕捉数组元素下标越界异常对象 + System.out.println("pay方法抛出数组元素下标越界异常!"); // 输出提示信息 + } finally { + sc.close(); // 关闭控制台输入对象 + System.out.println("控制台输入对象被关闭。"); // 输出提示信息 + } + } else { // 控制台输入的字符串长度不为4时 + // 输出提示信息 + System.out.println("违规操作:" + "输入西红柿单价时小数点后须保留两位有效数字(如3.00)!"); + } + } +} + +``` +使用throws关键字将方法产生的异常抛给上一级后,如果上以继续向上抛出,但最终要有能够捕捉并处理这个异常的代码。 + +#### 练习5 +模拟老师上课前的点名过程,并将旷课的学生作为异常抛出∶张三、李四、王五(老师在点名册上记下了“王五旷课”)。 + +#### 练习6 +超市经常会对定价较市场价低的产品实施限购∶ 超市里的鲜鸡蛋每500 克 3.98 元,每人限购1500克。现将超过1500克的作为异常抛出,而对于满足条件的,计算出应付款。 + + +##### 知识补充: +throws 关键字和 throw 关键字的区别如下∶ +- throws 用在方法声明后面,表示抛出异常,由方法的调用者处理,而throw用在方法体内,用来制造一个异常,由方法体内的语句处理。 +- throws是声明这个方法会抛出这种类型的异常,以便使它的调用者知道要捕捉这个异常,而 throw是直接抛出一个异常实例。 +- throws表示出现异常的一种可能性,并不一定会产生这些异常,但如果使用throw就一定会产生某种异常。 + + + + +**异常的使用原则:** + +异常处理的主要作用是捕捉并处理程序在运行时产生的异常。编写代码处理某个方法可能出现的异常时,可遵循以下原则∶ +- 不要过度使用异常。虽然通过异常可以增强程序的健壮性,但使用过多不必要的异常处理,可能会影响程序的执行效率; +- 不要使用过于庞大的try-catch块。在一try块中放置大量的代码,这种写法看上去"很简单",但是由于try块中的代码过于庞大,业务过于复杂,会增加try块中出现异常的几率,从而增加分析产生异常原因的难度; +- 避免使用catch(Exception e), 如果所有异常都采用相同的处理方式,那么将导致无法对不同异常进行分类处理; +- 不要忽略捕捉到的异常,遇到异常一定要及时处理; +- 如果父类抛出多个异常,则覆盖方法必须抛出相同的异常或其异常的子类,不能抛出新异常。 +