Java(22)異常處理
阿新 • • 發佈:2020-08-29
異常處理
Java異常介紹
Java在程式執行過程中的不正常情況稱為異常。捕獲錯誤最理想時間是編譯時候,但是有些錯誤在執行時才會報錯。
Java程式執行過程中的異常主要分為兩大類:
Error
:JVM系統內部錯誤、資源耗盡等情況。(程式設計師只能處理Exception,對Error無能為力。)Exception
:程式設計錯誤等一般問題,如空指標訪問、讀取不存在的檔案。。。
- 異常案例1:陣列越界異常
public class Test01{ public static int [] intarr={2,3,5}; public static void main(String[] args) { for (int i = 0; i < 4; i++) { // i迴圈了0,1,2,3,但是陣列長度只有3 System.out.println(intarr[i]); } } } /* 編譯時不報錯,執行報錯:Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3 */
- 異常案例2:空指標訪問異常
class Tennis{
public int i=0;
}
public class Test01{
public static void main(String[] args) {
Tennis a=null; //a沒有指向任何東西
System.out.println(a.i);
//編譯時不會報錯,執行時報錯:
//Exception in thread "main" java.lang.NullPointerException
}
}
- 異常案例3:分母為0異常
public class Test01{
public static int i=0;
public static void main(String[] args) {
float a=3/i;
}
}
/*編譯時不會報錯,執行時報錯:
Exception in thread "main" java.lang.ArithmeticException: / by zero
*/
Java異常類的層級
執行異常是執行才能發現的異常,是我們的常見異常,上面舉的3個例子都是執行異常。
異常處理機制
Java異常處理:抓拋模型(捕獲或者丟擲)。
捕獲異常:
Java通過try...catch...finally
捕獲異常,語法格式如下:
try{
//可能產生異常的程式碼
}catch (ExceptionName1 e1){ //catch可以有多個
// 當產生ExceptionName1異常時執行措施
}catch (ExceptionName2 e2){
// 當產生ExceptionName2異常時執行措施
}finally { //finally部分可寫可不寫
//無條件執行語句,無論有沒有異常都執行
}
案例1:
/**
* 通過try...catch來捕獲處理:
* try{
*
* }catch(){
*
* }
*/
public class Test01{
public static int i=0;
public static void main(String[] args) {
//用try花括號括住可能出錯的程式碼
try{
System.out.println(4/i);
}catch (Exception e){ //不知道捕獲什麼異常類時,可以使用異常的父類Exception
System.out.println(e.getMessage()); //這行程式碼可以檢視捕獲的異常是什麼
e.printStackTrace(); //這行程式碼也可以檢視捕獲的異常是什麼(列印方法呼叫棧)
//catch(){}花括號裡面可以不寫任何內容
}
System.out.println("Kobe,this is for you");//這行不受上面是否報異常的影響,
}
}
//執行結果為:Kobe,this is for you
案例2:
public class Test01{
public static void main(String[] args) {
String a=null;
try{
System.out.println(3/0);
System.out.println(a.toString());
}catch (java.lang.NullPointerException e1){
System.out.println("捕獲到了java.lang.NullPointerException異常");
}catch (java.lang.ArithmeticException e2){
System.out.println("捕獲到了java.lang.ArithmeticException異常");
}finally {
System.out.println("emm");
}
}
}
/*執行結果為:
捕獲到了java.lang.ArithmeticException異常
emm
*/
/*
從執行輸出結果可知,程式並沒有把兩個異常都捕獲到了,只捕獲到了3/0產生的ArithmeticException異常,
這是因為捕獲異常本身的目的就是為了防止程式出現異常,如果try{}花括號裡面前面的內容出現異常,就不會執行後面的內容了,所以沒有捕獲到a.toString()的空指標異常。
*/
丟擲異常:
使用方式:throws+try...catch
案例1:
package day01;
public class Test01 {
public static void main(String[] args) {
Flower a=new Flower();
//呼叫fun1()時進行捕獲異常:
try{
a.fun1();
}catch (Exception e){
e.printStackTrace();
}
}
}
class Flower{
void fun1() throws Exception{ //已經知道會報錯,丟擲異常
System.out.println(34/0);
}
}
如果有丟擲,某個上層呼叫就要有捕獲處理。丟擲異常,是當前方法不處理異常,但是把異常往上層的呼叫棧傳遞,由上層選擇捕獲異常進行處理,還是選擇繼續往更上層丟擲。如果main()方法丟擲異常,異常交由虛擬機器JVM處理。
案例2:
package day01;
class Flower{
static void fun1() throws Exception{ //異常從這裡開始被丟擲
System.out.println(34/0);
}
}
class Bee{
static void fun2() throws Exception{ //fun1()被呼叫,但是異常沒有被捕獲處理,繼續丟擲
Flower.fun1();
}
}
public class Test01 {
public static void main(String[] args) { //fun2()被呼叫,異常被捕獲處理
try{
Bee.fun2();
}catch (Exception e){
e.printStackTrace();
}
}
}
/*執行結果為:
java.lang.ArithmeticException: / by zero
at day01.Flower.fun1(Test01.java:5)
at day01.Bee.fun2(Test01.java:10)
at day01.Test01.main(Test01.java:16)
*/
/*
Main呼叫fun2(),fun2()呼叫fun1()
printStackTrace()打印出了方法的呼叫棧,並給出了原始碼的行號。
*/
案例3:如果異常被捕獲並且繼續丟擲不同型別的異常(異常型別轉換了),會發生什麼?
package day01;
class Vege{
static void fun1(String s){
if(s==null){
throw new NullPointerException();
}else {
System.out.println(s);
}
}
}
class Ora{
static void fun2(){
try{
Vege.fun1(null);
}catch (NullPointerException e1){
throw new IllegalArgumentException();
}
}
}
class Test01{
public static void main(String[] args) {
try {
Ora.fun2();
}catch (IllegalArgumentException e2){
e2.printStackTrace();
}
}
}
/*執行結果為:
java.util.NoSuchElementException
at day01.Ora.fun2(Test01.java:22)
at day01.Test01.main(Test01.java:29)
*/
/*
從執行結果可以看到,看不到原始的空指標異常的資訊了,如果想要檢視完整異常棧,需要新增引數,將本原始碼的
第18行的throw new IllegalArgumentException();
改成throw new IllegalArgumentException(e1);
*/
在Java中已經可以捕獲異常了,為什麼還要丟擲異常再進行捕獲,這種機制有什麼作用?個人目前理解是,為了使已經知道可能出現異常的方法繼續用下去,把抓到的異常丟擲給呼叫者,讓呼叫者來處理。
異常的遮蔽:
package day01;
class Police{
public static void main(String[] args) {
try{
System.out.println(4/0);
}catch (Exception e1){
throw new RuntimeException(e1);
}finally {
}
}
}
/*此處進行了異常轉型,執行結果為:
Exception in thread "main" java.lang.IllegalArgumentException
at day01.Police.main(Test01.java:10)
*/
//----------------------如果finally也丟擲異常:---------------
package day01;
class Police{
public static void main(String[] args) {
try{
System.out.println(4/0);
}catch (Exception e1){
throw new RuntimeException(e1);
}finally {
throw new IllegalArgumentException();
}
}
}
/*執行結果為:
Exception in thread "main" java.lang.IllegalArgumentException
at day01.Police.main(Test01.java:10)
*/
//從上面兩段原始碼執行結果可以知道,如果catch和finally同時準備丟擲異常,catch的異常會被遮蔽不丟擲