零基礎學習之Java例外
- 概述
- 基本介紹
- Error
- 代碼示例
- Exception
- 代碼示例
- 例外的處理
- throw
- 代碼示例
- throws
- 代碼示例
- try…catch
- 代碼示例
- finally塊
- 代碼示例
- finally與return(面試)
- 形式一:從try回來
- 形式二:從catch回來
- 形式三:從finally回來
- 自定義例外
- 基本介紹
- 代碼示例
- 例外注意事項
概述
正如“人無完人”一樣,程式也不是完美的,它總會存在這樣那樣的問題,而有些問題并不是能夠通程序式員開發更好的代碼來解決的,如果我們忽視它,可能就會造成程式的終止,甚至是系統的崩潰,因此,我們需要想辦法來合理的解決它,這就是Java中例外的由來,
例外是指程式在執行程序中,出現的非正常情況,比如:空的參考、陣列下標越界、記憶體溢位錯誤、讀取檔案不存在、網路斷開等
一般來說有兩種方法來處理例外:
- 遇到錯誤就終止程式運行;
- 開發人員在撰寫程式的時候考慮到可能出現的非正常情況,提前做好處理(這個是最好的,不過也是不容易的);
那究竟例外有哪些?常見的處理方法是什么?我想通過下面的文章,你一定可以得到想要的答案!
基本介紹
在Java這樣一個面向物件的語言中,例外被當成了一個物件來處理,其根類是java.lang.Throwable類,Throwable類有分成了兩個類,即Error和Exception,這是例外的兩個大類,他們分別代表了兩種情況:
- Error:不能處理的錯誤,這是系統內部的錯誤,運行時報錯,屬于系統問題,一般發生這種例外,JVM會選擇終止程式,開發人員需要提前避免,
- Exception:可以處理的例外,這是比較常見的例外,開發人員可以根據Java提供的類和問題對這類例外進行處理,

