非常全面的Java異常處理(全文干貨,值得收藏)
一.初始Java異常
1、對(duì)異常的理解:異常:在Java語言中,將程序執(zhí)行中發(fā)生的不正常情況稱為“異?!薄?開發(fā)過程中的語法錯(cuò)誤和邏輯錯(cuò)誤不是異常)
2、Java程序在執(zhí)行過程中所發(fā)生對(duì)異常事件可分為兩類:
- Error:Java虛擬機(jī)無法解決的嚴(yán)重問題。如:JVM系統(tǒng)內(nèi)部錯(cuò)誤、資源耗盡等嚴(yán)重情況。比如:StackOverflowError和OOM。一般不編寫針對(duì)性 的代碼進(jìn)行處理。
- Exception: 其它因編程錯(cuò)誤或偶然的外在因素導(dǎo)致的一般性問題,可以使用針對(duì)性的代碼進(jìn)行處理。例如:
- 空指針訪問
- 試圖讀取不存在的文件
- 網(wǎng)絡(luò)連接中斷
- 數(shù)組角標(biāo)越界
3、運(yùn)行時(shí)異常和編譯時(shí)異常
運(yùn)行時(shí)異常
- 是指編譯器不要求強(qiáng)制處置的異常。一般是指編程時(shí)的邏輯錯(cuò)誤,是程序員應(yīng)該積極避免其出現(xiàn)的異常。java.lang.RuntimeException類及它的子類都是運(yùn)行時(shí)異常。
- 對(duì)于這類異常,可以不作處理,因?yàn)檫@類異常很普遍,若全處理可能會(huì)對(duì)程序的可讀性和運(yùn)行效率產(chǎn)生影響。
編譯時(shí)異常
- 是指編譯器要求必須處置的異常。即程序在運(yùn)行時(shí)由于外界因素造成的一 般性異常。編譯器要求Java程序必須捕獲或聲明所有編譯時(shí)異常。
- 對(duì)于這類異常,如果程序不處理,可能會(huì)帶來意想不到的結(jié)果。

二.Error和Exception
1.Error
代碼示例一:java.lang.OutOfMemoryError(堆溢出)
public class ErrorTest {
public static void main(String[] args) {
//堆溢出:java.lang.OutOfMemoryError
Long[] arr = new Long[1024*1024*1024];
}
}
運(yùn)行結(jié)果:

代碼示例二:java.lang.StackOverflowError(棧溢出)
public class ErrorTest {
public static void main(String[] args) {
//棧溢出:java.lang.StackOverflowError
main(args);
}
}
運(yùn)行結(jié)果:

2.Exception(運(yùn)行時(shí)異常和編譯時(shí)異常)
運(yùn)行時(shí)異常
/* ******************以下是運(yùn)行時(shí)異常****************** */
//ArithmeticException
@Test
public void test1(){
int num1 = 3;
int num2 = 0;
int num3 = 3 / 0;
}
//InputMismatchException
@Test
public void test2(){
Scanner scanner = new Scanner(System.in);
int i = scanner.nextInt();
System.out.println(i);
scanner.close();
}
//NumberFormatException
@Test
public void test3(){
String str = "abcd";
int num = Integer.parseInt(str);
}
//ClassCastException
@Test
public void test4(){
Object obj = new Boolean(true);
String str = (String)obj;
}
//IndexOutOfBoundsException
@Test
public void test5(){
ArrayIndexOutOfBoundsException
Byte[] bytes = new Byte[3];
System.out.println(bytes[4]);
}
//NullPointerException
@Test
public void test6(){
int[] arr = null;
System.out.println(arr[1]);
}
編譯時(shí)異常
/* ******************以下是編譯時(shí)異常****************** */
@Test
public void test7(){
File file = new File("a.txt");
//java.io.FileNotFoundException
FileInputStream fis = new FileInputStream(file);
//java.io.IOException
int date = fis.read();
while (date != -1){
System.out.println((char)date);
date = fis.read();
}
fis.close();
}
ps:對(duì)于編譯時(shí)異常,我們需要異常處理
三.異常處理:抓拋模型
1.抓拋解釋
過程一:“拋”:程序在正常執(zhí)行的過程中,一旦出現(xiàn)異常,就會(huì)在異常代碼處生成一個(gè)對(duì)應(yīng)異常類的對(duì)象, 并將此對(duì)象拋出;一旦拋出對(duì)象以后,其后的代碼就不再執(zhí)行。
關(guān)于異常對(duì)象的產(chǎn)生:
① 系統(tǒng)自動(dòng)生成的異常對(duì)象
② 手動(dòng)的生成一個(gè)異常對(duì)象,并拋出(throw)
過程二:“抓”:可以理解為異常的處理方式:① try-catch-finally ② throws
2.try-catch-finally的使用
try{
//可能出現(xiàn)異常的代碼
}catch(異常類型1 變量名1){
//處理異常的方式1
}catch(異常類型2 變量名2){
//處理異常的方式2
}catch(異常類型3 變量名3){
//處理異常的方式3
}
…
finally{
//一定會(huì)執(zhí)行的代碼
}
說明:
- finally是可選的。
- 使用try將可能會(huì)出現(xiàn)異常的代碼段包裝起來,在執(zhí)行過程中,一旦出現(xiàn)異常,就會(huì)生成一個(gè)對(duì)應(yīng)異常類的對(duì)象,根據(jù)此對(duì)象的類型,去catch中進(jìn)行匹配
- 一旦try中的異常對(duì)象匹配到某一個(gè)catch時(shí),就進(jìn)入catch中進(jìn)行異常的處理。一旦處理完成,就跳出當(dāng)前的
try-catch結(jié)構(gòu)(在沒有寫finally的情況)。繼續(xù)執(zhí)行其后的代碼 - catch中的異常類型如果沒有子父類關(guān)系,則誰聲明在上,誰聲明在下無所謂。
catch中的異常類型如果滿足子父類關(guān)系,則要求子類一定聲明在父類的上面。否則,報(bào)錯(cuò) - 常用的異常對(duì)象處理的方式: ① String getMessage() ② printStackTrace()
- 在try結(jié)構(gòu)中聲明的變量,再出了try結(jié)構(gòu)以后,就不能再被調(diào)用
- try-catch-finally結(jié)構(gòu)可以嵌套
- finally中聲明的是一定會(huì)被執(zhí)行的代碼。即使catch中又出現(xiàn)異常了,try中有return語句,catch中有return語句等情況。
- 像數(shù)據(jù)庫連接、輸入輸出流、網(wǎng)絡(luò)編程Socket等資源,JVM是不能自動(dòng)的回收的,我們需要自己手動(dòng)的進(jìn)行資源的釋放。此時(shí)的資源釋放,就需要聲明在finally中。
示例一:
@Test
public void test1(){
String str = "abcd";
int num = 1314;
try {
num = Integer.parseInt(str);
System.out.println("進(jìn)入try代碼塊!");
}catch (NumberFormatException e){
System.out.println("出現(xiàn)數(shù)值轉(zhuǎn)換異常了!");
System.out.println(e.getMessage());
e.printStackTrace();
System.out.println("該catch語句塊將要執(zhí)行完了!");
} catch (NullPointerException e){
System.out.println("出現(xiàn)空指針異常!");
} catch (Exception e){
System.out.println("出現(xiàn)異常了");
}finally {
System.out.println("執(zhí)行finally語句了!");
}
System.out.println(num);
}
輸出結(jié)果:

示例二:
@Test
public void test2(){
File file = new File("a.txt");
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
int date = fis.read();
while(date != -1){
System.out.println((char)date);
date = fis.read();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}catch (IOException e){
e.printStackTrace();
}finally {
System.out.println("執(zhí)行finally語句了!");
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
輸出結(jié)果:

總結(jié):
- 使用try-catch-finally處理編譯時(shí)異常,是得程序在編譯時(shí)就不再報(bào)錯(cuò),但是運(yùn)行時(shí)仍可能報(bào)錯(cuò)。相當(dāng)于我們使用try-catch-finally將一個(gè)編譯時(shí)可能出現(xiàn)的異常,延遲到運(yùn)行時(shí)出現(xiàn)。
- 開發(fā)中,由于運(yùn)行時(shí)異常比較常見,所以我們通常就不針對(duì)運(yùn)行時(shí)異常編寫try-catch-finally了。針對(duì)于編譯時(shí)異常,我們說一定要考慮異常的處理。
3.throws + 異常類型的使用
"throws + 異常類型"寫在方法的聲明處。指明此方法執(zhí)行時(shí),可能會(huì)拋出的異常類型。一旦當(dāng)方法體執(zhí)行時(shí),出現(xiàn)異常,仍會(huì)在異常代碼處生成一個(gè)異常類的對(duì)象,此對(duì)象滿足throws后異常類型時(shí),就會(huì)被拋出。異常代碼后續(xù)的代碼,就不再執(zhí)行!
try-catch-finally:真正的將異常給處理掉了。
throws的方式只是將異常拋給了方法的調(diào)用者。 并沒有真正將異常處理掉。
子類重寫的方法拋出的異常類型不大于父類被重寫的方法拋出的異常類型(子類重寫的方法也可以不拋出異常)
public class SuperClass {
public void method() throws IOException {
}
}
class SubClass extends SuperClass{
//報(bào)錯(cuò),子類重寫的方法拋出的異常類型不大于父類被重寫的方法拋出的異常類型
// public void method() throws Exception{
//
// }
public void method() throws FileNotFoundException{
}
}
開發(fā)中如何選擇使用try-catch-finally 還是使用throws? 如果父類中被重寫的方法沒有throws方式處理異常,則子類重寫的方法也不能使用throws,意味著如果
子類重寫的方法中有異常,必須使用try-catch-finally方式處理。執(zhí)行的方法a中,先后又調(diào)用了另外的幾個(gè)方法,這幾個(gè)方法是遞進(jìn)關(guān)系執(zhí)行的。我們建議這幾個(gè)方法使用throws
的方式進(jìn)行處理。而執(zhí)行的方法a可以考慮使用try-catch-finally方式進(jìn)行處理。
代碼示例:
public class ErrorThrows {
public static void method1() throws IOException {
File file = new File("a.txt");
FileInputStream fileInputStream = new FileInputStream(file);
int data = fileInputStream.read();
while(data != -1){
System.out.println((char)data);
data = fileInputStream.read();
}
fileInputStream.close();
}
public static void method2() throws IOException {
method1();
}
public static void method3() throws IOException {
method1();
}
public static void main(String[] args) {
try {
method3();
} catch (IOException e) {
e.printStackTrace();
}
}
}
4.手動(dòng)拋出一個(gè)異常類對(duì)象(throw關(guān)鍵字使用)
代碼示例:
public class ReturnException {
static void method1(){
try{
System.out.println("進(jìn)入方法1");
throw new RuntimeException("手動(dòng)拋出異常");
}catch (Exception e){
e.printStackTrace();
System.out.println(e.getMessage());
} finally {
System.out.println("執(zhí)行finally語句了!");
}
}
public static void main(String[] args) {
method1();
}
}
輸出結(jié)果:

四.自定義異常類
自定義異常類,有如下三步驟:
- 繼承于現(xiàn)有的異常結(jié)構(gòu):RuntimeException 、Exception
- 提供全局常量:serialVersionUID
- 提供重載的構(gòu)造器
自定義異常類:
public class MyExceptionClass extends Exception{
static final long serialVersionUID = -5641210210148784L;
public MyExceptionClass() {
}
public MyExceptionClass(String message) {
super(message);
}
}
手動(dòng)拋出上述自定義的異常類對(duì)象:
public class MyExceptionTest {
static void method1() throws MyExceptionClass {
Scanner scanner = new Scanner(System.in);
System.out.println("請(qǐng)輸入大于0的數(shù)據(jù):");
double next = scanner.nextDouble();
if(next >0){
System.out.println("您輸入的數(shù)據(jù)為:"+next);
}else {
throw new MyExceptionClass("您輸入的數(shù)據(jù)不滿足要求!");
}
}
public static void main(String[] args) {
try {
method1();
} catch (MyExceptionClass myExceptionClass) {
myExceptionClass.printStackTrace();
}
}
}
運(yùn)行結(jié)果:

到此這篇關(guān)于非常全面的Java異常處理的文章就介紹到這了,更多相關(guān)Java異常處理干貨內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java Spring整合Freemarker的詳細(xì)步驟
本文對(duì)Spring整合Freemarker步驟做了詳細(xì)的說明,按步驟操作一定可以整合通過,這里提供給大家做參考2013-11-11
Springboot項(xiàng)目打war包docker包找不到resource下靜態(tài)資源的解決方案
今天小編就為大家分享一篇關(guān)于Springboot項(xiàng)目打war包docker包找不到resource下靜態(tài)資源的解決方案,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2019-03-03
Java Socket編程(三) 服務(wù)器Sockets
Java Socket編程(三) 服務(wù)器Sockets...2006-12-12
Spring Boot靜態(tài)資源路徑的配置與修改詳解
最近在做SpringBoot項(xiàng)目的時(shí)候遇到了“白頁”問題,通過查資料對(duì)SpringBoot訪問靜態(tài)資源做了總結(jié),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-09-09
Springboot整合ActiveMQ實(shí)現(xiàn)消息隊(duì)列的過程淺析
昨天仔細(xì)研究了activeMQ消息隊(duì)列,也遇到了些坑,下面這篇文章主要給大家介紹了關(guān)于SpringBoot整合ActiveMQ的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-02-02
springboot中如何將logback切換為log4j2
springboot默認(rèn)使用logback作為日志記錄框架,常見的日志記錄框架有l(wèi)og4j、logback、log4j2,這篇文章我們來學(xué)習(xí)怎樣將logbak替換為log4j2,需要的朋友可以參考下2023-06-06
Java編程guava RateLimiter實(shí)例解析
這篇文章主要介紹了Java編程guava RateLimiter實(shí)例解析,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-01-01

