- N +

throwable是所有異常的父類,所有異常對象的父類是

很多朋友對于throwable是所有異常的父類和所有異常對象的父類是不太懂,今天就由小編來為大家分享,希望可以幫助到大家,下面一起來看看吧!

JAVA語言如何進行異常處理,在try塊中可以拋出異常嗎

首先是可以在try塊中拋出異常的。

您可以使用throw語句顯示的拋出異常。throw的一般形式如下所示。

throwthrowableInstance;

其中throwableInstance必須是throwable或者其子類。基本類型如intchar以及非throwable類如String和object都不能做為異常。可以通過兩種方式獲得throwable對象

1.catch語句中使用參數或者new運算符創(chuàng)建。

當時要注意throw以后執(zhí)行的流會立即停止。

線程異常,如何檢測,解決

線程出現(xiàn)異常測試

任務類:Task.javapublicclassTaskimplementsRunnable{

privateinti;

publicTask(inti){

this.i=i;

}

@Override

publicvoidrun(){

if(i==5){

//System.out.println("throwexception");

thrownewIllegalArgumentException();

}

System.out.println(i);

}

}

如果i==5,將拋出一個異常

線程測試類:TaskTest.java

publicclassTestTask{

publicstaticvoidmain(String[]args){

inti=0;

while(true){

if(i==10)break;

try{

newThread(newTask(i++)).start();

}catch(Exceptione){

System.out.println("catchexception...");

}

}

}

}

通過使用try-catch,嘗試對拋出的異常進行捕獲

測試結果

ConnectedtothetargetVM,address:'127.0.0.1:64551',transport:'socket'

0

1

2

3

4

6

7

8

9

Exceptioninthread"pool-1-thread-1"java.lang.IllegalArgumentException

atcom.h2t.study.thread.Task.run(Task.java:21)

atjava.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)

atjava.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)

atjava.lang.Thread.run(Thread.java:748)

異常沒有被捕獲,只是在控制臺打印了異常,并且不影響后續(xù)任務的執(zhí)行emmmm這是為什么呢,捕獲不到異常就不知道程序出錯了,到時候哪天有個任務不正常排查都排查不到,這樣是要不得的。看一下Thread這個類,有個叫dispatchUncaughtException的方法,作用如其名,分發(fā)未捕獲的異常,把這段代碼揪出來:Thread#dispatchUncaughtException

privatevoiddispatchUncaughtException(Throwablee){

getUncaughtExceptionHandler().uncaughtException(this,e);

}

findusage是找不到該方法在哪里調用的,因為這個方法只被JVM調用Thread#getUncaughtExceptionHandler:獲取UncaughtExceptionHandler接口實現(xiàn)類

publicUncaughtExceptionHandlergetUncaughtExceptionHandler(){

returnuncaughtExceptionHandler!=null?

uncaughtExceptionHandler:group;

}

UncaughtExceptionHandler是Thread中定義的接口,在Thread類中uncaughtExceptionHandler默認是null,因此該方法將返回group,即實現(xiàn)了UncaughtExceptionHandler接口的ThreadGroup類UncaughtExceptionHandler#uncaughtException:ThreadGroup類的uncaughtException方法實現(xiàn)

publicvoiduncaughtException(Threadt,Throwablee){

if(parent!=null){

parent.uncaughtException(t,e);

}else{

Thread.UncaughtExceptionHandlerueh=

Thread.getDefaultUncaughtExceptionHandler();

if(ueh!=null){

ueh.uncaughtException(t,e);

}elseif(!(einstanceofThreadDeath)){

System.err.print("Exceptioninthread\""

+t.getName()+"\"");

e.printStackTrace(System.err);

}

}

}

因為在Thread類中沒有對group【parent】和defaultUncaughtExceptionHandler【Thread.getDefaultUncaughtExceptionHandler】進行賦值,因此將進入最后一層條件,將異常打印到控制臺中,對異常不做任何處理。整個異常處理器調用鏈如下:

