異常:
一.什么是異常?異常處理機制有什么作用?
程序在執行時發生了我們不想發生的異常情況,這種情況叫做異常;java語言的特性之一 --- 健壯性的實現主要就是靠異常處理機制,當程序執行過程中發生了異常,系統將異常信息打印到控制台上,程序員根據異常信息就可以對程序進行進一步的修改,進而使程序更加的健壯;
注意:異常也是一種類,系統內置有很多不同的異常類對應不同的異常情況,我們同樣可以根據我們的需求來定義不同的異常類,來處理不同的異常情況;
二.異常的體系結構:
Throwable:java 中所有異常和錯誤的父類;
Error:程序員無法解決處理的錯誤情況(跟咱們沒關系,不用管);
Exception: 程序本身可以捕獲並且可以處理的異常情況;其中又分為運行時異常(RuntimeException)(又稱作不受檢異常)和編譯時異常(IOException)(又稱作受檢異常);
運行時異常:空指針異常,數組下標越界異常等;運行時異常我們一般不利用異常處理機制對其進行處理,解決辦法就是直接修改代碼;
編譯時異常:編譯時異常必須對其處理否則無法運行;
三.異常的抓拋:
1.異常的拋出:
如果程序在運行過程中執行某段代碼時發生了異常,那么系統(JVM)將會根據異常的類型,在異常發生處創建對應的異常類型的對象並拋出,拋出給程序的調用者,並且本段代碼所屬的方法體中異常后的代碼將不再運行;
注意:這里的異常有可能是系統內置的異常,也有可能是我們手動拋出(throw)的的異常(我們定義的異常類);
2.異常的抓取:
對於異常的發生,有倆種處理方式。第一種,調用“ try-catch-finally ”語句來抓取異常;第二種,上拋(throws)給異常發生的方法的調用者;
四.try-catch-finally:
1.try 方法體內放置可能會出現異常的代碼,如果異常發生,就會 new 出一個異常類,此異常類會與 catch 的異常類型進行匹配,匹配成功,執行 catch 方法體內的代碼(代碼一般為打印異常的基本信息或打印異常的詳細信息),匹配不成功,繼續匹配后面不同的 catch ,最后finally 方法體內的代碼最終一定會執行;
2.catch 多個異常類時,如果存在有繼承關系的類,一定要按從子類到父類的順序來 catch,因為如果第一個就 catch 最大的父類,那么可能執行的異常處理代碼並非我們想要的;如果無繼承關系,自然順序就無所謂了;
3.catch 方法內常用的異常處理方法:
1) 異常 . getMessage ( ) ;
// 返回值為異常的基本信息(throw new 異常 ( "返回值就是這里的字符串喲" ) );一般搭配 System . out . println ( ) 打印輸出信息;
2) 異常 . printSrackTrace ( ) ;
// 打印異常的詳細信息(堆棧追蹤信息),如:
com.bjpowernode.javase.day1.WeaponIndexOufException: 武器庫裝備已達上限,[Lcom.bjpowernode.javase.day1.Weapon;@7f31245a無法載入武器庫系統
at com.bjpowernode.javase.day1.Army.addWeapon(Army.java:19)
at com.bjpowernode.javase.day1.武器系統.main(武器系統.java:12)
//第一行為異常的基本信息;
//第二行為異常出現的地方(是第三行中的異常出現的果);
//第三行也就是最后一行,為第一個異常出現的地方,是第二行異常出現的因;
注意:異常的詳細信息要從下往上看,因為異常一般會存在因果關系;
4.finally 內的代碼優先級僅次於 System . exit ( 0 ) ;
//強制關閉退出 JVM ,所以 finally 內的代碼不會執行;即使try內有 return 語句,在try方法強制結束之前, 也會先執行 finally 內的代碼;
注意:
1)在 try 內聲明的變量,出了 try ,系統就不認識了,解決方法是在 try 外聲明變量並初始化,在 try 內賦值,所以要理解 try 內裝的是一個“ 模塊 ”,一個可能會出現異常的代碼模塊;
2)try-catch-finally 也可以嵌套使用;
2)有 try ,必須有 finally / catch ,finally,catch 也不可以離開 try ;
五.throw -throws , try-catch-finally:
1.throw:手動拋出異常;一般這樣使用:
throw new XXXException("異常基本信息");//XXX代表是什么異常
2.throws:將“ 拋出的異常 ”捕獲並上交給方法的調用者;可以 throws 多個異常;一般這樣使用;
public void fangFa () throws XXXException{ //throws 的異常即為 方法體內 throw的異常
throws new XXXException("異常基本信息");
}
3.對於“ 拋出(throw)的異常 ” 有倆種處理方式:
第一種,繼續上拋給方法的調用者,但其實並沒有真正的解決異常,如果一直上拋到 main 方法,都沒有 try catch 異常,main 方法會繼續上拋到JVM,然后程序到此結束;第二種,直接在異常發生的方法內進行try catch 處理;
那么在日常開發中,究竟該如何選擇倆者的處理方式呢?
1)第一種情況,異常發生方法為子類重寫父類的方法,然而對應的父類方法並沒有 throws 異常,所以子類中重寫的方法就不能選擇 throws 了,只能被迫在此方法中就地解決(try - catch);
2)第二種情況,異常發生的方法屬於被調用的方法,而且調用此方法的方法也是被調用的,上面還有更多更多的方法,一直到最初的執行方法,這種存在層層遞進,相互關聯的方法,一般選擇將所有異常都 thows 給最初的調用者方法,然后在此方法中統一對所有異常進行處理;
3)注意: try-catch 和 throws 在方法中不要同時使用,因為只要使用 try-catch 就已經將異常處理掉了,再 throws 沒有任何意義;
六.栗子老師:
public class pra {
public static void main(String[] args) {
People p=new People("王狗蛋");
Food food=new Food("粑粑");
try{
p.eat(food);
}catch (ErrorFoodException e){
System.out.println(e.getMessage());
}
}
}
class People{
String name;
public People() {
}
public People(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void eat(Food food) throws ErrorFoodException{
if ("粑粑".equals(food.foodName)){
throw new ErrorFoodException("人不能吃"+food+"!");
//System.out.println("sdsas"); 異常拋出后不能寫任何代碼,因為根本到不了,沒有意義
}
//if 語句外就不受異常拋出的影響了,因為系統認為 if() 語句不一定執行,所以if()外的代碼是有意義的
System.out.println(name+"正在吃"+food);
}
}
class Food{
String foodName;
public Food() {
}
public String getFoodName() {
return foodName;
}
public void setFoodName(String foodName) {
this.foodName = foodName;
}
public Food(String foodName) {
this.foodName = foodName;
}
public String toString() {
return foodName;
}
}
class ErrorFoodException extends Exception{
public ErrorFoodException() {
}
public ErrorFoodException(String message) {
super(message);
}
}
運行結果:
--------------------------------
人不能吃粑粑!
Process finished with exit code 0
枚舉:
1)概念:枚舉屬於引用數據類型,當結果為兩種情況的時候,用布爾型,當結果有3種或3種以上且可以一枚一枚將結果列舉出來,就需要定義枚舉來進行使用;
2)定義枚舉:enum 枚舉名 { 枚舉值1,枚舉值2,枚舉值3,枚舉值4,...... }
3)注意:每個枚舉值都可以看作是一個常量,所以枚舉值一般都用大寫字母表示 ;
目前版本的 JDK,switch 語句支持 int,String,枚舉,但我們一般不這么使用枚舉;
4)栗子老師:(此程序寫的有些笨重,目的是為了更好的理解枚舉)
import java.util.Random;
public class pra{
public static void main(String[] args) {
Random random=new Random();
int i=random.nextInt(101);
Result result=power(i);
if (result==Result.S){
System.out.println("危險等級:S");
}else if (result==Result.A){
System.out.println("危險等級:A");
}else if (result==Result.B){
System.out.println("危險等級:B");
}else if (result==Result.C){
System.out.println("危險等級:C");
}else System.out.println("危險等級:D");
}
public static Result power(int i){
if (i>=95){
return Result.S;
}else if (i<95&&i>=85){
return Result.A;
}else if (i<85&&i>=70){
return Result.B;
}else if (i<70&&i>=50){
return Result.C;
}else return Result.D;
}
}
enum Result{
S,A,B,C,D
}
運行結果:
------------------------------
危險等級:D
Process finished with exit code 0
隨筆:
面試題:輸出幾?
public class pra {
public static void main(String[] args) {
int Result=m();
System.out.println(Result);
}
public static int m(){
int i=100;
try {
return i;
}finally {
i++;
}
}
}
點擊查看結果
100
Process finished with exit code 0
結果是不是很意外?為什么不是 101 呢?這里接觸到了 java 中的語法規則(語法規則是 java 里優先級最高的,任何代碼都必須遵循規則)
原則一:方法里中的代碼必須遵循自上而下的順序依次執行;
原則二:return 語句一旦執行,整個方法必須結束;
所以綜合原則一與原則二,既然系統識別到了 return 語句就必須執行,但是結束方法之前,必須先執行 finally 中的“ i++ ”,雖然此時 i 的值確實等於 101 ,但是 return 要遵循原則一,不能輸出新 i ,只能輸出老 i = 100 ;
其實就像於:
int i=100;
int j=i++; //i 確實等於101
return j; //但是系統被迫只能輸出 j !!!
由於博主目前只是一只猿寶寶,所以有些地方可能說的有些片面,若前輩們能夠指點一二就更好了 (~ ̄(OO) ̄)ブ