1. 不处理异常:如果代码发生异常,而没有进行 try...catch 则代码执行到此处就直接中断了,不会继续执行了。由于没有异常处理器,则这个异常被throw给了JVM,JVM处理异常的方法是:调用异常的 printStackTrace 方法,在标准输入设备中打印出上面的信息,然后JVM就shutdown了。
public void exception(){
int a = 1 / 0;
System.out.println("exception end.");
}
例如这个方法,没有进行异常处理,则JVM打印一下信息:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at org.hello.ExceptionBlock.exception(ExceptionBlock.java:13)
at org.hello.ExceptionBlock.main(ExceptionBlock.java:8)
打印了异常发生的线程,异常类型,异常消息,调用堆栈。
System.err.print("Exception in thread \""
+ t.getName() + "\" ");
e.printStackTrace(System.err);
}
对于这种未经处理的异常:
① 初始化一个异常对象
② JVM在异常发生的线程上调用,
/**
* Dispatch an uncaught exception to the handler. This method is
* intended to be called only by the JVM.
*/
private void dispatchUncaughtException(Throwable e) {//e就是第一步初始化好的参数。
getUncaughtExceptionHandler().uncaughtException(this, e);
// 获得一个线程默认的异常处理器(getUncaughtExceptionHandler())。调用该异常处理器的uncaughtException方法
}
2, try...catch 处理异常
例如:
public static void exce1(){
int a = 0;
try{
int b = Integer.parseInt("0");
a = 1 / b;
// 由于上面的语句发生了异常,所以下面的语句没有机会执行
System.out.println("a = 1 / b");
}catch(Exception e){
a = -1;
e.printStackTrace();
}
// 异常在catch块中处理完毕,这条语句就可以正常执行了。
System.out.println("exce1 end.");
}
在这里处理了异常,是的a具有合法的值,异常catch块执行完毕之后,相当于异常成功处理了,所以下面的 System.out.println("exce1 end."); 语句也就可以正常执行了。
3. try...catch..finally
public static void exce1(){
int a = 0;
try{
int b = Integer.parseInt("0");
a = 1 / b;
System.out.println("a = 1 / b");
}catch(Exception e){
//在catch块中发生了异常,所以下面的语句 不会执行,
a = 1/0;
e.printStackTrace();
}finally{
// 这里的finally块在所有的catch块都执行完毕之后执行
System.out.println("finally before.");
System.out.println("finally end.");
}
// 由于没有catch上面的异常,则下面的语句不会被执行
// 如果在catch块中没有异常,则下面的语句就可以正常执行
System.out.println("exce1 end." + a);
}
4. Throwable类
这个类其实就是JVM处理错误和异常的接口,也可以认为是JVM通知程序的一种机制。这个类及其子类都可以在 catch 语句中出现
try {
int b = Integer.parseInt("hello");
int a = 123 / 0;
}catch(ArithmeticException e){
e.printStackTrace();
}catch (NumberFormatException e) {
e.printStackTrace();
}catch(Throwable o){
}finally{
System.out.println("finally end.");
}
而且常常是JVM来初始化这些类的对象,然后这一个一个的catch块就成了一个一个的异常处理器。当发生异常时,JVM首先初始化好异常对象,然后通过异常对象的类型和注册的异常处理器的类型对比,如果匹配则调用该处理器处理异常,最后执行finally块的代码,此时这个异常就被处理完毕。处理异常的流程:
① JVM初始化异常对象
② 匹配执行对象的异常处理器,如果没有匹配到则该异常直接抛向jvm,jvm使用默认的方式处理异常:打印异常信息,终止线程,JVM退出。
③ 如果上面的匹配到了异常处理器,最终执行完毕之后执行finally块
至此,一个抛出的异常就处理完毕了,程序可以继续向下执行了。
5. 当catch到一个异常时,如何处理
在Throwable类的描述,举了一个例子:
try {
// 比如DAO中的数据库操作,出现异常
lowLevelOp();
} catch (LowLevelException le) {
// 初始化一个自定义的异常,将其抛到业务层。
// 业务层,根据业务逻辑来处理该异常。
throw new HighLevelException(le); // Chaining-aware constructor
}
在分层的架构下:例如WEB MVC中,如果一层抛出了异常但是没法处理(常常是不知道如何处理,或者说在这个处理不合适)那就封装一层往上抛。
6. 异常的分类
checked异常和unchecked异常
Exception类及其子类(除了java.lang.RuntimeException类)都是checked异常,当我们throw一个这种类型的异常时必须处理,而java.lang.RuntimeException类,则是unchecked异常,这种类型的异常可以不用强制处理:
public class TestException {
public static void main(String[] args) {
String res = "";
res = findUserName("hello");
System.out.println(res);
res = findUserName("");
System.out.println(res);
// try {
// res = findPassword("");
// } catch (PasswordIsInvalid e) {
// e.printStackTrace();
// }
}
public static String findUserName(String params){
if(null == params || "".equals(params)){
// UserNameIsInvalid是unchecked的异常,所以不需要处理
throw new UserNameIsInvalid("参数无:-D");
}
return "xxx";
}
public static String findPassword(String params) throws PasswordIsInvalid{
if(null == params || "".equals(params)){
// 这里抛出了一个checked异常,所以要进行处理,所以要在方法上throws这个异常
throw new PasswordIsInvalid("参数无:-D");
}
return "xxx";
}
}
@SuppressWarnings("serial")
class PasswordIsInvalid extends Exception{
public PasswordIsInvalid(String message) {
super(message);
}
}
@SuppressWarnings("serial")
class UserNameIsInvalid extends RuntimeException{
public UserNameIsInvalid(String message) {
super(message);
}
}