Error和Execption包括很多種情況,這才是我們需要考慮的,下面對它們進行分別介紹,
Error
對于嚴重錯誤Error,沒有辦法處理,只能做到提前避免,常見的Error有:StackOverflowError(內堆疊溢位錯誤)和OutOfMemoryError (記憶體溢位錯誤),
代碼示例
OutOfMemoryError
Java中堆是用來存盤物件實體的,,因此如果我們不斷地創建物件, 并且物件沒有被垃圾回收, 那么當創建的物件過多時, 會導致 heap 記憶體不足, 進而引發 OutOfMemoryError 例外.
/**
* 記憶體溢位
*/
public class Heap{
public static void main(String[] args){
//創建陣列list,用來保存物件
List<Integer> list = new ArryList<>();
int i=0;
while(true){
//不斷創建物件
list.add(i++);
}
}
}
StackOverflowError
JVM 的運行時資料區中有一個叫做堆疊的記憶體區域, 此區域的作用是: 每個方法在執行時都會創建一個堆疊幀, 用于存盤區域變數表、運算元堆疊、方法出口等資訊,因此當創建一個無限遞回的遞回呼叫, 當遞回深度過大時, 就會耗盡堆疊空間, 進而導致了 StackOverflowError 例外.
/**
* 堆疊溢位
*/
public class Stack{
public static void main(String[] args){
//呼叫方法
new Stack().test();
}
//創建測驗方法
public void test() {
//自己呼叫自己(遞回呼叫)
test();
}
}
Exception
一般來說,我們所說的例外就是指Exception,因為這類例外一旦出現,我們就要對代碼進行更正,修復程式進行處理,根據在編譯時期還是運行時期去檢查例外,可以將Exception分為:
- 編譯時期例外:checked例外,在編譯時期,就會檢查,如果沒有處理例外,則編譯失敗(開發工具會提示),如檔案找不到例外等,
- 運行時期例外:runtime例外,在運行時期,檢查例外.在編譯時期,運行例外不會被編譯器檢測到(不開發工具不會提示),如空指標例外,型別轉換例外,數字操作例外,型別不匹配例外等,
代碼示例
編譯時例外這里就不舉例了,在開發工具里會標紅提示,下面是常見的運行時例外代碼示例,
package com.atguigu.demo;
import org.junit.Test;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class Demo1 {
/*
編譯時例外:必須進行處理,否則編譯不通過
*/
//檔案找不到
@Test
public void test07() {
//這里FileInputStream報紅,編譯例外,需要處理
FileInputStream fis = new FileInputStream("Java例外學習筆記.txt");
}
/*
運行時例外
*/
public static void main(String[] args) {
//型別不匹配例外
Scanner input = new Scanner(System.in);
System.out.print("請輸入一個整數:");
//這個時獲取控制臺的輸入,如果輸入的不是整數,則報型別不匹配例外
int num = input.nextInt();
}
//空指標例外
@Test
public void testNullPointerException() {
String[] names = new String[5];
System.out.println(names[0].length());//字串的長度
}
//型別轉換例外
@Test
public void testClassCastException() {
Object obj = new Object();
String str = (String) obj;
}
//數學操作例外例外
@Test
public void testArithmeticException(){
int i = 1/0;
}
}
例外的處理
既然Java程式例外是非常常見的,那我們該如何處理它呢,由于Java將例外作為物件來處理,因此我們可以將Java例外的處理分成三個部分:
- Java程式出現例外時會生成一個例外類物件,該例外物件將被提交給Java運行時系統,這個程序稱為拋出(throw)例外,
- Java程式出現例外時將問題標識出來,報告給呼叫者,讓呼叫者去處理,這個程序通過throws進行宣告,
- Java程式出現例外時,在方法中使用try-catch的陳述句塊來處理例外,
throw
Java程式出現例外時會生成一個例外類物件,該例外物件將被提交給Java運行時系統,這個程序稱為拋出(throw)例外,例外物件的生成有兩種方式:
- 自動生成:程式運行程序中,虛擬機檢測到程式發生了問題,如果在當前代碼中沒有找到相應的處理程式,就會在后臺自動創建一個對應例外類的實體物件并拋出——自動拋出
- 手動創建:Exception exception = new ClassCastException();——創建好的例外物件不拋出對程式沒有任何影響,和創建一個普通物件一樣,但是一旦throw拋出,就會對程式運行產生影響了,
使用格式:
throw new 例外類名(引數);
代碼示例
package com.atguigu.demo;
public class Demo2 {
public static void main(String[] args) {
//定義陣列和訪問的角標
int[] arr = {1,2,3,4};
int index = 4; //測驗陣列越界例外
// int[] arr = {1,2,3,4}; //為null,測驗空指標例外
//呼叫方法測驗
int element = getElement(arr, index);
System.out.println(element);
}
public static int getElement(int[] arr, int index) {
//判斷陣列為空例外
if (arr == null){
throw new NullPointerException("陣列為空!");
}
//判斷陣列越界例外
// 陣列最大下標 arr.length-1
if (index < 0 || index > arr.length -1){
throw new ArrayIndexOutOfBoundsException("角標越界!");
}
int element = arr[index];
return element;
}
}
throws
Java程式出現例外時將問題標識出來,報告給呼叫者,讓呼叫者去處理,這個程序通過throws進行宣告,關鍵字throws運用于方法宣告之上,用于表示當前方法不處理例外,而是提醒該方法的呼叫者來處理例外(如果呼叫者不處理,則接著拋出例外).(不主動處理的方式,甩鍋給別人)
宣告例外格式:
修飾符 回傳值型別 方法名(引數) throws 例外類名1,例外類名2…{ } //可以宣告多個例外(也可直接一個Exception)
代碼示例
package com.atguigu.demo;
/*
宣告例外
*/
public class Demo4 {
//宣告一個Exception
public static void main(String[] args) throws Exception {
method();//不能直接呼叫,必須接著宣告例外或者處理例外,否則編譯不通過
}
//宣告多個例外
public static void method() throws
NullPointerException,ArrayIndexOutOfBoundsException{
System.out.println("宣告例外!");
}
}
try…catch
Java程式出現例外時,在方法中使用try-catch的陳述句塊來處理例外,try-catch的方式就是捕獲例外:Java中對例外有針對性的陳述句進行捕獲,可以對出現的例外進行指定方式的處理,(主動處理的方式,不甩鍋給別人)
捕獲例外語法如下:
try{
//可能會出現例外的代碼放在這里
}catch(例外型別 e){
//處理例外的代碼
//記錄日志/列印例外資訊/繼續拋出例外
}catch(例外型別 e){
//處理例外的代碼
//記錄日志/列印例外資訊/繼續拋出例外
}
...
注意: try和catch都不能單獨使用,必須連用(除非有finally,后面說),
catch可以有好幾個,即可以捕獲幾個例外
代碼示例
package com.atguigu.demo;
/*
try catch 捕獲例外
*/
public class Demo5 {
public static void main(String[] args) {
//獲取方法例外資訊
try {
//正常執行代碼
add();
} catch (Exception e) {
//捕獲例外
System.out.println("例外.......");
// String message = e.getMessage();
// System.out.println(message);
e.printStackTrace();
}
//多個例外捕獲
// catch(ArrayIndexOutOfBoundsException a) {
//
// }
}
//宣告例外
public static void add() throws Exception {
//System.out.println("add......");
int i = 1 / 0;
}
}
finally塊
在上述的try中,如果出現了例外,則例外后面的陳述句就不執行,但有些特定的陳述句是需要必須執行的,因此就需要finally塊就是解決這個問題的,這是因為在Java中finally代碼塊中存放的代碼都是一定會被執行的,
當在try陳述句塊中打開了一些物理資源(磁盤檔案/網路連接/資料庫連接等),我們都得在使用完之后關閉打開的資源,
finally的語法:
try{
}catch(...){
}finally{
//無論try中是否發生例外,也無論catch是否捕獲例外,也不管try和catch中是否有return陳述句,都一定會執行
}
或
try{
}finally{
//無論try中是否發生例外,也不管try中是否有return陳述句,都一定會執行
}
代碼示例
package com.atguigu.demo;
public class Demo6 {
public static void main(String[] args) {
try{
System.out.println("程式開始執行了");
int i = 1/0;
}catch (Exception e){
e.printStackTrace();
}finally {
System.out.println("這段代碼總會執行");//這里沒有寫前面說的資源情況,主要為了方便理解
}
}
}
finally與return(面試)
形式一:從try回來
public class TestReturn {
public static void main(String[] args) {
int result = test("12");
System.out.println(result);
}
public static int test(String str){
try{
Integer.parseInt(str);
return 1;
}catch(NumberFormatException e){
return -1;
}finally{
System.out.println("test結束");
}
}
}
形式二:從catch回來
public class TestReturn {
public static void main(String[] args) {
int result = test("a");
System.out.println(result);
}
public static int test(String str){
try{
Integer.parseInt(str);
return 1;
}catch(NumberFormatException e){
return -1;
}finally{
System.out.println("test結束");
}
}
}
形式三:從finally回來
public class TestReturn {
public static void main(String[] args) {
int result = test("a");
System.out.println(result);
}
public static int test(String str){
try{
Integer.parseInt(str);
return 1;
}catch(NumberFormatException e){
return -1;
}finally{
System.out.println("test結束");
return 0;
}
}
}
自定義例外
基本介紹
例外的情況有非常多,因此Java內部并不能把這些都包含進去,這就需要開發人員根據自己的實際業務情況進行自定義例外,比如年齡負數問題,考試成績負數問題等等,
例外類如何定義:
- 自定義一個編譯期例外::自定義類 并繼承于 java.lang.Exception,
- 自定義一個運行時期的例外類:自定義類 并繼承于 java.lang.RuntimeException,
代碼示例
package com.atguigu.demo;
public class Demo7 {
public static void main(String[] args){
try {
new Input().method();
}
catch(WrongInputException wie) {
System.out.println(wie.getMessage());
}
}
}
// 自定義的類繼承Exception
class WrongInputException extends Exception {
WrongInputException(String s) {
super(s);
}
}
class Input {
void method() throws WrongInputException {
// 拋出自定義的類
throw new WrongInputException("Wrong input");
}
}
例外注意事項
多個例外使用捕獲又該如何處理呢?
- 多個例外分別處理,
- 多個例外一次捕獲,多次處理,(推薦)
- 多個例外一次捕獲一次處理,
注意:多個例外一次捕獲,多次處理的方式,要求多個catch中的例外不能相同,并且若catch中的多個例外之間有子父類例外的關系,那么子類例外要求在上面的catch處理,父類例外在下面的catch處理,
-
運行時例外被拋出可以不處理,即不捕獲也不宣告拋出,
-
如果finally有return陳述句,永遠回傳finally中的結果,避免該情況.
-
如果父類拋出了多個例外,子類重寫父類方法時,拋出和父類相同的例外或者是父類例外的子類或者不拋出例外,
-
父類方法沒有拋出例外,子類重寫父類該方法時也不可拋出例外,此時子類產生該例外,只能捕獲處理,不能宣告拋出
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/401636.html
標籤:java
