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

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

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

1.Reflection

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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,開發者不妨嘗試下。(
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章