很多朋友對于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.javapublicclassTestTask{
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.javaprivatestaticclassExceptionHandlerimplementsThread.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是所有異常的父類的信息別忘了在本站進行查找哦。