健壮性
。eg.
public class ExceptionTest01 { public static void main(String[] args) { int a = 10; int b = 0; // 实际上JVM在执行到此处的时候,会new异常对象:new ArithmeticException("/ by zero"); // 并且JVM将new的异常对象抛出,打印输出信息到控制台了。 int c = a / b; System.out.println(a + "/" + b + "=" + c); // 此处运行也会创建一个:ArithmeticException类型的异常对象。 System.out.println(100 / 0); } }
异常在java中以 类
的形式存在,每一个 异常类 都可以创建 异常对象。
eg.
public class ExceptionTest02 { public static void main(String[] args) { // 通过“异常类”实例化“异常对象” NumberFormatException nfe = new NumberFormatException("数字格式化异常!"); // java.lang.NumberFormatException: 数字格式化异常! System.out.println(nfe); } }
1、补充:
public class ExceptionTest03 { public static void main(String[] args) { System.out.println(100 / 0); // 这里的HelloWorld没有输出,没有执行。 System.out.println("Hello World!"); } }
程序执行到System.out.println(100 / 0);
此处发生了 ArithmeticException
异常,底层 new
了一个ArithmeticException异常对象,然后抛出了。
由于是 main方法
调用了100 / 0,所以这个异常ArithmeticException抛给了main方法。
main方法没有处理,将这个异常自动抛给了 JVM
。JVM最终终止程序的执行。
此时System.out.println("Hello World!");
并不会执行。
注意:
ArithmeticException
继承 RuntimeException
,属于 运行时异常
。在编写程序阶段不需要对这种异常进行预先的处理。
eg.
public class ExceptionTest04 { public static void main(String[] args) { // main方法中调用doSome()方法 // 因为doSome()方法声明位置上有:throws ClassNotFoundException // 我们在调用doSome()方法的时候必须对这种异常进行预先的处理。 // 如果不处理,编译器就报错。 //编译器报错信息: Unhandled exception: java.lang.ClassNotFoundException doSome(); } /** * doSome方法在方法声明的位置上使用了:throws ClassNotFoundException * 这个代码表示doSome()方法在执行过程中,有可能会出现ClassNotFoundException异常。 * 叫做类没找到异常。这个异常直接父类是:Exception,所以ClassNotFoundException属于编译时异常。 * @throws ClassNotFoundException */ public static void doSome() throws ClassNotFoundException{ System.out.println("doSome!!!!"); } }
解决方法一、throws上报给方法调用者(推卸责任:调用者知道)
public class ExceptionTest04 { public static void main(String[] args) throws ClassNotFoundException { doSome(); } public static void doSome() throws ClassNotFoundException{ System.out.println("doSome!!!!"); } }
解决方法二、try…catch捕捉,处理(调用者是不知道)
public class ExceptionTest04 { public static void main(String[] args) { try { doSome(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static void doSome() throws ClassNotFoundException{ System.out.println("doSome!!!!"); } }
在方法声明的位置上使用 throws
关键字抛出,谁调用我这个方法,我就抛给谁。抛给 调用者
来处理。
这种处理异常的态度:上报。
这个异常不会上报,自己把这个事儿处理了。
异常抛到此处为止,不再上抛了。
注意:
后续代码不会执行
。后面的代码不会执行
。eg.
private static void m1() throws FileNotFoundException { System.out.println("m1 begin"); m2(); // 以上代码出异常,这里是无法执行的。 System.out.println("m1 over"); }
try { m1(); // m1方法出异常,下面代码不执行。 System.out.println("hello world!");//不执行 } catch (FileNotFoundException e){ //异常处理 System.out.println("出异常了!!"); System.out.println(e); } System.out.println("hello world"); //会执行
注意:
注意:
try { } catch (ClassNotFoundException e) { e.printStackTrace(); }
这个分支中可以使用e引用,e引用
保存的内存地址是那个new出来 异常对象的内存地址
。
具体的异常类型
,也可以是该异常类型的 父类型
。从小到大
。eg.
try { FileInputStream fis = new FileInputStream("D:\\Download\\Javabean-addperson案例解析.docx"); } catch(FileNotFoundException e) { System.out.println("文件不存在!"); } 等同于 try { FileInputStream fis = new FileInputStream("D:\\Download\\Javabean-addperson案例解析.docx"); } catch(Exception e) {// 多态:Exception e = new FileNotFoundException(); System.out.println("文件不存在!"); }
try { FileInputStream fis = new FileInputStream("D:\\Download\\Javabean-addperson案例解析.docx"); fis.read(); } catch(IOException e){ System.out.println("读文件报错了!"); } catch(FileNotFoundException e) { System.out.println("文件不存在!"); }
|
分割eg.
try { //创建输入流 FileInputStream fis = new FileInputStream("D:\\Download\\Javabean-addperson案例解析.docx"); // 进行数学运算 System.out.println(100 / 0); // 这个异常是运行时异常,编写程序时可以处理,也可以不处理。 } catch(FileNotFoundException | ArithmeticException | NullPointerException e) { System.out.println("文件不存在?数学异常?空指针异常?都有可能!"); }
方法名 | 作用 |
---|---|
String getMessage() | 返回异常的详细消息字符串 |
void printStackTrace() | 追踪堆栈异常信息(采用异步线程) |
在finally子句中的代码是最后执行的,并且是 一定会执行
的,即使try语句块中的代码出现了异常。
finally子句必须和try一起出现,不能单独编写。
通常在finally语句块中完成 资源的释放/关闭
。
eg.
public class ExceptionTest10 { public static void main(String[] args) { FileInputStream fis = null; // 声明位置放到try外面。这样在finally中才能用。 try { fis = new FileInputStream("D:\\Download\\Javabean-addperson案例解析.docx"); String s = null; // 这里一定会出现空指针异常! s.toString(); System.out.println("hello world!"); // 流使用完需要关闭,因为流是占用资源的。 // 即使以上程序出现异常,流也必须要关闭! // 放在这里有可能流关不了。 //fis.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch(IOException e){ e.printStackTrace(); } catch(NullPointerException e) { e.printStackTrace(); } finally { System.out.println("hello 浩克!"); // 流的关闭放在这里比较保险。 // finally中的代码是一定会执行的。 // 即使try中出现了异常! if (fis != null) { // 避免空指针异常! try { // close()方法有异常,采用捕捉的方式。 fis.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
eg.
public class ExceptionTest11 { public static void main(String[] args) { try { System.out.println("try..."); return; } finally { System.out.println("finally..."); } // 这里不能写语句,因为这个代码是无法执行到的。 //System.out.println("Hello World!"); } }
以下代码的执行顺序:
注意:
System.exit(0);
只有这个可以治finally。
public class ExceptionTest12 { public static void main(String[] args) { try { System.out.println("try..."); // 退出JVM System.exit(0); // 退出JVM之后,finally语句中的代码就不执行了! } finally { System.out.println("finally..."); } } }
public class ExceptionTest13 { public static void main(String[] args) { int result = m(); System.out.println(result); //100 } /* java语法规则(有一些规则是不能破坏的,一旦这么说了,就必须这么做!): java中有一条这样的规则: 方法体中的代码必须遵循自上而下顺序依次逐行执行(亘古不变的语法!) java中海油一条语法规则: return语句一旦执行,整个方法必须结束(亘古不变的语法!) */ public static int m(){ int i = 100; try { // 这行代码出现在int i = 100;的下面,所以最终结果必须是返回100 // return语句还必须保证是最后执行的。一旦执行,整个方法结束。 return i; } finally { i++; } } }
反编译之后的效果:
public static int m(){ int i = 100; int j = i; i++; return j; }
类
无法继承方法
无法覆盖变量
不能重新赋值。SUN提供的JDK内置的异常肯定是不够的用的。在实际的开发中,有很多业务,这些业务出现异常之后,JDK中都是没有的。和业务挂钩的。因此需要自定义异常。
Exception
或者 RuntimeException
.构造方法
,一个无参数的,一个带有String参数的。eg.
//栈操作异常:自定义异常! public class StackOperationException extends Exception{ // 编译时异常! public MyStackOperationException(){ } public MyStackOperationException(String s){ super(s); } }
class Animal { public void doSome(){ } public void doOther() throws Exception{ } } class Cat extends Animal { // 编译正常。 public void doSome() throws RuntimeException{ } // 编译报错。 /*public void doSome() throws Exception{ }*/ // 编译正常。 /*public void doOther() { }*/ // 编译正常。 /*public void doOther() throws Exception{ }*/ // 编译正常。 public void doOther() throws NullPointerException{ } }
注意:
一般不会这样考虑,方法覆盖复制一份,然后重写就好了。
eg.
public void pop() throws StackOperationException { if(index < 0){ throw new MyStackOperationException("弹栈失败,栈已空!");//手动抛出异常 } }
该方法index < 0时手动抛出异常,然后在方法里没有处理,上报给调用者,让调用者处理!