好程式設計師Java分享Java開發常用規範技巧一

好程式設計師IT發表於2019-07-04

好程式設計師Java分享Java開發常用規範技巧一

1 、Object 的 equals 方法容易拋空指標異常。

從原始碼來進行分析equals方法是屬於Object類的,如果呼叫方為null,那麼自然在執行的時候會丟擲空指標異常的情況。

object類中的原始碼:

從原始碼來進行分析equals方法是屬於Object類的,如果呼叫方為null,那麼自然在執行的時候會丟擲空指標異常的情況。

object類中的原始碼:


    public boolean equals(Object obj) {

        return (this == obj);

    }


為了避免這種現況出現,在比對的時候儘量將常量或者有確定值的物件置前。

例如說:

正確:“test”.equals(object);

錯誤:object.equals(“test”);


  2、 類的命名使用駝峰式命名的規範。

例如:UserService,但是以下情景例外:DO / BO / PO / DTO / VO。

例如說:UserPO,StudentPO(PO,VO,DTO,等這類名詞需要全大寫)

@Data

@Builder

public class CustomBodyDTO {

    private String name;

    private String idCode;

    private String status;

}

  1. 如果在模組或者介面,類,方法中使用了設計模式,那麼請在命名的時候體現出來。 例如說:TokenFactory,LoginProxy等。

public class TokenFactory {

    public TokenDTO buildToken(LoginInfo loginInfo) {

        String token = UUID.randomUUID().toString();

        TokenDTO tokenDTO = TokenDTO.builder()

                .token(token)

                .createTime(LocalDateTime.now())

                .build();

        String redisKey = RedisKeyBuilder.buildTokenKey(token);

        redisService.setObject(redisKey, loginInfo, Timeout.ONE_DAY * 30 * 2);

        log.info("建立token成功|loginInfo={}", loginInfo.toString());

        return tokenDTO;

    }

}

4、對於所有相同型別的包裝類進行比較的時候,都是用equal來進行操作。

對於Integer類來說,當相應的變數數值範圍在-128到127之間的時候,該物件會被儲存在IntegerCache.cache裡面,因此會有物件複用的情況發生。

所以對於包裝類進行比較的時候,最好統一使用equal方法。

private static class IntegerCache {

        static final int low = -128;

        static final int high;

        static final Integer cache[];

        static {

            // high value may be configured by property

            int h = 127;

            String integerCacheHighPropValue =

                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");

            if (integerCacheHighPropValue != null) {

                try {

                    int i = parseInt(integerCacheHighPropValue);

                    i = Math.max(i, 127);

                    // Maximum array size is Integer.MAX_VALUE

                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);

                } catch( NumberFormatException nfe) {

                    // If the property cannot be parsed into an int, ignore it.

                }

            }

            high = h;

            cache = new Integer[(high - low) + 1];

            int j = low;

            for(int k = 0; k < cache.length; k++)

                cache[k] = new Integer(j++);

            // range [-128, 127] must be interned (JLS7 5.1.7)

            assert IntegerCache.high >= 127;

        }

        private IntegerCache() {}

    }


  public static Integer valueOf(int i) {

        if (i >= IntegerCache.low && i <= IntegerCache.high)

            return IntegerCache.cache[i + (-IntegerCache.low)];

        return new Integer(i);

}

5、所有的pojo類中的屬性最好統一使用包裝類屬性型別資料。 RPC方法的返回值和引數都統一使用包裝類資料。區域性變數中使用基本的資料型別。

對於實際的應用場景來說,例如說一個學生類,當我們設定裡面的成績欄位為int型別的時候,如果學生沒有考試,那麼這個成績欄位應該為空,但是int預設會賦值為0,那麼這個時候使用基本資料型別就容易產生誤區,到底是考了0分,還是說沒有參加考試。

如果換成使用包裝類Integer型別的話,就可以透過null值來進行區分了。

6、當pojo類在進行編寫的時候要重寫相應的toString方法,如果該pojo中繼承了另外的一個pojo類,那麼請在相應的tostring函式中加入super.toString()方法。

透過重寫toString方法有利於在日誌輸出的時候檢視相應物件的屬性內容進行逐一分析,對於一些有繼承關係的物件而言,加入了super.toString方法更加有助於對該物件的理解和分析。

7、在pojo的getter和setter方法裡面,不要增加業務邏輯的程式碼編寫,這樣會增加問題排查的難度。

正確做法:

public class User {

    private Integer id;

    private String username;

    public Integer getId() {

        return id;

    }

    public User setId(Integer id) {

        this.id = id;

        return this;

    }

    public String getUsername() {

        return username;

    }

    public User setUsername(String username) {

        this.username = username;

        return this;

    }

}

8、final 可以宣告類、成員變數、方法、以及本地變數。

下列情況使用 final 關鍵字:

不允許被繼承的類,如:String 類。

不允許修改引用的域物件,如:POJO 類的域變數。

不允許被重寫的方法,如:POJO 類的 setter 方法。

不允許執行過程中重新賦值的區域性變數。

避免上下文重複使用一個變數,使用 final 描述可以強制重新定義一個變數,方便更好地進行重構。

9、對於任何類而言,只要重寫了equals就必須重寫hashcode。

舉例說明:

1)HashSet在儲存資料的時候是儲存不重複物件的,這些物件在進行判斷的時候需要依賴hashcode和equals方法,因此需要重寫。

2)在自定義物件作為key鍵時,需要重寫hashcode和equals方法,例如說String類就比較適合用於做key來使用。

10、不要在 foreach 迴圈裡進行元素的 remove/add 操作。

remove 元素請使用 Iterator方式,如果併發操作,需要對 Iterator 物件加鎖。

Iterator<String> iterator = list.iterator();

while (iterator.hasNext()) {

String item = iterator.next();

if (刪除元素的條件) {

iterator.remove();

}

}

11、使用HashMap的時候,可以指定集合的初始化大小。

例如說,HashMap裡面需要存放10000個元素,但是由於沒有進行初始化大小操作,所以在新增元素的時候,hashmap的內部會一直在進行擴容操作,影響效能。

那麼為了減少擴容操作,可以在初始化的時候將hashmap的大小設定為:已知需要儲存的大小/負載因子(0.75)+1

HashMap hashMap=new HashMap<>(13334);

12、Map類集合中,K/V對於null型別儲存的情況:

集合名稱

key

value

說明

HashMap

允許為null

允許為null

執行緒不安全

TreeMap

不允許為null

允許為null

執行緒不安全

HashTable

不允許為null

不允許為null

執行緒安全

ConcurrentHashMap

不允許為null

不允許為null

執行緒安全


13、可以利用 Set 元素唯一的特性,可以快速對一個集合進行去重操作,避免使用 List 的contains 方法進行遍歷、對比、去重操作。

通關觀察可以發現,HashSet底層透過將傳入的值再傳入到一個HashMap裡面去進行操作,進入到HashMap裡面之後,會先透過呼叫該物件的hashcode來判斷是否有重複的值,如果有再進行equals判斷,如果沒有相同元素則插入處理。

   public boolean add(E e) {

        return map.put(e, PRESENT)==null;

    }


14、執行緒池不允許使用 Executors 去建立,而是透過 ThreadPoolExecutor 的方式,這樣的處理方式讓寫的同學更加明確執行緒池的執行規則,規避資源耗盡的風險。

錯誤做法:

ExecutorService executors = Executors.newSingleThreadExecutor();

ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);


對於執行緒池的引數需要有深入的理解後,結合實際的機器引數來進行引數設定,從而防止在使用中出現異常。

ExecutorService fixedExecutorService = new ThreadPoolExecutor(

                1,

                2,

                60,

                TimeUnit.SECONDS,

                 linkedBlockingQueue,

                new MyThreadFactory(),

                new ThreadPoolExecutor.AbortPolicy()

        );


ps:使用Executors.new 方式建立執行緒池的缺點:

對於FixedThreadPool 和 SingleThreadPool而言

允許的請求佇列長度為 Integer.MAX_VALUE,可能會堆積大量的請求,從而導致 OOM。

對於CachedThreadPool 和 ScheduledThreadPool而言

允許的建立執行緒數量為 Integer.MAX_VALUE,可能會建立大量的執行緒,從而導致 OOM。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69913892/viewspace-2649586/,如需轉載,請註明出處,否則將追究法律責任。

相關文章