## 实例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), 如果所有异常都采用相同的处理方式，那么将导致无法对不同异常进行分类处理；
- 不要忽略捕捉到的异常，遇到异常一定要及时处理；
- 如果父类抛出多个异常，则覆盖方法必须抛出相同的异常或其异常的子类，不能抛出新异常。