首先判斷默認異常處理器【defaultUncaughtExceptionHandler】是不是為null,在判斷線程組異常處理器【group】是不是為null,在判斷自定義異常處理器【uncaughtExceptionHandler】是不是為null,都為null則在控制臺打印異常

線程異常處理

分析了一下源碼就知道如果想對任務執(zhí)行過程中的異常進行處理一個就是讓ThreadGroup不為null,另外一種思路就是讓UncaughtExceptionHandler類型的變量值不為null。

異常處理器:ExceptionHandler.java

privatestaticclassExceptionHandlerimplementsThread.UncaughtExceptionHandler{

@Override

publicvoiduncaughtException(Threadt,Throwablee){

System.out.println("異常捕獲到了:"+e);

}

}

設置默認異常處理器

Thread.setDefaultUncaughtExceptionHandler((t,e)->System.out.println("異常捕獲到了:"+e));

inti=0;

while(true){

if(i==10)break;

Threadthread=newThread(newTask(i++));

thread.start();

}

打印結果:

0

2

1

3

9

6

7

4

異常捕獲到了:java.lang.IllegalArgumentException

8

通過設置默認異常就不需要為每個線程都設置一次了

設置自定義異常處理器

Threadt=newThread(newTask(i++));

t.setUncaughtExceptionHandler(newExceptionHandler());

打印結果:

0

2

4

異常捕獲到了:java.lang.IllegalArgumentException

6

1

3

7

9

8

設置線程組異常處理器

MyThreadGroupmyThreadGroup=newMyThreadGroup("測試線程線程組");

Threadt=newThread(myThreadGroup,newTask(i++))

自定義線程組:MyThreadGroup.java

privatestaticclassMyThreadGroupextendsThreadGroup{

publicMyThreadGroup(Stringname){

super(name);

}

@Override

publicvoiduncaughtException(Threadt,Throwablee){

System.out.println("捕獲到異常了:"+e);

}

}

打印結果:

1

2

0

4

3

6

7

8

9

捕獲到異常了:java.lang.IllegalArgumentException

線程組異常捕獲處理器很適合為線程進行分組處理的場景,每個分組出現(xiàn)異常的處理方式不相同設置完異常處理器后異常都能被捕獲了,但是不知道為什么設置異常處理器后任務的執(zhí)行順序亂了,難道是因為為每個線程設置異常處理器的時間不同【想不通】

線程池異常處理

一般應用中線程都是通過線程池創(chuàng)建復用的,因此對線程池的異常處理就是為線程池工廠類【ThreadFactory實現(xiàn)類】生成的線程添加異常處理器

默認異常處理器

Thread.setDefaultUncaughtExceptionHandler(newExceptionHandler());

ExecutorServicees=Executors.newCachedThreadPool();

es.execute(newTask(i++))

自定義異常處理器

ThreadPoolExecutorthreadPoolExecutor=newThreadPoolExecutor(1,1,

0L,TimeUnit.MILLISECONDS,

newLinkedBlockingQueue<Runnable>());

threadPoolExecutor.setThreadFactory(newMyThreadFactory());

threadPoolExecutor.execute(newTask(i++));

自定義工廠類:

MyThreadFactory.java

privatestaticclassMyThreadFactoryimplementsThreadFactory{

@Override

publicThreadnewThread(Runnabler){

Threadt=newThread();

//自定義UncaughtExceptionHandler

t.setUncaughtExceptionHandler(newExceptionHandler());

returnt;

}

}

設計原則,為什么要由線程自身進行捕獲

來自JVM的設計理念"線程是獨立執(zhí)行的代碼片斷,線程的問題應該由線程自己來解決,而不要委托到外部"。因此在Java中,線程方法的異常【即任務拋出的異常】,應該在線程代碼邊界之內處理掉,而不應該在線程方法外面由其他線程處理

線程執(zhí)行Callable任務

前面介紹的是線程執(zhí)行Runnable類型任務的情況,眾所周知,還有一種有返回值的Callable任務類型測試代碼:

TestTask.java

