異常處理
異常體系:
Error是指java虛擬機無法解決的嚴重問題;如JVM系統內部錯誤、資源耗盡等嚴重情況;比如:StrackOverflowError、OOM(OutOfMemoryError)(主要就是看後面帶Error就是錯誤)。
java.lang.Throwable
|-----java.lang.Error:一般不編寫針對性的代碼進行處理。
|-----java.lang.Exception:可以進行異常的處理
|------編譯時異常(checked)
|-----IOException
|-----FileNotFoundException
|-----ClassNotFoundException
|------運行時異常(unchecked,RuntimeException)
|-----NullPointerException
|-----ArrayIndexOutOfBoundsException
|-----ClassCastException
|-----NumberFormatException
|-----InputMismatchException
|-----ArithmeticException
public class MyExceptionTest1 {
@Test
public void test() {
FileInputStream fis = null;
try {
File file = new File("hello.txt");
fis = new FileInputStream(file);
int date = fis.read();
while(date != -1) {
System.out.print((char)date);
date = fis.read();
}
}catch(FileNotFoundException e) {
e.printStackTrace();
}catch(IOException e) {
e.printStackTrace();
}finally {
while(fis != null) {
try {
fis.close();
}catch(IOException e) {
e.printStackTrace();
}
}
}
}
@Test
public void test2() {
//ArrayIndexOutOfBoundsException;
int[] arr = new int[5];
System.out.println(arr[5]);
//NullPointerException
int[] arr2 = null;
System.out.println(arr2[0]);
}
@Test
public void test3() {
// NumberFormatException
String str = "abc";
int a = Integer.parseInt(str);
}
//ClassCastException
@Test
public void test4(){
Object obj = new Date();
String str = (String)obj;
}
//ArithmeticException
@Test
public void test5(){
int a = 10;
int b = 0;
System.out.println(a / b);
}
//InputMismatchException
@Test
public void test6(){
Scanner scanner = new Scanner(System.in);
int score = scanner.nextInt();
System.out.println(score);
scanner.close();
}
}
抓拋模型:
抓:程序正常執行的過程中,如果出現異常就會在異常代碼處產生一個對應異常類的異常對象,並拋出;並且其後的代碼不會再執行。
關於異常的產生:
①系統自動生成的異常對象;
②手動生成的異常類的對象,並拋出(throw)
抓:抓可以理解成異常的處理方式:
①try-catch-finally
②throws
try{ //可能出現異常的代碼
}catch(異常類型1 變量名1){
//處理異常的方式1
}catch(異常類型2 變量名2){
//處理異常的方式2
}catch(異常類型3 變量名3){
//處理異常的方式3
}
…
finally{
//一定會執行的代碼
}
說明:
①finally是可選的;
②使用try將可能出現異常代碼包裝起來,在執行過程中,一旦出現異常就會生成一個對應異常類的對象,根據此對象 的類型,去catch中進行匹配;
③一旦try中的異常對象匹配到某一個catch時,就進入catch中進行異常的處理。一旦處理完成,就跳出當前的try-catch結構(在沒有寫finally的情況)。繼續執行後面的代碼,如果有finally先執行finally中的代碼。
④catch中的異常類型如果沒有子父類關係,則誰聲明在上,誰聲明在下無所謂。catch中的異常類型如果滿足子父類關係,則要求子類一定聲明在父類的上面。否則,報錯
⑤常用的異常處理方式:一、String getMessage();二、printStrackTrace()。
⑥try結構中聲明的變量在出了try結構之後就不能再進行調用。
⑦try-catch-finally結構可以嵌套
體會1:使用try-catch-finally處理編譯時異常,是得程序在編譯時就不再報錯,但是運行時仍可能報錯。相當於我們使用try-catch-finally將一個編譯時可能出現的異常,延遲到運行時出現。
體會2:開發中,由於運行時異常比較常見,所以我們通常就不針對運行時異常編寫try-catch-finally了。針對於編譯時異常,我們說一定要考慮異常的處理。
finally使用:
①finally是可選的;
②finally中聲明的是一定會被執行的代碼。即使catch中又出現異常了,try中有return語句,catch中有return語句等情況。
③像數據庫連接、輸入輸出流、網絡編程Socket等資源,JVM是不能自動的回收的,我們需要自己手動的進行資源的釋放。此時的資源釋放,就需要聲明在finally中。
public class FinallyTest {
@Test
public void test2(){
FileInputStream fis = null;
try {
File file = new File("hello1.txt");
fis = new FileInputStream(file);
int data = fis.read();
while(data != -1){
System.out.print((char)data);
data = fis.read();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
if(fis != null)
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Test
public void testMethod(){
int num = method();
System.out.println(num);
}
public int method(){
try{
int[] arr = new int[10];
System.out.println(arr[10]);
return 1;
}catch(ArrayIndexOutOfBoundsException e){
e.printStackTrace();
return 2;
}finally{
System.out.println("我一定會被執行");
return 3;
}
}
@Test
public void test1(){
try{
int a = 10;
int b = 0;
System.out.println(a / b);
}catch(ArithmeticException e){
e.printStackTrace();
// int[] arr = new int[10];
// System.out.println(arr[10]);
}catch(Exception e){
e.printStackTrace();
}
// System.out.println("我好帥啊!!!~~");
finally{
System.out.println("我好帥啊~~");
}
System.out.println("wo zai na");
}
}
異常處理的方式二:throws+異常類型
1、“throws+異常類型”寫在方法的聲明出。指明方法執行時可能會出現的異常。
當方法體執行時,出現了異常,還是會在異常代碼處生成一個異常類的對象,此對象滿足throws後的異常類型時,就會被拋出。異常代碼後的代碼就不會再執行。
2、體會:try-catch-finally:真正的將異常給處理掉了。throws的方式只是將異常拋給了方法的調用者。 並沒有真正將異常處理掉。
3、開發中如何選擇使用try-catch-finally 還是使用throws?
3.1、如果父類中被重寫的方法沒有用throws的方式處理異常,則子類中重寫的方法也不能夠使用throws的方式進行處理。也就是說,如果父類沒有使用throws,子類對異常的處理只能使用try-catch-finally的方式。
3.2、如果要執行的方法a中先後調用了另外幾個方法,且這些方法之間存在遞進關係,一般建議調用的方法使用throws進行處理,而執行方法a使用try進行處理。(這不單單是爲了方便和節省內存考慮,有時如果method1中出現異常可能導致method2中需要的數據並沒有生成,但如果使用try處理,那麼執行方法a就不會再處理而是直接執行下面的程序;)
public class ExceptionTest2 {
public static void main(String[] args){
try{
method2();
}catch(IOException e){
e.printStackTrace();
}
// method3();
}
public static void method3(){
try {
method2();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void method2() throws FileNotFoundException,IOException{
method1();
}
public static void method1() throws IOException{
File file = new File("hello1.txt");
FileInputStream fis = new FileInputStream(file);
int data = fis.read();
while(data != -1){
System.out.print((char)data);
data = fis.read();
}
fis.close();
System.out.println("hahaha!");
}
}
方法重寫的規則之一:
子類重寫的方法拋出的異常類型不大於父類被重寫的方法拋出的異常類型;
(如果大於父類中的異常類型,父類就處理不了。)
如何自定義異常:
1、繼承現有的異常體系,一般是RunTimeException和Exception;
2、提供全局常量:serialVersionUID
3、提供重載的構造器;
public class MyException extends Exception{
static final long serialVersionUID = -7034897193246939L;
public MyException(){
}
public MyException(String msg){
super(msg);
}
}
體會手動拋出異常:
public class StudentTest {
public static void main(String[] args) {
try {
Student s = new Student();
s.regist(-1001);
System.out.println(s);
} catch (Exception e) {
// e.printStackTrace();
System.out.println(e.getMessage());
}
}
}
class Student{
private int id;
public void regist(int id) throws Exception {
if(id > 0){
this.id = id;
}else{
// System.out.println("您輸入的數據非法!");
//手動拋出異常對象
// throw new RuntimeException("您輸入的數據非法!");
// throw new Exception("您輸入的數據非法!");
throw new MyException("不能輸入負數");
//錯誤的
// throw new String("不能輸入負數");
}
}
@Override
public String toString() {
return "Student [id=" + id + "]";
}
}
執行的先後順序判別:
public class ReturnExceptionDemo {
static void methodA() {
try {
System.out.println("進入方法A");
throw new RuntimeException("製造異常");
} finally {
System.out.println("用A方法的finally");
}
}
static void methodB() {
try {
System.out.println("進入方法B");
return;
} finally {
System.out.println("調用B方法的finally");
}
}
public static void main(String[] args) {
try {
methodA();
} catch (Exception e) {
System.out.println(e.getMessage());
}
methodB();
}
}