開發者應該避免使用的6個Java功能

csdn發表於2013-10-22

  本文作者是一名擁有多年Java開發經驗的程式設計師,他從經驗中得出,並不是所有的Java SE功能/API都值得程式設計師去使用,比如本文列舉的這6個,大家在使用前得慎重對待。以下是對原文的摘譯。

  多年的Java開發經驗告訴我,從長遠角度來看,以下這些Java SE功能/API,開發者最好停止使用。 

  • Reflection
  • Bytecode manipulation 
  • ThreadLocals
  • Classloaders
  • Weak/Soft references
  • Sockets 

  1.Reflection

  Reflection即反射,在許多流行的庫裡面都有反射機制,比如Spring和Hibernate。通過對業務程式碼進行反思,我建議大家避免使用反射。下面列出我反對使用的原因:

  首先涉及到程式碼可讀性/工具支援。開啟IDE並且在Java程式碼裡找到相互依賴關係。使用relection替換方法呼叫,並且試著重複該步驟。事情變的愈發不可收拾,正常情況下都應該封裝好了再修改狀態。下面來看看具體程式碼示例:

public class Secret {

    private String secrecy; 

    public Secret(String secrecy) { 

        this.secrecy = secrecy; 

    } 

    public String getSecrecy() { 

        return null; 

    } 

} 

public class TestSecrecy { 

    public static void main(String[] args) throws Exception { 

        Secret s = new Secret("TOP SECRET"); 

        Field f = Secret.class.getDeclaredField("secrecy"); 

        f.setAccessible(true); 

        System.out.println(f.get(s)); 

    } 

}

  通過檢視以上程式碼可以得知,方法getDeclaredField()引數只有在執行時才可以被發現。而你也清楚,執行時產生的bug總比不執行指令碼要更加棘手。

  其次,反射呼叫優化是由JIT執行的,一些優化可能需要花費很長時間才能得到應用,而有些優化甚至都得不到應用,所以關於反射的效能優化有時會被數量化。但在一個典型的業務應用程式中——你可能不會真正意識到這些效能開銷。

  總之,開發者應該通過AOP合理地在業務層使用反射,除此以外,你最好離它遠遠的。

  2.Bytecode manipulation.

  位元組碼操作,如果我看到你在Java EE應用程式裡直接使用CGLIBASM,我可能會立即跑開。

  最糟糕的事情莫過於在編譯期間沒有任何可執行的程式碼。實際上,當產品在執行時,你根本不知道哪塊程式碼在執行。所以,當你遇到麻煩時,會自然地把錯誤拋給執行時故障排除和除錯,不過這樣反而會更麻煩。

  3.ThreadLocals

  這裡有兩個不相關的原因,當我在業務層程式碼裡看到ThreadLocals時會顫抖。首先,在ThreadLocals的幫助裡,你可能會看到許多變數的使用都沒有通過方法呼叫鏈來明確地向下傳遞。這在某些場合下是有用的,但當你一旦粗心,你會在程式碼裡構建許多意料不到的依賴關係。

  第二個不相關的原因與我日常的工作相關,在ThreadLocals裡儲存資料會引發記憶體洩露。最起碼我遇到的Permgen洩露有十分之一都是使用ThreadLocals造成的,在結合了類載入器和執行緒池後,“java.lang.OutOfMemoryError:Permgen space”異常可能就馬上出現了。

  4.Classloaders

  首先,類載入器是一個複雜的野獸。你必須先了解它的層次結構、委託機制、類快取等等。即使你認為自己已經掌握了,它可能還是不能正常工作。最終將導致一個類載入器洩露問題。因此我只能建議你將這個任務留給應用伺服器處理

  5.Weak/Soft references

  現在,你應該更好的理解Java的內部方法。使用軟引用來重寫所有的快取並不明智。我知道,當你手上拿著錘子的時候,就會到處尋找釘子。可對於錘子來說,快取並不是個好釘子。為什麼?基於軟引用構建快取可能是如何委託一些複雜因素到GC而不是通過自身實現的一個好例子。

  下面舉個快取的例子,你使用軟引用來建立資料,當記憶體被耗盡時,GC進入並且進行清理。但是,快取中被刪除的物件並未得到你的控制,而且很有可能在下一次的cache-miss中重新建立。如果記憶體仍然不足,你可以觸發GC進行再次清理。你可能已經看出了整個執行過程的惡性迴圈,整個應用程式就變成了CPU與GC不斷執行的狀態了

  6.Sockets 

  普通老式的java.net.Socket實在是太複雜,以至於很難弄正確。我覺得阻塞性是其根本性的缺陷。當你編寫一個典型的帶有Web前端的Java EE應用程式時,應用程式需要高併發度來支援大量的使用者,而你現在最不想發生的是不具有可擴充套件的執行緒池坐等阻塞套接字。

  目前有許多精彩可用的第三方庫,使用它們可以更好的完成任務,比如Netty,開發者不妨嘗試下。

  來自:Plumbr

相關文章