日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

try catch对异常进行输出到日志、_java安全编码指南之:异常处理

發(fā)布時間:2024/8/5 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 try catch对异常进行输出到日志、_java安全编码指南之:异常处理 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

點擊上方的藍字關(guān)注我吧

程序那些事

簡介

異常是java程序員無法避免的一個話題,我們會有JVM自己的異常也有應(yīng)用程序的異常,對于不同的異常,我們的處理原則是不是一樣的呢?

一起來看看吧。

異常簡介

先上個圖,看一下常見的幾個異常類型。

所有的異常都來自于Throwable。Throwable有兩個子類,Error和Exception。

Error通常表示的是嚴重錯誤,這些錯誤是不建議被catch的。

注意這里有一個例外,比如ThreadDeath也是繼承自Error,但是它表示的是線程的死亡,雖然不是嚴重的異常,但是因為應(yīng)用程序通常不會對這種異常進行catch,所以也歸類到Error中。

Exception表示的是應(yīng)用程序希望catch住的異常。

在Exception中有一個很特別的異常叫做RuntimeException。RuntimeException叫做運行時異常,是不需要被顯示catch住的,所以也叫做unchecked Exception。而其他非RuntimeException的Exception則需要顯示try catch,所以也叫做checked Exception。

不要忽略checked exceptions

我們知道checked exceptions是一定要被捕獲的異常,我們在捕獲異常之后通常有兩種處理方式。

第一種就是按照業(yè)務(wù)邏輯處理異常,第二種就是本身并不處理異常,但是將異常再次拋出,由上層代碼來處理。

如果捕獲了,但是不處理,那么就是忽略checked exceptions。

接下來我們來考慮一下java中線程的中斷異常。

java中有三個非常相似的方法interrupt,interrupted和isInterrupted。

isInterrupted()只會判斷是否被中斷,而不會清除中斷狀態(tài)。

interrupted()是一個類方法,調(diào)用isInterrupted(true)判斷的是當前線程是否被中斷。并且會清除中斷狀態(tài)。

前面兩個是判斷是否中斷的方法,而interrupt()就是真正觸發(fā)中斷的方法。

它的工作要點有下面4點:

  • 如果當前線程實例在調(diào)用Object類的wait(),wait(long)或wait(long,int)方法或join(),join(long),join(long,int)方法,或者在該實例中調(diào)用了Thread.sleep(long)或Thread.sleep(long,int)方法,并且正在阻塞狀態(tài)中時,則其中斷狀態(tài)將被清除,并將收到InterruptedException。

  • 如果此線程在InterruptibleChannel上的I / O操作中處于被阻塞狀態(tài),則該channel將被關(guān)閉,該線程的中斷狀態(tài)將被設(shè)置為true,并且該線程將收到j(luò)ava.nio.channels.ClosedByInterruptException異常。

  • 如果此線程在java.nio.channels.Selector中處于被被阻塞狀態(tài),則將設(shè)置該線程的中斷狀態(tài)為true,并且它將立即從select操作中返回。

  • 如果上面的情況都不成立,則設(shè)置中斷狀態(tài)為true。

  • 看下面的例子:

    public void wrongInterrupted(){ try{ Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } }

    上面代碼中我們捕獲了一個InterruptedException,但是我們僅僅是打印出了異常信息,并沒有做任何操作。這樣程序的表現(xiàn)和沒有發(fā)送一異常一樣,很明顯是有問題的。

    根據(jù)上面的介紹,我們知道,interrupted()方法會清除中斷狀態(tài),所以,如果我們自身處理不了異常的情況下,需要重新調(diào)用Thread.currentThread().interrupt()重新拋出中斷,由上層代碼負責處理,如下所示。

    public void correctInterrupted(){ try{ Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }

    不要在異常中暴露敏感信息

    遇到異常的時候,通常我們需要進行一定程度的日志輸出,從而來定位異常。但是我們在做日志輸出的時候,一定要注意不要暴露敏感信息。

    下表可以看到異常信息可能會暴露的敏感信息:

    除了敏感信息之外,我們還要做好日志信息的安全保護。

    在處理捕獲的異常時,需要恢復(fù)對象的初始狀態(tài)

    如果我們在處理異常的時候,修改了對象中某些字段的狀態(tài),在捕獲異常的時候需要怎么處理呢?

    private int age=30; public void wrongRestore(){ try{ age=20; throw new IllegalStateException("custom exception!"); }catch (IllegalStateException e){ System.out.println("we do nothing"); } }

    上面的例子中,我們將age重置為20,然后拋出了異常。雖然拋出了異常,但是我們并沒有重置age,最后導(dǎo)致age最終被修改了。

    整個restore的邏輯沒有處理完畢,但是我們部分修改了對象的數(shù)據(jù),這是很危險的。

    實際上,我們需要一個重置:

    public void rightRestore(){ try{ age=20; throw new IllegalStateException("custom exception!"); }catch (IllegalStateException e){ System.out.println("we do nothing"); age=30; } }

    不要手動完成finally block

    我們在使用try-finally和try-catch-finally語句時,一定不要在finally block中使用return, break, continue或者throw語句。

    為什么呢?

    根據(jù)Java Language Specification(JLS)的說明,finally block一定會被執(zhí)行,不管try語句中是否拋出異常。

    在try-finally和try-catch-finally語句中,如果try語句中拋出了異常R,然后finally block被執(zhí)行,這時候有兩種情況:

    如果finally block正常執(zhí)行,那么try語句被終止的原因是異常R。

    如果在finally block中拋出了異常S,那么try語句被終止的原因?qū)兂蒘。

    我們舉個例子:

    public class FinallyUsage { public boolean wrongFinally(){ try{ throw new IllegalStateException("my exception!"); }finally { System.out.println("Code comes to here!"); return true; } } public boolean rightFinally(){ try{ throw new IllegalStateException("my exception!"); }finally { System.out.println("Code comes to here!"); } } public static void main(String[] args) { FinallyUsage finallyUsage=new FinallyUsage(); finallyUsage.wrongFinally(); finallyUsage.rightFinally(); }}

    上面的例子中,我們定義了兩個方法,一個方法中我們在finally中直接return,另一方法中,我們讓finally正常執(zhí)行完畢。

    最終,我們可以看到wrongFinally將異常隱藏了,而rightFinally保留了try的異常。

    同樣的,如果我們在finally block中拋出了異常,我們一定要記得對其進行捕獲,否則將會隱藏try block中的異常信息。

    不要捕獲NullPointerException和它的父類異常

    通常來說NullPointerException表示程序代碼有邏輯錯誤,是需要程序員來進行代碼邏輯修改,從而進行修復(fù)的。

    比如說加上一個null check。

    不捕獲NullPointerException的原因有三個。

    使用null check的開銷要遠遠小于異常捕獲的開銷。

    如果在try block中有多個可能拋出NullPointerException的語句,我們很難定位到具體的錯誤語句。

    最后,如果發(fā)生了NullPointerException,程序基本上不可能正常運行或者恢復(fù),所以我們需要提前進行null check的判斷。

    同樣的,程序也不要對NullPointerException的父類RuntimeException, Exception, or Throwable進行捕捉。

    不要throw RuntimeException, Exception, or Throwable

    我們拋出異常主要是為了能夠找到準確的處理異常的方法,如果直接拋出RuntimeException, Exception, 或者 Throwable就會導(dǎo)致程序無法準確處理特定的異常。

    通常來說我們需要自定義RuntimeException, Exception, 或者 Throwable的子類,通過具體的子類來區(qū)分具體的異常類型。

    不要拋出未聲明的checked Exception

    一般來說checked Exception是需要顯示catch住,或者在調(diào)用方法上使用throws做申明的。

    但是我們可以通過某些手段來繞過這種限制,從而在使用checked Exception的時候不需要遵守上述規(guī)則。

    當然這樣做是需要避免的。我們看一個例子:

    private static Throwable throwable; private ThrowException() throws Throwable { throw throwable; } public static synchronized void undeclaredThrow(Throwable throwable) { ThrowException.throwable = throwable; try { ThrowException.class.newInstance(); } catch (InstantiationException e) { } catch (IllegalAccessException e) { } finally { ThrowException.throwable = null; } }

    上面的例子中,我們定義了一個ThrowException的private構(gòu)造函數(shù),這個構(gòu)造函數(shù)會throw一個throwable,這個throwable是從方法傳入的。

    在undeclaredThrow方法中,我們調(diào)用了ThrowException.class.newInstance()實例化一個ThrowException實例,因為需要調(diào)用構(gòu)造函數(shù),所以會拋出傳入的throwable。

    因為Exception是throwable的子類,如果我們在調(diào)用的時候傳入一個checked Exception,很明顯,我們的代碼并沒有對其進行捕獲:

    public static void main(String[] args) { ThrowException.undeclaredThrow( new Exception("Any checked exception")); }

    怎么解決這個問題呢?換個思路,我們可以使用Constructor.newInstance()來替代class.newInstance()。

    try { Constructor constructor = ThrowException.class.getConstructor(new Class>[0]); constructor.newInstance(); } catch (InstantiationException e) { } catch (InvocationTargetException e) { System.out.println("catch exception!"); } catch (NoSuchMethodException e) { } catch (IllegalAccessException e) { } finally { ThrowException.throwable = null; }

    上面的例子,我們使用Constructor的newInstance方法來創(chuàng)建對象的實例。和class.newInstance不同的是,這個方法會拋出InvocationTargetException異常,并且把所有的異常都封裝進去。

    所以,這次我們獲得了一個checked Exception。

    更多精彩內(nèi)容

    1

    java安全編碼指南之:敏感類的拷貝

    2

    java安全編碼指南之:可見性和原子性

    3

    java安全編碼指南之:輸入校驗

    作者小F,金融科技從業(yè)多年,懂技術(shù)又懂金融,主攻Java和區(qū)塊鏈方向,篇篇都是用心之作,筆耕不輟,持續(xù)更新!

    微信號 : 程序那些事

    ●?掃碼關(guān)注我吧

    喜歡本篇文章?幫忙點個「在看」再走吧

    總結(jié)

    以上是生活随笔為你收集整理的try catch对异常进行输出到日志、_java安全编码指南之:异常处理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。