java代碼之美(11)---java代碼的優化


java代碼的優化

隨着自己做開發時間的增長,越來越理解雷布斯說的: 敲代碼要像寫詩一樣美。也能理解有一次面試官問我你對代碼有潔癖嗎?

一段好的代碼會讓人看就像詩一樣,也像一個干凈房間會讓人看去很舒服。

一段好的項目代碼我覺得可以用這三個維度去分析。1)性能 2)可擴展性3)可讀性

有關代碼的規范早在很久就有阿里巴巴的java開發手冊,里面有非常多的規范。太多了,自己也沒完全記住,抽空也會時不時再去翻翻。

接下來就寫一些有關性能和可讀性一些習慣,不全以后想到什么會再補充進來。

一、性能考慮

1、必須注意: 不對數據庫層做任何操作 如果業務的確需要,那也最好注解說明原因

2、盡量減少對變量的重復計算

在不做編譯優化的情況下,在循環中,循環條件會被反復計算,如果不使用復雜表達式,而使循環條件值不變的話,程序將會運行的更快。

for (int i = 0; i < list.size(); i++)
{...}
 //建議修改成:
for (int i = 0, length = list.size(); i < length; i++)
{...}

這樣list.size()只會調用一次,減少性能消耗。

3、盡量采用懶加載的策略,即在需要的時候才創建

這個習慣需要培養,在寫邏輯的時候,尤其是創建對象的時候是否需要考慮懶加載。

例如:

A a = new A();
if (i == 1) 
{
list.add(a);
} 
//建議替換為:
if (i == 1) 
{
A a = new A();
list.add(a);
} 

4、字符串累加

1)循環外: 字符串拼接可以直接使用String的+操作,沒有必要通過StringBuilder進行append.
2)循環內: 好的做法是在循環外聲明StringBuilder對象,在循環內進行手動append。不論循環多少層都只有一個 StringBuilder對象。

反編譯出的字節碼文件顯示每次循環都會 new 出一個 StringBuilder 對象,然后進行 append 操作,最后通過 toString 方法返回 String 對象,造成內存資源浪費。

StringBuffer sb = new StringBuffer();
sb.append("a");
sb.append("b");
sb.append("c");
sb.append("d");
//不在循環體內其實可以直接用加號,優化后一行代碼:
String sb="a"+"b"+"c"+"d";

有關JDK不同版本對String拼接的優化可以參考:jdk不同版本對String拼接的優化分析

5、盡量避免使用split

split由於支持正則表達式,所以效率比較低。

替代

  String str1="a,b,c,d,,f,g"; 
  //可以考慮使用apache的StringUtils.split(string,char)
  List<String> list = Arrays.asList(StringUtils.split(str1, ","));
  //可以考慮guava工具
  List<String> list1=Splitter.on(",").splitToList(str1);

6、確定Stringbuffer的容量

Stringbuffer的構造器會創建一個默認大小(通常是16)的字符數組。在使用中,如果超出這個大小,就會重新分配內存,創建一個更大的數組,並將原先的數組復制過來,再丟棄舊的數組。在大多數情況下,你可以在創建Stringbuffer的時候指定大小,這樣就避免了在容量不夠的時候自動增長,以提高性能。

例子:

 Stringbuffer buffer = new Stringbuffer(); // violation
 buffer.append ("hello");
//更正好:為stringbuffer提供寢大小。一般循環體內使用都可以知道大小
 Stringbuffer buffer = new Stringbuffer(max);
 buffer.append ("hello");

7、使用工具類 Arrays.asList()把數組轉換成集合時,不能使用其修改集合相關的方 法

它的 add/remove/clear 方法會拋出 UnsupportedOperationException 異常。

說明:asList 的返回對象是一個 Arrays 內部類,並沒有實現集合的修改方法。Arrays.asList 體現的是適配器模式,只是轉換接口,后台的數據仍是數組。

String[] str = new String[] { "a", "b" };
List list = Arrays.asList(str);
//第一種情況:list.add("c"); 運行時異常。
//第二種情況:str[0]= "gujin"; 那么list.get(0)也會隨之修改。

8、查找數組元素,可以用Arrays.asList(T[] array).contains(T obj)

二、可讀性考慮

1、推薦盡量少用 else, if-else 的方式

可以考慮:

 if(condition){
   ...
 return obj; }
// 接着寫 else 的業務邏輯代碼;

說明:如果非得使用if()...else if()...else...方式表達邏輯,【強制】請勿超過3層,超過請使用策略設計模式。
正例:邏輯上超過 3 層的 if-else 代碼可以使用衛語句,或者狀態模式來實現。

接下來抽空會寫一篇超過三層if-else更好的解決方案博客。

2、在 if/else/for/while/do 語句中必須使用大括號,即使只有一行代碼

避免使用: if (condition) statements;

3、使用條件操作符替代"if (cond) return; else return;" 結構

//條件操作符更加的簡捷
     if (isdone) {
         return 0;
     } else {
         return 10;
        }
//更正
   return (isdone ? 0 : 10);

4、Object 的 equals 方法容易拋空指針異常,應使用常量或確定有值的對象來調用 equals

正例: "test".equals(object);
反例: object.equals("test");
說明:推薦使用java.util.Objects (JDK7引入的工具類)

5、不允許出現任何魔法值(即未經定義的常量)直接出現在代碼中

反例

String key="Id#taobao_"+tradeId;cache.put(key, value);

6、取反操作符(!)降低程序的可讀性,所以不要總是使用

 boolean method (boolean a, boolean b) {
        if (!a)
            return !a;
        else
            return !b;
    }

7、注釋掉的代碼盡量要配合說明,而不是簡單的注釋掉

代碼被注釋掉有兩種可能性:1)后續會恢復此段代碼邏輯。2)永久不用。前者如果沒 有備注信息,難以知曉注釋動機。后者建議直接刪掉(代碼倉庫保存了歷史代碼)。

8、特殊注釋標記,請注明標記人與標記時間

  1. 待辦事宜(TODO)😦 標記人,標記時間,[預計處理時間]) 表示需要實現,但目前還未實現的功能。

  2. 錯誤不能工作(FIXME):(標記人,標記時間,[預計處理時間])在注釋中用 FIXME 標記某代碼是錯誤的,而且不能工作,需要及時糾正的情況。



只要自己變優秀了,其他的事情才會跟着好起來(少將1)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM