五、异常
什么是异常
导致程序的正常流程被中断的事件
异常的处理
try catch
1、将可能抛出异常的代码放在try里
2、如果没有异常,就会顺序往下执行,并且不执行catch块中的代码
3、如果发生异常,try 里的代码会立即终止,程序流程会运行到对应的catch块中
4、e.printStackTrace(); 会打印出方法的调用痕迹
使用异常的父类进行catch
所有异常都是Exception的子类,也可以用这个catch
多异常捕捉
有时候一段代码会抛出多种异常,解决办法就是多加一条catch代码块
另一个种办法是把多个异常,放在一个catch里统一捕捉,使用|来分隔多个异常,需要通过instanceof 进行 判断具体的异常类型
finally
finally代码块,无论异常是否发生,该代码块一定会被执行
throws
将该方法中的异常抛出去,抛给调用该方法的方法中,让上一级去处理
throw和throws的区别
throws 出现在方法声明上,而throw通常都出现在方法体内
throws 表示出现异常的一种可能性,并不一定会发生这些异常;throw则是抛出了异常,执行throw则一 定抛出了某个异常对象
异常的分类
异常分为:可查异常,非可查异常(运行时异常和错误)
可查异常:必须进行异常处理,不处理编辑器会报错
运行时异常:不进行处理不会报错,Java之所以会设计运行时异常的原因之一,是因为下标越界,空指针这些运 行时异常太过于普遍,如果都需要进行捕捉,代码的可读性就会变得很糟糕
错误:指的是系统级别的异常,不需要强制捕捉
自定义异常
创建一个类,继承Exception,然后提供构造方法(可以有参也可以无参,参数就是异常信息,需要传递给父类)
方法中抛出一个自定义的异常,并且在方法体中,判断何种状况抛出异常
public class test {
public static void main(String[] args){
try{
te(3);
}
catch(MyException e){
System.out.println("传递的值为3");
e.printStackTrace();
}
}
public static void te(int a) throws MyException {
if(a ==3){
throw new MyException("抛出异常了");
}
}
}
class MyException extends Exception{
public MyException() {
}
public MyException(String message) {
super(message);
}
}
123
练习
1)自定义异常
对MyStringBuffer的插入和删除方法中的边界条件判断,用抛出异常来解决
例: insert(int pos, String b) , 当pos 是负数的时候,抛出自定义异常
需要实现自定义两种异常
IndexIsNagetiveException 下标为负异常
IndexIsOutofRangeException 下标超出范围异常
public class MyStringBuffer implements InterfaceStringBuffer {
private char[] ch; //内部管理的个字符数组
private int len; // 全局都要使用的数组内有效元素的个数
public MyStringBuffer() {
ch = new char[16];//创建对象要默认创建一个大小16的空数组
}
public MyStringBuffer(String str) {
ch = new char[16];
try{
append(str);//当创建对象时传递了一个字符串,则调用内部的append去添加
}
catch (IndexIsOutofRangeException e){
e.printStackTrace();
}
catch (IndexIsNagetiveException e){
e.printStackTrace();
}
}
@Override
public void append(String str) throws IndexIsNagetiveException, IndexIsOutofRangeException {
insert(len,str);
}
@Override
public void append(char c) throws IndexIsNagetiveException, IndexIsOutofRangeException {
insert(len,c);
}
@Override
public void insert(int pos, char b) throws IndexIsNagetiveException,IndexIsOutofRangeException {
insert(pos,String.valueOf(b));
}
@Override
public void insert(int pos, String b) throws IndexIsNagetiveException,IndexIsOutofRangeException {
// if(pos < 0 || pos>len){
// return;
// }
if(pos <0){
throw new IndexIsNagetiveException("位置为负值");
}
if(pos >len){
throw new IndexIsOutofRangeException("位置超过最大值");
}
char[] c = b.toCharArray();
char[] temp = new char[capacity()];
while (len+c.length > temp.length){//一步一步扩容
temp = new char[temp.length*2 + 2];//原数组要进行扩容
}
System.arraycopy(ch, 0, temp, 0, pos);
System.arraycopy(c, 0, temp, pos, c.length);
System.arraycopy(ch, pos, temp, pos + c.length, len - pos);
ch = temp;
len = len + b.length();
}
@Override
public void delete(int start) throws IndexIsOutofRangeException, IndexIsNagetiveException {
delete(start,len);
}
@Override
public void delete(int start, int end) throws IndexIsOutofRangeException, IndexIsNagetiveException {
/*
* 总体思想就是清零ch数组
* 再把删除后的数组元素一个一个append进去
* 这样可以避免过分关注ch数组大小和有效元素的问题
* 全部由append去处理,最终还是由insert处理
* 所以insert一定要写全面一点
*/
if (end - start <= 0) {
return;
}
if (start < 0) {
return;
}
if (end > len) {
return;
}
char[] temp = ch; //把ch数组缓存
ch = new char[16];//ch数组清零
int lentemp = len;//长度缓存,到时循环时需要用到
len = 0;//ch都清零了,配套的len也得清零
for (int i = 0; i < start; i++) {
append(temp[i]);
}
for (int i = end; i < lentemp; i++) {
append(temp[i]);
}
}
@Override
public void reverse() {
char[] temp = new char[capacity()];
for (int i = 0; i < len; i++) {
System.arraycopy(ch, i, temp, len - 1 - i, 1);
}
ch = temp;
}
@Override
public int length() {
return len;
}
public int capacity() {
return ch.length;
}
public String toString() {
char[] temp = new char[len];
System.arraycopy(ch, 0, temp, 0, len);//避免打印后字符串后面有很多空字符
return String.valueOf(temp);
}
}
2)练习异常综合1
银行存取钱系统
test.java
public class test {
public static void main(String[] args) {
Account ac = new Account(1500);
ac.deposit(2000);
try{
ac.withdraw(5000);
}
catch(OverdraftException e){
System.out.println("余额不足,取款失败,透支额度为:"+e.getDeficit());
e.printStackTrace();
}
ac.deposit(3500);
}
}
Account.java
public class Account {
private double balance;
public Account(double init) {
balance += init;
System.out.println("创建了一个余额为" + balance + "的账户");
}
public double getBalance() {
return balance;
}
public void deposit(double amt) {
System.out.println("存款金额:" + amt);
balance += amt;
System.out.println("余额为" + getBalance());
}
public void withdraw(double amt) throws OverdraftException {
System.out.println("取款金额:" + amt);
if (amt - balance > 0) {
throw new OverdraftException("发生了透支行为", amt - balance);
} else {
balance -= amt;
System.out.println("余额为" + getBalance());
}
}
}
OverdraftException.java
public class OverdraftException extends Exception{
private double deficit;
public OverdraftException(String message, double deficit) {
super(message);
this.deficit = deficit;
}
public double getDeficit() {
return deficit;
}
}
3)练习异常综合2
增加透支功能,存取时都要考虑透支额,需要上一题的Account和OverdraftException类
test.java
import java.util.Scanner;
public class test {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
System.out.println("请先创建一个银行账户");
System.out.println("请输入初始金额:");
double init = s.nextDouble();
System.out.println("请输入透支额度:");
double overdraftProtection = s.nextDouble();
CheckingAccount ac = new CheckingAccount(init,overdraftProtection);
while (true){
System.out.println("请选择服务:1,取款 2,存款");
int i= s.nextInt();
switch (i){
case 1:
System.out.println("请输入取款金额:");
double amt = s.nextDouble();
try{
ac.withdraw(amt);
}
catch(OverdraftException e){
System.out.println("余额不足,取款失败,透支额度为:"+e.getDeficit());
e.printStackTrace();
}
break;
case 2:
System.out.println("请输入存款金额:");
double amt1 = s.nextDouble();
ac.deposit(amt1);
break;
default:
System.out.println("输入有误!");
}
}
}
}
CheckingAccount.java
public class CheckingAccount extends Account{
private double overdraftProtection;
private double overBalance;
public CheckingAccount(double init, double overdraftProtection) {
super(init);
this.overdraftProtection = overdraftProtection;
overBalance = overdraftProtection;
System.out.println("并激活了透支额度为"+overdraftProtection);
}
public void withdraw(double amt) throws OverdraftException {
if(amt <= this.balance){//如果正常取钱,调用父类的方法操作
super.withdraw(amt);
}else if(amt <= this.balance+overBalance){//如果需要透支一部分,则重新写withdraw
System.out.println("取款金额:" + amt);
overBalance = this.balance+overBalance-amt;
this.balance = 0;
System.out.println("透支额度剩余:"+overBalance);
System.out.println("余额为" + getBalance());
}else {//超出透支额度,抛出异常
throw new OverdraftException("发生了透支行为", amt - this.balance);
}
}
public void deposit(double amt) {
if(overBalance == overdraftProtection){//如果没有透支,直接调用父类的方法
super.deposit(amt);
}else {
if(amt<overdraftProtection-overBalance){//透支了,但存的钱不够还
overBalance = overBalance+amt;
}else {//还的钱可以冲抵透支的,还可以有余额
balance = balance+amt-(overdraftProtection-overBalance);
overBalance = overdraftProtection;
}
System.out.println("存款金额:" + amt);
System.out.println("余额为" + getBalance());
System.out.println("透支额度剩余:"+overBalance);
}
}
}