第一节 JAVA异常简介
程序中阻止当前方法或作用域继续执行的问题,我们就把它称作异常。所有异常类的鼻祖是Throwable类,该类分成两个,分别是Error类和Exception类。Error一般是虚拟机错误或者线程死锁,系统错误内存溢出。这里我们主要讨论后者,Exception是编码、环境、用户操作、输入出现问题。主要分为RuntimeException(非检查异常,运行时异常)和检查异常以及其他各种异常。异常可以提示程序员出现错误,使中断的程序能够以适当的方式运行;或者保存用户操作进行数据回滚;退出;fanilly及时回收占用资源。
常见的非检查异常有四种:空指针异常 NullPointerException,数组下标越界异常 ArrayIndexOutOfBoundsException, 类型转换异常 ClasslastException,算数异常 ArithmeticException。这是在今天做练习时遇到的一种异常:欲得到的数据类型与实际输入的类型不匹配 InputMismatchException。
非检查异常就是运行时异常,引起非检查异常的原因有很多:比如说引用了一个空对象的属性或者方法;也有可能是数组访问越界,或者是一个错误的类型转换,以及可能是算数引起的异常比如整数除以0,0不能作为除数。除了这四种还有很多其他运行时异常,都是RuntimeExcepetion的子类,运行时异常会由java虚拟机自动抛出自动捕获。检查异常与RuntimeException不同,必须要声明并手动添加语句捕获处理,一般是文件异常或者sql异常 IOException SQLException 文件不存在或是连接错误。相反的,继承自 RuntimeException 的异常可以不需要进行声明。
第二节 处理异常
一般用try-catch或者try-catch-finally捕获并处理异常。
try{//一些会抛出异常的方法}catch(异常类型Exception e){//处理该异常的代码块}
try抛出异常,catch捕获处理相应的异常代码块。如果try块中的方法确实会抛出异常,方法会终止执行,然后程序的控制权会交由catch块中的异常处理程序去处理,catch块中的语句该如何写呢,则是根据不同的业务情景不同对待,比如可以向用户或者编程人员发出警告,去检查配置以及网络连接,或者也可以在catch语句块中进行错误日志这样的操作。
多重catch
try{//一些会抛出异常的方法
}catch(Exception e){//处理该异常的代码块
}catch(Exception2 e){//处理异常2的代码块
}catch(Exception3 e){//处理异常3的代码块
}...(N个catch块)}finally{最终将要执行的一些代码,善后工作}
关于catch块中的异常编写先后顺序问题,先子后父,先小后大,先子类后父类来编写catc块中的异常语句。
第三节 try-catch案例
e.printStackTrace();输出异常的位置类型信息原因
e.toString();输出异常类型及异常信息
e.getMessage();输出异常信息
在这里值得注意的是如果定义的是一个有返回值的方法,比如public int test(){},try块和catch块中都要有return返回值或者,在这两个代码结束的最后返回一个int类型的值,mian函数调用方法时可以新建变量去接收这个返回值。
第四节 JAVA中的异常抛出及自定义异常类
throw 将产生的异常抛出,这是一个动词。throws 也叫声明异常,写在方法名和方法的参数列表之后,在方法体之前,用它修饰的方法,向调用者表明该方法可能会抛出某种类型的异常,可以抛出一种或多种,用逗号隔开。然后具体的方法里可以调用一些会抛出异常的方法,或者可以先抛出一个异常,这里就用到了throw关键字。
public void test()throws异常列表,逗号隔开{
//1、调用会抛出异常的方法,2、或者先抛出一个异常,throw new Exception();}
throw写在方法体里边代表一个具体的抛出异常的动作
自定义异常:
class自定义异常类 extents 异常类型{
//添加有参构造器
public 自定义异常类(String message){super(message)}
//添加无参构造器
public 自定义异常类(){ }
}
继承的必须是相近的类库异常或者是所有异常类型的基类Exception,异常处理不了时可以交由调用它的上级去处理。
第五节 java中的异常链
有时候可以把捕获的异常包装成一个新的异常,然后在新的异常里添加一个对原始异常的引用,再把这个新异常抛出,就像链式反应一样,一个导致另一个。
异常链的两种写法:一种是initcause(e)调用initcause方法把参数异常传递进去,这个是定义原始异常。另一种是简便写法RuntimeException e2=new RuntimeException(e);使用第一种方法时,也一样要新建一个RuntimeException();只是没有参数。
例题是把喝大了这个自定义异常包装成运行时异常然后抛出,在main方法中捕获,这就是异常链。编写第一个方法直接抛出异常喝大了,方法二中调用1方法,因为1会抛出异常,所以要用try catch语句块进行包围。
public void test2(){
try{test1();}catch(DrunkException e){
RuntimeException e2=new RuntimeException();
e2.inItcause(e); //RuntimeException e2=new RuntimeException(e);
throw e2;抛出异常
}}
在这里需要注意的是test1方法必须写throws声明异常,test2却不用,这是由于Exception包括非检查性异常RuntimeException和检查性异常如:IOException之类,两种异常的区别:
非检查性异常及子类,程序中可以不处理,但是运行时会报异常.
检查性异常及子类,程序中必须处理,其它一样.
所以,RunTimeException异常是不需要throws的,程序中无需处理,throws一下也没事,//尝试过没有报错
initCause();定义原始异常,这里也就是说该运行时异常的原始异常:喝大了异常DrunkException
第六节 实际应用中的经验总结
1.处理运行异常时,采用逻辑去合理规避,优化代码的同时,辅助try-catch去处理;
2.在多重catch块后面,我们还可以加一个catch(Exception e)来处理可能会被遗漏的异常;
3.对于不确定是否会抛出异常的代码,可以加上try-catch,处理潜在的异常;
4.尽量去处理异常,切忌只是简单的调用printStackTrace()去打印输出;
5.具体如何处理异常,要根据不同的业务需求和异常类型去决定;
6.尽量添加finally语句块去释放占用的资源,有其是在网络连接和连接数据库的情况下。
留下的练习题使用到的知识点
练习题是模拟图书馆借书。
For循环遍历数组内容;
equals比较字符串是否一样;
While(true)循环,可以先定义一个boolean变量为true,出现某个结果想要结束循环时可以给它复制false;
try-catch放在循环体内部还是外部。这次的练习是输入图书的序号或者书名来确认书是否存在,一共可能出现两个异常,第一个是该输入数字的时候输入字符串InputMismatchException还有一个异常是数组下标访问越界异常ArrayIndexOutOfBoundsException。练习的要求主要是做一个数组存放书,然后借取的时候如果输入不匹配的信息会如何报错,写出来的代码也顺便放在这留做纪念吧:
package trycatch.JieShuXiTong;
import java.util.InputMismatchException;
import java.util.Scanner;
/**
* Created by Administrator on 2017/3/28.
*/
public class JieShuXiTong {
String[] name = {"科幻世界", "空之境界", "发条女孩", "三体", "深渊上的火", "安德的游戏", "天渊",
"狼人十字架", "时砂之王"};
String[] xuHao = {"1-", "2-", "3-", "4-", "5-", "6-", "7-", "8-", "9-",};
public static void main(String[] args) {
System.out.println("您好,欢迎您的到来,目前图书馆可供借阅的图书有:");
JieShuXiTong js = new JieShuXiTong();
//循环遍历输出序号和书名
for (int i = 0; i < js.name.length; i++) {
System.out.print(js.xuHao[i]);
System.out.print(js.name[i]);
if (i < js.name.length - 1) System.out.print(";");
}
System.out.println("");
System.out.println("请选择您查找图书的方式");
//定义一个boolean类型的变量,初始值为true
boolean bl=true;
//while循环,这样当不想让他循环时给赋值成false就好了
//给整个循环体加了try块。异常只有两种可能一种是数组遍历时越界,还有一种是类型不匹配,比如int类型你输入胡汉字
//或者字符就不对了
while (bl) {
try {
System.out.println("输入1,按书名查找图书");
System.out.println("输入2,按图书序号查找图书");
Scanner a = new Scanner(System.in);
int num = a.nextInt();
if (num == 1) {
System.out.println("请输入您要查询的书的名字");
String name2 = a.next();
for (int i = 0; i < js.name.length; i++) {
if (name2.equals(js.name[i])) {
System.out.println("book:" + name2);
bl=false;
break;
} else if (i == js.name.length - 1) {
System.out.println("图书不存在或输入异常,请重新输入");
}
}
}else if (num == 2) {
System.out.println("请输入您要查询的书的号码");
int num2 = a.nextInt();
System.out.println("book:" + js.name[(num2 - 1)]);
bl=false;
}else{
System.out.println("您的输入有误请重新操作");
continue;
}
} catch (InputMismatchException e) {
System.out.println("您的输入格式有误,请重新输入");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("您的输入的号码已超过当前最大书号,请重新输入");
}
}
}
}