publicclassTestTask{

publicstaticvoidmain(String[]args){

inti=0;

while(true){

if(i==10)break;

FutureTask<Integer>task=newFutureTask<>(newCallableTask(i++));

Threadthread=newThread(task);

thread.setUncaughtExceptionHandler(newExceptionHandler());

thread.start();

}

}

privatestaticclassExceptionHandlerimplementsThread.UncaughtExceptionHandler{

@Override

publicvoiduncaughtException(Threadt,Throwablee){

System.out.println("異常捕獲到了:"+e);

}

}

}

打印結果:

DisconnectedfromthetargetVM,address:'127.0.0.1:64936',transport:'socket'

0

1

2

3

4

6

7

8

9

觀察結果,異常沒有被捕獲,thread.setUncaughtExceptionHandler(newExceptionHandler())方法設置無效,emmmmm,這又是為什么呢,在問為什么就是十萬個為什么兒童了。查看FutureTask的run方法,F(xiàn)utureTask#run:

publicvoidrun(){

if(state!=NEW||

!UNSAFE.compareAndSwapObject(this,runnerOffset,

null,Thread.currentThread()))

return;

try{

Callable<V>c=callable;

if(c!=null&&state==NEW){

Vresult;

booleanran;

try{

result=c.call();

ran=true;

}catch(Throwableex){

result=null;

ran=false;

setException(ex);

}

if(ran)

set(result);

}

}finally{

//runnermustbenon-nulluntilstateissettledto

//preventconcurrentcallstorun()

runner=null;

//statemustbere-readafternullingrunnertoprevent

//leakedinterrupts

ints=state;

if(s>=INTERRUPTING)

handlePossibleCancellationInterrupt(s);

}

}

FutureTask#setException:

protectedvoidsetException(Throwablet){

if(UNSAFE.compareAndSwapInt(this,stateOffset,NEW,COMPLETING)){

//將異常設置給outcome變量

outcome=t;

//設置任務的狀態(tài)為EXCEPTIONAL

UNSAFE.putOrderedInt(this,stateOffset,EXCEPTIONAL);//finalstate

finishCompletion();

}

}

看到catch這段代碼,當執(zhí)行任務捕獲到異常的時候,會將任務的處理結果設置為null,并且調用setException方法對捕獲的異常進行處理,因為setUncaughtExceptionHandler只對未捕獲的異常進行處理,F(xiàn)utureTask已經對異常進行了捕獲處理,因此調用setUncaughtExceptionHandler捕獲異常無效對任務的執(zhí)行結果調用get方法:

inti=0;

while(true){

if(i==10)break;

FutureTask<Integer>task=newFutureTask<>(newCallableTask(i++));

Threadthread=newThread(task);

thread.setUncaughtExceptionHandler(newExceptionHandler());

thread.start();

//打印結果

try{

System.out.println(task.get());

}catch(Exceptione){

System.out.println("異常被抓住了,e:"+e);

}

}

執(zhí)行結果將會將捕獲到的異常打印出來,執(zhí)行結果:

0

1

2

3

4

異常被抓住了,e:java.util.concurrent.ExecutionException:java.lang.IllegalArgumentException

6

7

DisconnectedfromthetargetVM,address:'127.0.0.1:50900',transport:'socket'

8

9

FutureTask#get:

publicVget()throwsInterruptedException,ExecutionException{

ints=state;

if(s<=COMPLETING)

//未完成等待任務執(zhí)行完成

s=awaitDone(false,0L);

returnreport(s);

}

FutureTask#report:

privateVreport(ints)throwsExecutionException{

Objectx=outcome;

if(s==NORMAL)

return(V)x;

if(s>=CANCELLED)

thrownewCancellationException();

thrownewExecutionException((Throwable)x);

}

outcome在setException方法中被設置為了異常,并且s為state的狀態(tài)最終8被設置為EXCEPTIONAL,因此方法將捕獲的任務拋出【newExecutionException((Throwable)x)】

總結:

Callable任務拋出的異常能在代碼中通過try-catch捕獲到,但是只有調用get方法后才能捕獲到

【北京】IT技術人員面對面試、跳槽、升職等問題,如何快速成長,獲得大廠入門資格和升職加薪的籌碼?與大廠技術大牛面對面交流,解答你的疑惑。《從職場小白到技術總監(jiān)成長之路:我的職場焦慮與救贖》活動鏈接:http://mk1.top/1ndjnvb

想了解更多Java相關,百度搜索圈T社區(qū)www.aiquanti.com,免費視頻教程。純干貨

Error與Exception有什么區(qū)別

1)error都是繼承自父類java.lang.Error,而exception都繼承自java.lang.Exception.

2)再看看JDK中對于java.lang.Error和java.lang.Exception的解釋。java.lang.Error:AnErrorisasubclassofThrowablethatindicatesseriousproblemsthatareasonableapplicationshouldnottrytocatch.Mostsucherrorsareabnormalconditions.即:Error是Throwable的子類,用于標記嚴重錯誤。合理的應用程序不應該去try/catch這種錯誤。絕大多數的錯誤都是非正常的,就根本不該出現(xiàn)的。java.lang.Exception:TheclassExceptionanditssubclassesareaformofThrowablethatindicatesconditionsthatareasonableapplicationmightwanttocatch.即Exception是Throwable的一種形式的子類,用于指示一種合理的程序想去catch的條件。即它僅僅是一種程序運行條件,而非嚴重錯誤,并且鼓勵用戶程序去catch它。

3)Error和RuntimeException及其子類都是未檢查的異常(uncheckedexceptions),而所有其他的Exception類都是檢查了的異常(checkedexceptions).checkedexceptions:通常是從一個可以恢復的程序中拋出來的,并且最好能夠從這種異常中使用程序恢復。比如FileNotFoundException,ParseException等。uncheckedexceptions:通常是如果一切正常的話本不該發(fā)生的異常,但是的確發(fā)生了。比如ArrayIndexOutOfBoundException,ClassCastException等。從語言本身的角度講,程序不該去catch這類異常,雖然能夠從諸如RuntimeException這樣的異常中catch并恢復,但是并不鼓勵終端程序員這么做,因為完全沒要必要。因為這類錯誤本身就是bug,應該被修復,出現(xiàn)此類錯誤時程序就應該立即停止執(zhí)行。因此,面對Errors和uncheckedexceptions應該讓程序自動終止執(zhí)行,程序員不該做諸如try/catch這樣的事情,而是應該查明原因,修改代碼邏輯。

自定義異常繼承Exception和RunTimeException的區(qū)別

謝邀,好處是運行時異常可以捕獲,也就可以手工處理還可以編譯通過。

runtimeexception是一個具體異常,發(fā)生在運行的時候如內存泄漏,下標越界,空指針等異常。

exception是異常定義,繼承throwable。它也是runtimeex的父類。它處理的范圍大于runtimeex。就這些了吧。

java為什么總是需要拋各種異常

首先,我們知道Java有3種拋出異常的形式:throw(執(zhí)行的時候一定拋出某種異常對象),throws(出現(xiàn)異常的可能性,不一定會發(fā)生),系統(tǒng)自動拋異常。

throw用在一個語句拋出異常的時候,throw(aninstanceofexceptionclass)比如一個方法/函數里,try{…}catch(Exceptione){thrownewArithmeticException(“XXX”);}finally{…};

throws則是用在聲明方法可能拋出異常的時候,throw(exceptionclass)比如publicintdivision(intx,inty)throwsArithmeticException{…};

系統(tǒng)自動拋異常則是當程序語句出現(xiàn)邏輯錯誤,主義錯誤或類型轉換錯誤的時候,系統(tǒng)自動拋出異常,比如inta=5;intb=0;c=a/b;這個時候移動會自動拋出ArithmeticException。

什么是異常

異常,顧名思義,就是有異于正常狀態(tài),有錯誤發(fā)生。而這錯誤會阻止Java當前函數方法的運行。

那么Java里面異常的體系是怎么樣的呢?

1.Java里面所有不正常類都繼承于Throwable類;而Throwable類包括2類:Error類和Exception類。

2.Error類包括虛擬機錯誤(VirtualMachineError)和線程死鎖(ThreadDeath)。

