天天看點

這樣寫代碼,直接被主管攆出去

前言:

編寫具有規範、易懂的代碼,注意代碼的每一個細節,可以避免稀奇古怪的問題,在一定程度上也能小幅度的提升程式的運作效率。

以下每個例子都是來源于日常的學習與工作中,随着工作年限的提升,我将會不定時地更新此文。

一、簡化if、else

減少if、else判斷的分支。當條件簡單時,可以直接return一個表達式。

優化前:                                                                                 被攆指數:50%

//判斷該數是否是正數
    public boolean isPositive(int num) {
        if (num > 0) {
            return true;
        } else {
            return false;
        }
    }      

優化後:

//判斷該數是否是正數
    public boolean isPositive(int num) {
        return num > 0;
    }      

4行代碼直接簡化到了1行,并且更加容易閱讀。

當然,優化if、else語句還有很多優化方式,具體可以參考我的這一篇文章​​優化if else的幾種方式​​

二、初始化集合時,最好指定容量

如果能在一開始确定往集合存入的元素個數,那麼最好先執行集合的容量,可以有效避免擴容以及記憶體浪費。

優化前:                                                                                 被攆指數:20%

Map<String, Object> response = new HashMap<>();
        response.put("code", 0);
        response.put("success", true);
        response.put("msg", "action success");      

優化後:

Map<String, Object> response = new HashMap<>(3);
        response.put("code", 0);
        response.put("success", true);
        response.put("msg", "action success");      

其實我建議這裡指定容量為4可能好點,即不觸發擴容的最小的2的倍數。

當然,這裡設定為3也行,HashMap會自動找到第一個大于此數字的2的倍數,即4,并将4設定為table的初始長度。

接下來會出一篇,講解怎麼去更好地設定HashMap初始容量的文章。

相關的一個話題:為什麼HashMap的容量總是2的倍數?有興趣的同學可以移步到我的另外一篇文章​​為什麼長度總是2的整數次方​​

三、避免不必要的手動裝箱或拆箱

當将一個基本資料類型指派給一個對應的包裝類時,會自動進行裝箱。當一個包裝類型與基本資料類型比較時,也會觸發包裝類型的自動拆箱。這些都不需要我們手動的去進行。

優化前:                                                                                 被攆指數:80%

@Data
    private static class User {
        private Integer age;
    }

    public static void main(String[] args) {
        User user = new User();
        user.setAge(new Integer(12));
        //....
        if (user.getAge().intValue()<18){
            System.out.println("未滿18歲不得...");
        }
    }      

優化後:

@Data
    private static class User {
        private Integer age;
    }

    public static void main(String[] args) {
        User user = new User();
        user.setAge(12);
        //....
        if (user.getAge() < 18) {
            System.out.println("未滿18歲不得...");
        }
    }      

對裝箱和拆箱不熟悉的同學,可以參考我的另外一篇文章​​談談拆箱與裝箱​​

四、在代碼中增加事務處理

在多次對資料庫進行操作時,需要增加事務以供出現異常時進行復原。否則輕則資料備援,重則資料錯亂。

優化前:                                                                                 被攆指數:100%

public void deleteStudent(int studentId){
        //删除學生
        studentMapper.delete(studentId);
        //其他業務操作,可能會出現異常
        //删除學生成績
        scoreMapper.delete(studentId);
    }      

優化後:

@Transactional(propagation = Propagation.REQUIRED)
    public void deleteStudent(int studentId) {
        //删除學生
        studentMapper.delete(studentId);
        //其他操作,可能會出現異常
        //删除學生成績
        scoreMapper.delete(studentId);
    }      

事務的傳播行為還有很多種,有興趣的可以參考我的另外一篇文章​​Spring事務的傳播行為​​

當然,如果涉及分布式事務時,情況會更加複雜,這裡不作讨論。

五、複制大數組時,使用System.arraycopy

如果我們在業務中,需要複制一個特别大的數組(以萬為機關),那麼可以考慮使用System.arraycopy

優化前:                                                                                 被攆指數:40%

//原數組,含有大量元素
        int[] src = new int[20000];
        //目标數組
        int[] des = new int[src.length];
        //複制數組
        for (int i = 0; i < src.length; i++) {
            des[i] = src[i];
        }      

優化後:

//原數組,含有大量元素
        int[] src = new int[20000];
        //目标數組
        int[] des = new int[src.length];
        //複制數組
        System.arraycopy(src, 0, des, 0, src.length);      

在數組長度機關不同的情況下,複制函數的選擇不是一概而論的,具體可以參考我的這篇文章​​數組複制效率的比較​​

六、使用确定值調用equals,或者直接使用Objects.equals

當使用equals進行比較時,為了避免潛在的空指針風險,應該使用确定值發起equals調用。

優化前:                                                                                 被攆指數:100%

if (user.getName().equals("jack")) {
            //其他處理
        }      

優化後

if ("jack".equals(user.getName())) {
            //其他處理
        }

        //或者使用Objects.equals()
        if (Objects.equals(user.getName(), "jack")) {
            //其他處理
        }      

Objects是JDK7時引入的,提供靜态方法操作對象。

這年頭不怕面試官問Object類的方法,就怕問Objects,怕是很多人都不知道有這個類吧。

關于Object類,可以看我的這篇文章​​Object類的方法簡談​​

七、線程内使用完ThreadLocal後,記得remove

子線程使用完ThreadLocal時,可以手動調用ThreadLocal的remove方法,将目前ThreadLocal從子線程的ThreadLocalMap中移除。

如果我們隻是一次性的使用該子線程,那麼調用remove方法後,可以在一定程度上避免記憶體洩漏。

如果子線程是從線程池中取出來的,那麼調用remove方法後,可以避免潛在的資料錯亂的問題。

static ThreadLocal<Integer> tl = new ThreadLocal<>();

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

        Thread t = new Thread(() -> {
            tl.set(1);
            //其他操作
        });
        t.start();

        //等待子線程執行完成
        t.join();

        //不再使用ThreadLocal
        tl = null;
    }      
static ThreadLocal<Integer> tl = new ThreadLocal<>();

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

        Thread t = new Thread(() -> {
            tl.set(1);
            //其他操作
            tl.remove();
        });
        t.start();

        //等待子線程執行完成
        t.join();

        //不再使用ThreadLocal
        tl = null;
    }      

持續更新...