1. 程式人生 > 實用技巧 >java程式碼優化

java程式碼優化

1:多餘的 if/else,對於boolean值,避免不必要的等式判斷。

反例:

 boolean ret;
 int i=0;
if(i==0)
 {
     ret=true;
 }

 else
 {
   ret=false;
 }

類似上面這種寫法if/else 可以簡寫:

int i=0;
boolean ret=(i==0)?true:false;

2:多餘的 else

public static String Login(String name)
{
    String reponseJson="";
    if(name==null)
    {
        reponseJson= "請輸入使用者名稱";
    }
    else
    {
       //登入方法
        reponseJson="";
    }
    
    return  reponseJson;
}

完全可以提前 return,進而幹掉 else 分支

public static String Login(String name)
{
    String reponseJson="";
    if(name==null)
    {
        reponseJson= "請輸入使用者名稱";
    }
     //登入方法
    reponseJson="";
   
    return  reponseJson;
}
  • 簡單就是美,程式碼寫的越少,犯錯的機率就越小。
  • 提前終止程式,絕大多數情況下,會節省很多不必要的開銷(會減少很多無效的判斷,減少無效變數、物件的建立)。
  • 每種程式語言都離不開 if/else 進行條件判斷,如果在編碼時,存在過多的 if/else 巢狀,程式碼的可讀性就會下降,後期維護難度就會大大提高。

3:隨處可見的判空邏輯。

if(name == null || "".equals(name)) {

}

很多時候都需要做非空檢查

確實有點不雅觀。

很多同學會想著,自己封裝 StringUtils 工具類

可以引用

import org.apache.commons.lang3.StringUtils;
if(StringUtils.isBlank(name))
 {

     return  "";
 }

4:完成物件間的屬性 Copy,編寫冗長的程式碼。

BeanUtils.copyProperties(EntityOld,EntityNew);

5for

所以例如下面的操作:

for (int i = 0; i < list.size(); i++)
{...}

建議替換為:

for (int i = 0, length = list.size(); i < length; i++)
{...}

6 儘量採用懶載入的策略,即在需要的時候才建立

例如:

String str = "aaa";
if (i == 1)
{
  list.add(str);
}

建議替換為:

if (i == 1)
{
  String str = "aaa";
  list.add(str);
}

7當複製大量資料時,使用System.arraycopy()命令

8 迴圈內不要不斷建立物件引用

例如:

for (int i = 1; i <= counts; i++)
{
    Object obj = new Object();    
}

這種做法會導致記憶體中有count份Object物件引用存在,count很大的話,就耗費記憶體了,建議為改為:

Object obj = null;
for (int i = 0; i <= counts; i++)
{
    obj = new Object();
}

9 儘量避免隨意使用靜態變數

要知道,當某個物件被定義為static的變數所引用,那麼gc通常是不會回收這個物件所佔有的堆記憶體的,如:

public class A
{
    private static B b = new B();  
}

10 將常量宣告為static final,並以大寫命名

這樣在編譯期間就可以把這些內容放入常量池中,避免執行期間計算生成常量的值。另外,將常量的名字以大寫命名也可以方便區分出常量與變

11 字串變數和字串常量equals的時候將字串常量寫在前面

這是一個比較常見的小技巧了,如果有以下程式碼:

String str = "123";
if (str.equals("123"))
{
    ...
}

建議修改為:

String str = "123";
if ("123".equals(str))
{
    ...
}

這麼做主要是可以避免空指標異常

12請知道,在java中if (i == 1)和if (1 == i)是沒有區別的,但從閱讀習慣上講,建議使用前者

13不要對陣列使用toString()方法

看一下對陣列使用toString()打印出來的是什麼:

public static void main(String[] args) {

int[] is = new int[]{2, 5, 3};

System.out.println(is.toString());

}

14不要對超出範圍的基本資料型別做向下強制轉型

這絕不會得到想要的結果:

public static void main(String[] args)
{
    long l = 123456789645454L;
    int i = (int)l;
    System.out.println(i);
}
15 公用的集合類中不使用的資料一定要及時remove掉

16把一個基本資料型別轉為字串,基本資料型別.toString()是最快的方式、String.valueOf(資料)次之、資料+""最慢

17使用最有效率的方式去遍歷Map

遍歷Map的方式有很多,通常場景下我們需要的是遍歷Map中的Key和Value,那麼推薦使用的、效率最高的方式是:

public static void main(String[] args)
{

HashMap<String, String> hmp = new HashMap<String, String>();
hmp.put("324", "234");
hmp.put("33524", "234");

long startTime=0;
long endTime=0;
startTime = System.currentTimeMillis();
Set<Map.Entry<String, String>> entrySet = hmp.entrySet();
Iterator<Map.Entry<String, String>> iter = entrySet.iterator();
while (iter.hasNext())
{
    Map.Entry<String, String> entry = iter.next();
    System.out.println(entry.getKey() + "\t" + entry.getValue());
}
endTime = System.currentTimeMillis();
System.out.println("1程式執行時間:" + (endTime - startTime) + "ms");

    startTime = System.currentTimeMillis();
    Iterator<Map.Entry<String, String>> iterator = hmp.entrySet().iterator();
    while (iterator.hasNext()) {
        Map.Entry<String, String> entry = iterator.next();
        System.out.println("key"+  entry.getKey() + "\t" + entry.getValue());
    }
    endTime = System.currentTimeMillis();
    System.out.println("2程式執行時間:" + (endTime - startTime) + "ms");

    startTime = System.currentTimeMillis();
    for (String key : hmp.keySet()) {

        System.out.println("key"+key + "\t" +  hmp.get(key));
    }
    endTime = System.currentTimeMillis();
    System.out.println("3程式執行時間:" + (endTime - startTime) + "ms");
}
結果:

33524 234
324 234
程式執行時間:2ms
key33524 234
key324 234
程式執行時間:0ms
key33524 234
key324 234
程式執行時間:1ms

18對資源的close()建議分開操作

19 對於ThreadLocal使用前或者使用後一定要先remove

20 long或者Long初始賦值時,使用大寫的L而不是小寫的l,因為字母l極易與數字1混淆,這個點非常細節,值得注意

21 所有重寫的方法必須保留@Override註解

22 迴圈體內不要使用"+"進行字串拼接,而直接使用StringBuilder不斷append

23在存在大量字串拼接或者大型字串拼接的時候,儘量使用StringBuilder和StringBuffer,確定 StringBuffer的容量

24避免Random例項被多執行緒使用,雖然共享該例項是執行緒安全的,但會因競爭同一seed 導致的效能下降,JDK7之後,可以使用ThreadLocalRandom來獲取隨機數

25靜態類、單例類、工廠類將它們的建構函式置為private

26時間選擇 : 迴圈中用System.nanoTime因為精度高,平時用System.currentTimeMillis()能和data轉換

27.float和double 要效能和記憶體用float,要精度高用double

28.集合初始化儘量指定大小

int[] arr=new int[]{1,2,3};
List<Integer> list=new ArrayList<>(arr.length);

29.長整型常量後新增大寫 L

在使用長整型常量值時,後面需要新增 L ,必須是大寫的 L ,不能是小寫的 l ,小寫 l 容易跟數字 1 混淆而造成誤解。

30.建議使用 try-with-resources 語句

Java 7 中引入了 try-with-resources 語句,該語句能保證將相關資源關閉,優於原來的 try-catch-finally 語句,並且使程式程式碼更安全更簡潔。

31.刪除未使用的私有方法和欄位

32.刪除未使用的區域性變數

33公有靜態常量應該通過類訪問

34.禁止使用構造方法 BigDecimal(double)

35.返回空陣列和空集合而不是 null

反例:

private static  List<Integer> getList()
{
    
    return null;
}

正例:

private static  List<Integer> getList()
{

    return Collections.emptyList();
}

36.列舉的屬性欄位必須是私有不可變

37.小心 String.split(String regex)

字串 String 的 split 方法,傳入的分隔字串是正則表示式!部分關鍵字(比如.[]()\|等)需要轉義

38如果只是查詢單個字元的話,用charAt()代替startsWith()

39 使用移位操作來代替'a / b'操作

"/"是一個很“昂貴”的操作,使用移位操作將會更快更有效。

例子:

private static void calculates(int a)
{


   int div = a /4;
   int div2 = a / 8;
   int temp = a / 3;
}
更正:
public static void calculate2(int a) {
    int div = a >> 2;
    int div2 = a >> 4;
    int temp = a / 3;
}

40使用移位操作代替'a * b'

例子:

private static void calculates(int a)
{
   int div = a *4;
   int div2 = a* 8;
   int temp = a * 3;
}

更正:

public static void calculate2(int a) {
    int div = a << 2;
    int div2 = a << 4;
    int temp = a* 3;
}

41在字串相加的時候,使用 ' ' 代替 " ",如果該字串只有一個字元的話

例子:

private static void Str(String s)
{
    String string = s + "d"; // violation.
    string = "abc" + "d";      // violation.
}

更正:

public static void Str2(String s) {
    String string = s + 'd'; // violation.
    string = "abc" + 'd';      // violation.
}

42把try/catch塊放入迴圈體內,會極大的影響效能,如果編譯JIT被關閉或者你所使用的是一個不帶JIT的JVM,效能會將下降21%之多!

43儘可能的使用棧變數,訪問靜態變數和例項變數將會比訪問區域性變數多耗費2-3個時鐘週期