3.Exception類則是我們在說的異常;包括運行時異常(RuntimeException)和檢查異常;這里的異常通常是編碼,環(huán)境,用戶操作輸入出現(xiàn)了問題。

4.運行時異常(RuntimeException)包括以下4種異常:空指針異常(NullPointerException),數組下標越界異常(ArrayIndexOutOfBoundsException),類型轉換異常(ClassCastException),算術異常(ArithmeticException)。

空指針異常:

數組下標越界異常:

類型轉換異常:

算術異常:

5.最后剩下的檢查異常則是剩下各種異常的集合;這里發(fā)生異常的原因有很多,文件異常(IOException),連接異常(SQLException)等等;和運行時異常不同的是,這里的異常我們必須手動在代碼里添加try…catch…(finally…)語句來捕獲處理。

今天又了解學習到了一些具體的額外的異常:

Throw拋出異常詳細過程

和throws聲明方法可能會發(fā)生異常不同,throw語句則是直接拋出一個異常。

前面有提到,throw(aninstanceofexceptionclass),這里的一個exception類的實例其實也可以說是一個ExceptionObject(Throwable類或則其子類的對象;也可以是自定義的繼承自Throwable的直接或間接的異常類)。如果,我們用了thrownewString(“異常XXX”);則會在編譯的時候報錯,因為String類并不是Throwable類的子類。

接著讓我們回到怎么用throw語句的階段。

一般我們有兩種方式來用throw:直接在某處會發(fā)生異常的地方用throw語句或則用try…catch…finally…語句來捕獲處理異常和關閉釋放資源。

首先是第一種,直接在某處會發(fā)生異常的地方用throw語句;這是一種主動的方法,主動拋出異常去處理。

而第二種,用try…catch…finally…語句來捕獲處理異常和關閉釋放資源則是被動的方法。try里面放入可能會發(fā)生異常的語句塊,如果在運行期間遇到了異常,則會交給catch來處理異常(catch可以是多個,處理不同的異常),finally則是無論有沒有異常發(fā)生,只要加上了就會運行。

首先我們來看第一種方法的函數:

我們的intc=4/2,其實是正確的;但是我們的throw語句主動拋出了異常,那么程序就會到catch里面找有沒有這個異常,有的話進行處理。所以我們要主動拋異常的話,要很確信這個代碼一定會發(fā)生異常且后期不太會去變動了(最好放在if條件語句里)。所以我們得到的結果如下:

接著我們來看第二種方法。我們一開始先測正確的,只是把主動拋出異常語句給注釋掉:

因為try里面的語句塊沒有異常,所以只執(zhí)行了try和finally里面的語句塊。運行的結果如下:

我們接著來測當try里面的語句塊有異常,且沒有主動拋出異常的時候,try會不會捕捉到異常吧:

得到的結果如下,會去處理異常和執(zhí)行finally里面的語句塊:

最后深入理解一點try里面的異常觸發(fā)會逐層向上的這個概念。在我們try語句里主動/被動拋出異常的時候,程序會調向調用者程序(上面的例子里就是我們自己這個函數;但有的時候我們會在try語句里執(zhí)行別的函數比如B,這個函數B里我們假如觸發(fā)了異常,它會調向try語句所在的函數A),尋找和它相匹配的catch語句,執(zhí)行catch語句里面相應的異常處理程序;但假如沒有找到相匹配的catch語句,那么它會再轉向上一層的調用程序…這樣逐層向上,直到最外層的異常程序終止程序并打印出stacktrace。

參考資料

rollbar.com/guides/java…www.javatpoint.com/throw-keywo…www.geeksforgeeks.org/throw-throw…

本文分享自華為云社區(qū)《Java-throw異常詳解以及過程-云社區(qū)-華為云》,作者:gentle_zhou。

throwable是所有異常的父類的介紹就聊到這里吧,感謝你花時間閱讀本站內容,更多關于所有異常對象的父類是、throwable是所有異常的父類的信息別忘了在本站進行查找哦。

返回列表
上一篇:
下一篇: