一: try{}catch{}语句块
1 try{}catch{}
这种形式一般来说前者和后者不是因果关系
2.可以一个try跟几个catch
在try中的异常一般是有因果关系的(类似于事务不可再分,要么全部成功要么全部失败,部分成功或失败是逻辑不通的),
这种情况不能使用第一种方式。
3.其后跟finally(前两种情况)
也可以try{}finally{}(用在不想处理代码,但是却有必须要执行的代码,这种情况需要在方法的声明处抛出异常)
不加catch语句
但是finally不能单独使用!!
public class ExceptionTest {
// try{}catch(){}的经典用法
public static void test1() {
FileInputStream fin = null;
try {
fin = new FileInputStream("c:\\aa.txt");
int i = 0;
while ((i = fin.read()) != -1) {
// byte -> int -> char
System.out.print((char) i);
//以上操作类似事务,不可再分,分则逻辑不通
}
} catch (FileNotFoundException ex) {
ex.printStackTrace();
//return 无法阻止finally代码的执行
//System.exit(x); 异常或无条件退出Jvm是可以终止finally代码的执行的
} catch (IOException ex) {
ex.printStackTrace();
}
finally {
try {
if (fin != null) {
// 流打开之后,必须要执行关闭的操作
fin.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
public static void main(String[] args) {
test1();
}
}
二:异常的分类
1.编译时异常(直接继承Exception),又叫不可查异常(unchecked exceptions)在方法的声明处抛出异常,要求程序员必须对其处理,要么try...catch...要么throws,直接throw +编译异常 这种情况不处理编译是不给通过的;2.运行时异常(Error分支或继承RuntimeException),又叫可查异常(checked exceptions)在方法内部某判断语句的分支中直接throw 异常,编译期间没有影响,但是只要执行到该处就会抛出异常退出JVM,这种throw+运行时异常是可以编译通过的其中Error分支 是程序无法处理的错误,表示运行应用程序中较严重问题。大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVM(Java 虚拟机)出现的问题。例如, Java虚拟机运行错误(Virtual MachineError), 当 JVM 不再有继续执行操作所需的内存资源时,将出现 OutOfMemoryError。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止。
三:throw 的使用
throw是将异常对象扔给调用者。以下是模拟JVM的栈的Demo。
public class Stack {
private String[] arr;
private int index = 0;
public Stack(int size) {
// 根据构造方法传递的int值,初始化数组对象.这样写比较灵活
arr = new String[size];
}
/**
* 压栈的方法 .每次压入一个数据.也就是把参数放到数组的某个位置.当栈满的时候通过异常来传递信息
*
* @param str
* @throws StackException
* 当栈满的时候通过异常来传递信息
*/
public void push(String str) throws StackException {
if (index < arr.length) {
arr[index] = str;
index++;
} else {
// 当栈满的时候,创建一个异常对象,然后throw出去,通过异常来传递信息
StackException ex = new StackException("栈满了");
throw ex;
}
}
/**
* 弹栈的方法.控制弹栈的数据是最后一个压栈的数据(也就是所谓的后进先出)
*
* @return .
* @throws StackException 当栈空的时候抛出异常
*/
public String pop() throws StackException {
if (index > 0) {
index--;
String str = arr[index];
arr[index] = null;
return str;
} else {
throw new StackException("栈空了");
}
}
}
自定义异常类StackException(也是一般自定义异常的模板)
)
public class StackException extends Exception {
// 自定义异常如果继承Exception那么throw的时候编译器强制要求处理
//如果继承RuntimeException则不会要求处理,这种异常很少用,一般是在用户的执行事务中出错来终止用户接下来的无效操作
public StackException() {
}
public StackException(String msg) {
super(msg);
}
}
测试类
public class Main {
/**
* @param args
*/
public static void main(String[] args) {
// 创建栈对象
Stack stack = new Stack(10);
// for (int i = 1; i <= 100; i++) {
// String str = "Hello-" + i;
// try {
// stack.push(str);
// } catch (StackException e) {
// e.printStackTrace();
// break;
// }
// }
// 以上把try{}catch()放到了for循环中,完整的业务流程被try{}catch()打乱了.这种方式不好
// 我们把for循环放到了try{}里面,这样程序的结构没有被打乱.
// 当循环的过程中如果遇到异常,则程序跳转到catch()里面,循环被自动终断.这是最佳方式
try {
for (int i = 1; i <= 100; i++) {
String str = "Hello-" + i;
stack.push(str);
}
} catch (StackException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 多次弹栈
try {
for (int i = 1; i <= 100; i++) {
String str = stack.pop();
System.out.println(str);
}
} catch (StackException e) {
e.printStackTrace();
}
}
}
四.将编译时异常转换为运行时异常
有的时候为了使用户的操作更加简单,我们会为外界调用给予更好的方式,不扔出编译时异常给调用者处理。
private Student(int id, String name, String strBirthday, Sex sex) {
try {
// 把String -> Date
this.birthday = sdf.parse(strBirthday);
} catch (ParseException e) {
// 把一个编译时异常转换成一个运行时异常,然后通过运行时异常向用户传递信息.用户可以不用额外处理异常
//也可以自定义一个异常,该异常要继承RuntimeException,也就是自定义异常的第二种
throw new IllegalArgumentException(strBirthday + "不是有效的日期格式", e);
}
this.id = id;
this.name = name;
this.sex = sex;
}
try {
// 把String -> Date
this.birthday = sdf.parse(strBirthday);
} catch (ParseException e) {
// 把一个编译时异常转换成一个运行时异常,然后通过运行时异常向用户传递信息.用户可以不用额外处理异常
//也可以自定义一个异常,该异常要继承RuntimeException,也就是自定义异常的第二种
throw new IllegalArgumentException(strBirthday + "不是有效的日期格式", e);
}
this.id = id;
this.name = name;
this.sex = sex;
}
以上代码使外界创建创建更加方便,但是,在parse()方法的声明处 throws ParseException,这是一个编译时异常,需要程序员进行声明捕捉以便抛出
那么用try{}catch{}还是throws呢?
1.如果使用throws,那么用户在创建的时候需要对异常进行相关的处理,这有悖于我们的初衷;
2.如果使用try{}catch{} 在catch中解决了异常,外界得不到异常信息,那么接下来的代码执行就没有意义!!
这种问题的解决方案:在catch{}语句块中throws一个运行时异常,这个时候,即不用外界处理异常,还能在异常发生后终止用户之后的操作
这里我们选择使用IllegalArgumentException来代替(也可以选择第二种自定义异常)