2009-02-24 50 views
4

我正在考慮編寫一個程序來檢查Java中的「泄漏抽象」 。這突然出現在腦海馬上一個領域是例外:Java漏洞抽象檢查器

public class X 
{ 
    // this one is fine, Readers throw IOExceptions so it is 
    // reasonable for the caller to handle it 
    public void parse(final Reader r) 
     throws IOException 
    { 
    } 

    // This one is bad. Nothing in the API indicate that JDBC 
    // is being used at all. 
    public void process() 
     throws SQLException 
    {  
    } 
} 

注意,我不想上選中/ unchecked異常的相對優點的爭論。我正在尋找的是其他的例子(不一定是異常處理),人們也可以通過檢查源代碼或類文件合理地捕捉到這些例子。

我知道checkstyle,findbugs和PMD,而AFAIK沒有一個處理這個問題(我不反對把這些工具放到其中一個工具裏,而不是寫我自己的)。

是否有任何其他泄漏抽象的例子,你想到可以靜態檢查?

編輯:

之所以第二個是壞的是,該方法拋出,其中客戶端無法知道JDBC(例如,它可以是任何東西)的方式產生的異常正在使用。所以「泄漏抽象」是JDBC正在被使用。如果底層機制改變爲其他方式(比如說JPA是一個不同的數據庫抽象庫),那麼異常也都需要改變。所以底層的數據庫庫被泄漏出去了。

+0

那麼,是要確定API沒有停留在正確的抽象層次上?這個問題可能是語義上的,因爲只能做出這樣的判斷(很多時候我們做錯了)。mmmhhh – OscarRyz 2009-02-24 03:11:34

+0

是的,如果你想改變它,它會是主觀的。這個想法是指出清理代碼可能有意義的地方。 – TofuBeer 2009-02-24 03:23:28

+0

對,很有意思。 – OscarRyz 2009-02-24 03:47:28

回答

2

所以。

如何檢測API是否泄漏實現細節或不保持相同的抽象級別。你可能會看到this talk。它解釋了良好的API看起來怎麼樣和設計(可以從良好做法有哪些不良行爲扣除)

例如

功能應該是很容易解釋。 如果它的名字很難,通常是一個糟糕的設計。

從中你可以發現,如果方法或返回參數給出了詳細的指令,他們不與抽象層次一起。

比如一個高級方法

-initProcess(): SGN_MTL 

可以在返回值泄漏implemntation細節。

這裏最困難的部分是檢測抽象級別何時發生變化。

例如,在您的方法中,如果自身的代碼是JDCB圖層的實現,則可以將SQLExceptions全部拋出。

其他來源你可以看到更多的這些主題是這個列表。 http://www.jetbrains.com/idea/documentation/inspections.jsp

查看「抽象」下的項目,即。

  • 具體類的實例變量:當實例變量的類型被聲明爲具體類而不是接口時報告。

典型的例子是:

private ArrayList list; 

時,這將是更好的一個又一個的

private List list; 
0

您可以考慮擴展您的示例以檢查是否違反Liskov Substitution Principle。有些人會說,實現接口的類只應拋出與接口定義的相同的異常。

如果您可以分析對象的使用情況,則最好提示可以使用更一般的類型(例如,當IDBConnection需要時,該方法需要SQLConnection)。

+0

對於Java而言,實現不能拋出與接口不同的類型(它可以拋出聲明異常的子類)。最終的想法是讓這個工具提供一個更好的例外,如果存在的話,或者至少讓程序知道他們應該做出一個,如果他們想要的話。 – TofuBeer 2009-02-24 02:54:47

2

因爲我沒有在原文中檢測到問題,我會漫遊。

任何這樣的工具都必須讓用戶告訴它什麼異常有資格作爲給定類的非泄漏,並且任何不在這樣的清單上的東西都是泄漏。

這只是例外。據我瞭解,抽象漏洞更多。考慮一下:

class Client 
{ 
    private Integer ID; 

    public Integer ID() { return this.ID; } 
} 

這是否屬於泄漏?如果以後我需要將ID表示爲Long,那麼它就是。您可能會修復這樣的情況:

class Client 
{ 
    private ClientID ID; 

    public ClientID ID() { return this.ID; } 
} 

class ClientID 
{ 
    private Integer value; 

    public ClientID(String id) { this.value = Integer.parseInt(id); } 

    public String asString() { return value.toString(); } 

    ... other methods that don't reveal value's type here ... 
} 

這將解決客戶端泄漏問題,但現在您將在ClientID上運行您的工具。它是否漏水?

如果您必須檢查不是簡單的getter方法,這可能會變得更加複雜。如果ClientID有一個方法對其ID進行了一些數學運算(放縱我)並返回一個整數。這是泄漏嗎?這是否屬於泄漏該值是一個整數?

所以我不確定這是否是一種機器很容易捕獲的代碼味道。

0

思想。有一個處理非公開類型的公共成員。

 
class Foo { ... } // local to the package 

public class Bar 
{ 
    class Car() { ... } 

    public Bar(Foo f) { ... } 

    public Car star() { ... } 
} 

酒吧和明星會漏水。您可以看到Bar構造函數b,但只能在Bar類的相同包中調用它。您可以調用星型方法,但只能將返回值用作對象。

對於這兩種情況,您都會看到您需要考慮讓成員爲私人或包訪問或公開類型。