1、給不可實例化的類提供私有構造器
比如:每個項目中都有很多工具類,提供了很多static類型的方法供大家使用,誰也不希望看到下面的代碼:
- TextUtils textUtils = new TextUtils();
- if(textUtils.isDigitsOnly("123"))
- {
- //doSometing
- }else
- {
- //doSomething
- }
爲工具類添加私有構造器:
- public class TextUtils {
- private TextUtils() { /* cannot be instantiated */ }
這是android的TextUtils的源碼,這樣就可以了,讓他妹的初始化實例~,當然你也可以在私有方法裏面扔個異常。
- public class TextUtils
- {
- private TextUtils()
- {
- /* cannot be instantiated */
- throw new UnsupportedOperationException("cannot be instantiated");
- }
- }
對於異常的使用,一儘量使用Java提供的異常類,這樣可以使你的API比較易讀和易懂。
2、正確使用String,避免創建不必要的對象
很多人面試的時候都遇到過這樣的問題:String s = new String("abc");請問創建了幾個對象。也從側面說明了這是個反面的代碼寫法:
a、String s = new String("abc");“abc”本身就是一個String的實例,所以new String創建了不必要的String實例
b、如果改寫成 String s = "abc",不僅只創建了一個實例,而且在同一臺VM中,對於“abc”(字符串的字面常量)還會重用。
3、優先使用基本類型,Java提供了8種基本類型,以及對應的裝箱基本類型,且在Java1.5 提供了自動裝箱和解箱操作,雖然方便了代碼的編寫,但是如果不注意,可能帶來不好的效果。
看下面的代碼:
- long start = System.nanoTime();
- Long sum = 0L;
- for (long i = 0; i < Integer.MAX_VALUE; i++)
- {
- sum += i;
- }
- System.out.println(sum);
- System.out.println(System.nanoTime() - start);//20995956735
如果你觀察了內存,會發現,一直GC一直在內存回收,並且計算時間需要20多秒,如果我說這段代碼有個bug,導致代碼運行很慢,以及耗費內存,你能找到嗎?
下面我修改下代碼:
- long start = System.nanoTime();
- long sum = 0l;
- for (long i = 0; i < Integer.MAX_VALUE; i++)
- {
- sum += i;
- }
- System.out.println(sum);
- System.out.println(System.nanoTime() - start);//5029758632
這次運行不會出現GC一直回收內存,且速度也只需要5秒左右,可能眼神不好的,沒有發現哪個地方修改了。
問題就出在自動裝箱、解箱上。第一次的程序sum爲Long類型,在計算sum+=i;時會把sum自動解箱成long sum 然後運算,運算完成後,再裝箱成Long sum,導致程序構造了大約2的32次方個多餘Long實例。所以各位且用且嚴謹。
4、對於自己管理內存的類,一定要清除不必要的對象引用,防止內存泄漏
看下面的代碼:
- package com.zhy._01;
- import java.util.Arrays;
- /*
- * 使用數組模擬棧
- */
- public class MyStack
- {
- private static final int DEFAULT_INIT_SIZE = 10;
- private Object[] eles = new Object[DEFAULT_INIT_SIZE];
- /**
- * 當前棧頂索引
- */
- private int currentIndex;
- /**
- * 彈棧
- *
- * @return
- */
- public Object pop()
- {
- if (currentIndex == 0)
- throw new ArrayIndexOutOfBoundsException("stack is empty");
- return eles[--currentIndex];
- }
- /**
- * 壓棧
- *
- * @param o
- */
- public void push(Object o)
- {
- ensureCapacity();
- eles[currentIndex++] = o;
- }
- private void ensureCapacity()
- {
- if (eles.length == currentIndex)
- {
- eles = Arrays.copyOf(eles, currentIndex * 2 + 1);
- }
- }
- }
代碼中存在一個地方,導致了內存泄漏,你可以發現不?
- return eles[--currentIndex];
這行代碼導致,如果棧增長了特別大,然後調用多次pop彈棧,雖然currentIndex小了,但是棧始終保持中之前pop出的過期對象的引用,這就導致了內存泄漏。如果不注意甚至最終造成OOM。
應該改爲:
- /**
- * 彈棧
- *
- * @return
- */
- public Object pop()
- {
- if (currentIndex == 0)
- throw new ArrayIndexOutOfBoundsException("stack is empty");
- Object tmp = eles[--currentIndex];
- eles[currentIndex] = null ;
- return tmp ;
- }
當然了,不要因爲擔心內存泄漏,在每個變量使用完成後都添加xxx=null,對於消除過期引用的最好方法,就是讓包含該引用的變量結束生命週期,而不是顯示的清空。一般情況下,對於類自己管理的內存,應當警惕。