松原網(wǎng)站建設(shè)一條龍全包(javadoc模板)java類模板的使用方法,
前言北宋科學(xué)家沈括在《夢溪筆談》第十八卷《技藝》中這樣描述"活字印刷術(shù)":慶歷中,有布衣畢昇,又為活版其法用膠泥刻字,薄如錢唇,每字為一印,火燒令堅……若止印三、二本,未為簡易;若印數(shù)十百千本,則極為神速。
在日常編碼的過程中,我們可以總結(jié)出很多"樣板代碼",就像"活字印刷術(shù)"中的"活字"一樣當(dāng)我們編寫新的代碼時,需要用到這些"活字",就把"樣板代碼"拷貝過來,修改替換一下就可以了,寫起代碼來"極為神速""。
樣板代碼"其實就是一種樣例、一種模式、一種經(jīng)驗……總結(jié)的"樣板代碼"越多,編寫代碼的格式越規(guī)范、質(zhì)量越高、速度越快這里,作者總結(jié)了幾種常見Java的"樣板代碼",希望起到拋磚引玉的作用,希望大家不斷總結(jié)和完善,形成自己的樣板代碼庫。
1. 樣板代碼簡介1.1. 什么是樣板代碼?樣板代碼(Boilerplate Code),通常是指一堆具有固定模式的代碼塊,可以被廣泛地應(yīng)用到各個程序模塊例如,讀取文件就是典型的樣板代碼:try (BufferedReader reader = 。
new BufferedReader(new FileReader(fileName))) { String line; while (Objects.nonNull(line = reader.readLine())) {
// 處理一行 ... } } catch (IOException e) { String message = String.format("讀取文件(%s)異常", fileName); log.error(message, e);
thrownew ExampleException(message, e); }1.2. 樣板代碼有什么用?樣板(Boilerplate ),可以拆分為樣例(Example)和模式(Pattern)兩個單詞進(jìn)行理解——
樣例(Example)指可以當(dāng)成一種標(biāo)準(zhǔn)范例,模式(Pattern)指可以作為一種解決方案當(dāng)遇到類似的案例時,就把樣板代碼拷貝過去,根據(jù)實際情況進(jìn)行修改,該案例就被輕松解決了樣板代碼的主要作用:提供一種標(biāo)準(zhǔn)樣例:。
可以用于新人學(xué)習(xí),能夠快速上手并使用;提供一種解決方案:遇到類似案例時,可以快速利用該方案進(jìn)行解決;有助于不斷積累經(jīng)驗:當(dāng)發(fā)現(xiàn)一種樣例代碼時,都會不斷地進(jìn)行優(yōu)化,力求達(dá)到最佳樣例;有助于提高代碼質(zhì)量:樣板代碼必然通過了時間考驗,存在BUG和出錯的幾率相對比較低;
有助于提高編碼速度:利用樣板代碼編碼,只是復(fù)制粘貼修改代碼,編碼速度大幅提高;有助于統(tǒng)一代碼樣式:心中有了樣板代碼,就能保證每次都寫出統(tǒng)一樣式的代碼1.3. 如何編寫樣板代碼?在作者以前的文章《編碼方法論,賦能你我他》中,有詳細(xì)的說明和舉例,這里不再累述。
其中,適合于樣板代碼的編寫方法有:復(fù)制粘貼生成代碼利用復(fù)制粘貼樣板代碼,用好了編碼會事半功倍用文本替換生成代碼利用文本替換生成代碼,可以很快生成一段新代碼用Excel公式生成代碼把樣板代碼先公式化,傳入不同的參數(shù),生成不同的代碼。
用工具或插件生成代碼很多開發(fā)工具或插件都提供一些工具生成代碼,比如:生成構(gòu)造方法、重載基類/接口方法、生成Getter/Setter方法、生成toString方法、生成數(shù)據(jù)庫訪問方法……能夠避免很多手敲代碼。
用代碼生成代碼用代碼生成代碼,就是自己編寫代碼,按照自己的樣板代碼格式生成代碼1.4. 如何減少樣板代碼?樣板代碼(Boilerplate Code)具有很大的重復(fù)性,通常被認(rèn)為是一種冗余而又不得不寫的代碼。
其實不然,有些樣板代碼不能減少,只是我們還沒有遇到合適的解決方案而已通常情況下,我們可以通過以下幾種方式減少樣板代碼:1.4.1. 利用注解減少樣板代碼比如,JavaBean模型類中的Getter/Setter就是樣板代碼,我們可以通過Lombok的@Getter/@Setter注解來減少這樣的樣板代碼。
原始代碼:publicclassUser{ privateLong id; ... publicLong getId() { return id; }
public void setId(Long id) { this.id = id; } ... }優(yōu)化代碼:@Getter@Setter public class User {
privateLongid; ... }1.4.2. 利用框架減少樣板代碼比如,MyBatis 是一款優(yōu)秀的持久層框架,封裝了獲取數(shù)據(jù)庫連接和聲明、設(shè)置參數(shù)、獲取結(jié)果集等所有JDBC操作MyBatis 可以通過簡單的 XML 或注解來配置和映射原始類型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 對象)為數(shù)據(jù)庫中的記錄。
原始代碼:/** 查詢公司員工 */publicList queryEmployee(Long companyId) { try (Connection connection = tddlDataSource.getConnection(); PreparedStatement statement = connection.prepareStatement(QUERY_EMPLOYEE_SQL)) { statement.setLong(
1, companyId); try (ResultSet result = statement.executeQuery()) { List employeeList =
new ArrayList<>(); while (result.next()) { EmployeeDO employee = new EmployeeDO(); employee.setId(result.getLong(
1)); employee.setName(result.getString(2)); ... employeeList.add(employee); }
return employeeList; } } catch (SQLException e) { String message = String.format(
"查詢公司(%s)用戶異常", companyId); log.error(message, e); thrownew ExampleException(message, e); } }
優(yōu)化代碼:UserDAO.java:@MapperpublicinterfaceUserDAO{ List queryEmployee(@Param("companyId"
)Long companyId); }UserDAO.xml: < select id="queryEmployee"
resultType="com.example.repository.UserDO"> select id , name ... from
t_user where company_id = #{companyId} 1.4.3. 利用設(shè)計模式減少樣板代碼利用設(shè)計模式,可以把一些重復(fù)性代碼進(jìn)行封裝。
比如,上面的讀取文件行模式代碼,就可以用模板方法進(jìn)行封裝原始代碼:try (BufferedReader reader = new BufferedReader(new FileReader(fileName))) {
String line; while (Objects.nonNull(line = reader.readLine())) { // 處理一行 ... } }
catch (IOException e) { String message = String.format("讀取文件(%s)異常", fileName); log.error(message, e);
thrownew ExampleException(message, e); }優(yōu)化代碼:/** 定義方法 */publicstaticvoid readLine(String fileName, Consumer<
String> lineConsumer) { try (BufferedReader reader = new BufferedReader(new FileReader(fileName))) {
String line; while (Objects.nonNull(line = reader.readLine())) { lineConsumer.accept(line); } }
catch (IOException e) { String message = String.format("讀取文件(%s)異常", fileName); log.error(message, e);
thrownew ExampleException(message, e); } } // 使用代碼 readLine("example.txt", line -> { // 處理一行
... });1.5. 消滅不了的樣板代碼如果樣板代碼可以被消滅,那么世界上就不存在樣板代碼了即便是上一節(jié)提供的減少樣板代碼方法,也不能完全的消滅樣板代碼,因為這些樣板代碼依舊存在于框架和模式的實現(xiàn)中。
所以,樣板代碼是消滅不了的既然不能消滅樣板代碼,那就應(yīng)該合理地利用樣板代碼提煉一段樣板代碼,若只用二三次,未為簡便;若用數(shù)十百千次,則極為神速下面,列舉了幾種常見Java的樣板代碼,描述了樣板代碼在日常編程中如何提煉和使用。
2. 定義工具類2.1. 常用定義方式通常,我們會如下定義工具類:/** 例子工具類 */publicclassExampleHelper {/** 常量值 */publicfinalstaticint
CONST_VALUE = 123; /** 求和方法 */publicstaticintsum(int a, int b){ return a + b; } }2.2. 存在一些問題
2.2.1. 修飾符順序不規(guī)范通過SonarLint插件掃描,會出現(xiàn)以下問題:Rule keyRule nameDescriptionjava:S1124Modifiers should be declared in the correct order(修飾符應(yīng)該以正確的順序聲明)
Reorder the modifiers to comply with the Java Language Specification.(重新排序修飾符以符合Java語言規(guī)范)Java語言規(guī)范建議使用"static final",而不是"final static"。
請記住這么一條規(guī)則:靜態(tài)常量,靜態(tài)(static)在前,常量(final)在后2.2.2. 工具類可以被繼承覆蓋如果我們定義一個MyExampleHelper來繼承ExampleHelper:public
classMyExampleHelperextendsExampleHelper {/** 常量值 */publicstaticfinalint CONST_VALUE = 321; /** 求和方法 */
publicstaticintsum(int a, int b){ return a * b; } }會發(fā)現(xiàn),MyExampleHelper會對ExampleHelper中的常量和方法進(jìn)行覆蓋,導(dǎo)致我們不知道是不是使用了ExampleHelper中的常量和方法。
對于Apache提供的工具類,很多同學(xué)都喜歡定義相同名稱的工具類,并讓這個工具類繼承Apache的工具類,并在這個類中添加自己的實現(xiàn)方法其實,我是非常不推薦這種做法的,因為你不知道——你調(diào)用的是Apache工具類提供的常量和方法,還是被覆蓋的常量和方法。
最好的辦法,就是對工具類添加final關(guān)鍵字,讓這個工具類不能被繼承和覆蓋2.2.3. 工具類可以被實例化對于ExampleHelper工具類,我們可以這樣使用:intvalue = ExampleHelper.CONST_VALUE;
int sum = ExampleHelper.sum(1, 2);也可以被這樣使用:ExampleHelper exampleHelper = new ExampleHelper(); intvalue
= exampleHelper.CONST_VALUE; int sum = exampleHelper.sum(1, 2);對于工具類來說,沒有必要進(jìn)行實例化所以,我們建議添加私有構(gòu)造方法,并在方法中拋出。
UnsupportedOperationException(不支持的操作異常)2.3. 最佳定義方式根據(jù)以上存在問題及其解決方法,最佳定義的ExampleHelper工具類如下:/** 例子工具類 */。
publicfinalclassExampleHelper {/** 常量值 */publicstaticfinalint CONST_VALUE = 123; /** 構(gòu)造方法 */private
ExampleHelper(){ thrownew UnsupportedOperationException(); } /** 求和方法 */publicstatic
intsum(int a, int b){ return a + b; } }3. 定義枚舉類3.1. 常用定義方式通常,我們會如下定義枚舉類:/** 例子枚舉類 */public
enum ExampleEnum { /** 枚舉相關(guān) */ ONE(1, "one(1)"), TWO(2, "two(2)"), THREE(3, "two(3)");
/** 屬性相關(guān) */private Integer value; private String desc; /** 構(gòu)造方法 */privateExampleEnum(Integer
value, String desc) { this.value = value; this.desc = desc; } /** 獲取取值 */public
Integer getValue() { returnvalue; } /** 獲取描述 */public String getDesc() { return
desc; } }3.2. 一些優(yōu)化建議3.2.1. 修飾符private可缺省通過SonarLint插件掃描,會出現(xiàn)以下問題:Rule keyRule nameDescriptionjava:S2333
Redundant modifiers should not be used(不應(yīng)該使用多余的修飾符)"private" is redundant in this context.(private在上下文中是多余的。
)根據(jù)建議,應(yīng)該刪除構(gòu)造方法前多余的private修飾符3.2.2. 建議使用基礎(chǔ)類型用包裝類型Integer保存枚舉取值,本身并沒有什么問題但是,本著能用基礎(chǔ)類型就用基礎(chǔ)類型的規(guī)則,所以建議使用基礎(chǔ)類型int。
3.2.3. 建議使用final字段假設(shè),我們要實現(xiàn)一個靜態(tài)方法,可能一不小心就把枚舉值給修改了:/** 修改取值 */publicstaticvoidmodifyValue() { for (ExampleEnum
value : values()) { value.value++; } }如果調(diào)用了modifyValue方法,就會把枚舉值修改,導(dǎo)致應(yīng)用程序出錯為了避免這樣的情況出現(xiàn),我們建議對字段添加final修飾符,從而避免字段值被惡意篡改。
3.3. 最佳定義方式/** 例子枚舉類 */publicenum ExampleEnum { /** 枚舉相關(guān) */ ONE(1, "one(1)"), TWO(2, "two(2)"
), THREE(3, "two(3)"); /** 字段相關(guān) */private final intvalue; private final String desc;
/** 構(gòu)造方法 */ ExampleEnum(intvalue, String desc) { this.value = value; this.desc = desc; }
/** 獲取取值 */publicintgetValue() { returnvalue; } /** 獲取描述 */public String getDesc() {
return desc; } }4. 定義模型類下面,以定義User(用戶)模型類為例,從JavaBean模式、重載構(gòu)造方法、Builder模式3種方式,來說明模型類的定義方法以及優(yōu)缺點假設(shè):User(用戶)模型類共有4個屬性——id(標(biāo)識)、name(名稱)、age(年齡)、desc(描述),其中必填屬性為——id(標(biāo)識)、name(名稱),可填屬性為——age(年齡)、desc(描述)。
4.1. JavaBean模式JavaBean是一個遵循特定寫法的Java類,它通常具有如下特點:必須具有一個無參的構(gòu)造方法;所有屬性字段必須是私有的;所有屬性字段必須通過遵循一種命名規(guī)范的Getter/Setter方法開放出來。
通過JavaBean模式定義的User(用戶)模型類如下:/** 用戶類 */publicclassUser {private Long id; private String name;
private Integer age; private String desc; public Long getId(){return id;} publicvoidsetId
(Long id){this.id = id;} public String getName(){return name;} publicvoidsetName(String name)
{this.name = name;} public Integer getAge(){return age;} public vid setAge(Integer age){this.age = age;}
public String getDesc(){return desc;} publicvoidsetDesc(String desc){this.desc = desc;} }注意:也可以通過Lombok的@Getter/@Setter注解生成對應(yīng)個Getter/Setter方法。
使用代碼:User user = new User(); user.setId(1L); user.setName("alibaba"); user.setAge(102); user.setDesc(
"test"); verifyUser(user);主要優(yōu)點:代碼非常簡單,只有私有屬性字段及其公有Getter/Setter方法;賦值對象代碼可讀性較強(qiáng),明確地知道哪個屬性字段對應(yīng)哪個值;非常簡單實用,被廣泛地用于HSF、Dubbo、MyBatis等中間件。
主要缺點:由于可以通過Setter方法設(shè)置屬性字段,所以不能定義為不可變類;由于每個字段分別設(shè)置,所以不能保證字段必填,必須設(shè)置完畢后進(jìn)行統(tǒng)一驗證4.2. 重載構(gòu)造方法通過"重載構(gòu)造方法"定義User(用戶)模型類如下:。
/** 用戶類 */publicfinalclassUser{ privateLong id; private String name; private Integer age;
private String desc; public User(Long id, String name) { this(id, name, null); }
public User(Long id, String name, Integer age) { this(id, name, age, null); } public User(
Long id, String name, Integer age, String desc) { Assert.notNull(id, "標(biāo)識不能為空"); Assert.notNull(name,
"名稱不能為空"); this.id = id; this.name = name; this.age = age; this.desc = desc; }
publicLong getId() {return id;} public String getName() {return name;} public Integer getAge() {
return age;} public String getDesc() {return desc;} }使用代碼:User user1 = new User(1L, "alibaba"); User user2 =
new User(1L, "alibaba", 102, "test");主要優(yōu)點:初始化對象代碼簡潔,只有簡單的一行代碼;可以定義為不可變類,初始化后屬性字段值不可變更;可以在構(gòu)造方法內(nèi)進(jìn)行不可空驗證。
主要缺點:重載構(gòu)造方法數(shù)量過多,無法覆蓋必填字段和非必填字段的所有組合;初始化對象代碼可讀性差,無法看出哪個屬性字段對應(yīng)哪個值;如果刪除某個字段,初始化對象代碼可能不會報錯,導(dǎo)致出現(xiàn)賦值錯誤問題4.3. Builder模式。
/** 用戶類 */publicfinalclassUser{ privateLong id; private String name; private Integer age;
private String desc; private User(Builder builder) { this.id = builder.id; this.name = builder.name;
this.age = builder.age; this.desc = builder.desc; } public static Builder newBuilder(
Long id, String name) { return new Builder(id, name); } publicLong getId() {return id;}
public String getName() {return name;} public Integer getAge() {return age;} public String getDesc() {
return desc;} public static classBuilder{ privateLong id; private String name;
private Integer age; private String desc; private Builder(Long id, String name) { Assert.notNull(id,
"標(biāo)識不能為空"); Assert.notNull(name, "名稱不能為空"); this.id = id; this.name = name; }
public Builder age(Integer age) { this.age = age; returnthis; }
public Builder desc(String desc) { this.desc = desc; returnthis; }
public User build() { return new User(this); } } } 注意:可以采用Lombok的@Builder注解簡化代碼。
使用代碼:User user = User.newBuilder(1L, "alibaba").age(102).desc("test").build();主要優(yōu)點:明確了必填參數(shù)和可選參數(shù),在構(gòu)造方法中進(jìn)行驗證;
可以定義為不可變類,初始化后屬性字段值不可變更;賦值代碼可讀性較好,明確知道哪個屬性字段對應(yīng)哪個值;支持鏈?zhǔn)椒椒ㄕ{(diào)用,相比于調(diào)用Setter方法,代碼更簡潔主要缺點:代碼量較大,多定義了一個Builder類,多定義了一套屬性字段,多實現(xiàn)了一套賦值方法;。
運行效率低,需要先創(chuàng)建Builder實例,再賦值屬性字段,再創(chuàng)建目標(biāo)實例,最后拷貝屬性字段5. 定義集合常量在編碼中,經(jīng)常使用到各種集合常量,比如List(列表)常量、Set(集合)常量、Map(映射)常量等。
5.1. 普通定義方式定義代碼:最簡單的方法,就是直接定義一個普通的集合常量/** 例子工具類 */publicfinalclassExampleHelper{ /** 常量值列表 */public。
staticfinalList CONST_VALUE_LIST = Arrays.asList(1, 2, 3); /** 常量值集合 */publicstaticfinal
Set CONST_VALUE_SET = new HashSet<>(Arrays.asList(1, 2, 3)); /** 常量值映射 */publicstaticfinal
Map CONST_VALUE_MAP; static { CONST_VALUE_MAP = new HashMap<>(MapHelper.
DEFAULT); CONST_VALUE_MAP.put(1, "value1"); CONST_VALUE_MAP.put(2, "value2"); CONST_VALUE_MAP.put(
3, "value3"); } ... }使用代碼:使用也很方便,直接通過"類名.常量名"使用// 使用常量值集合 List constValueList = ExampleHelper.CONST_VALUE_LIST; 。
Set constValueSet = ExampleHelper.CONST_VALUE_SET; Map constValueMap = ExampleHelper.CONST_VALUE_MAP;
5.2. 存在主要問題通過SonarLint插件掃描,會出現(xiàn)以下問題:Rule keyRule nameDescriptionjava:S2386Mutable fields should not be "public static"(可變字段不應(yīng)為“公共靜態(tài)”)
Make this member "protected".(將此成員設(shè)為“protected”)由于普通的集合對象(如ArrayList、HashMap、HashSet等)都是可變集合對象,即便是定義為靜態(tài)常量,也可以通過操作方法進(jìn)行修改。
所以,上面方法定義的集合常量,并不是真正意義上的集合常量其中,Arrays.asList方法生成的內(nèi)部ArrayList不能執(zhí)行add/remove/clear方法,但是可以set方法,也屬于可變集合對象。
// 操作常量列表ExampleHelper.CONST_VALUE_LIST.remove(3); // UnsupportedOperationExceptionExampleHelper.CONST_VALUE_LIST
.add(4); // UnsupportedOperationExceptionExampleHelper.CONST_VALUE_LIST.set(1, 20); // [1,20,3]ExampleHelper
.CONST_VALUE_LIST.clear(); // UnsupportedOperationException// 操作常量集合ExampleHelper.CONST_VALUE_SET.remove
(3); // [1,2]ExampleHelper.CONST_VALUE_SET.add(3); // [1,2,3]ExampleHelper.CONST_VALUE_SET.clear(); // []
// 操作常量映射ExampleHelper.CONST_VALUE_MAP.remove(3); // {1:"value1",2:"value2"}ExampleHelper.CONST_VALUE_MAP
.put(3, "value3"); // {1:"value1",2:"value2",3:"value3"}ExampleHelper.CONST_VALUE_MAP.clear(); // []5.3. 最佳定義方式
在JDK中,Collections工具類中提供一套方法,用于把可變集合對象變?yōu)椴豢勺儯ú豢尚薷?,修改時會拋出UnsupportedOperationException異常)集合對象所以,可以利用這套方法定義集合靜態(tài)常量。
/** 例子工具類 */publicfinalclassExampleHelper{ /** 常量值列表 */publicstaticfinalList CONST_VALUE_LIST = Collections.unmodifiableList(Arrays.asList(
1, 2, 3)); /** 常量值集合 */publicstaticfinal Set CONST_VALUE_SET = Collections.unmodifiableSet(
new HashSet<>(Arrays.asList(1, 2, 3))); /** 常量值映射 */publicstaticfinal Map CONST_VALUE_MAP;
static { Map valueMap = new HashMap<>(MapHelper.DEFAULT); valueMap.put(
1, "value1"); valueMap.put(2, "value2"); valueMap.put(3, "value3"); CONST_VALUE_MAP = Collections.unmodifiableMap(valueMap); } ... }
6. 定義數(shù)組常量上一章介紹了如何定義集合常量,這一章就來介紹一下如何定義數(shù)組常量6.1. 定義公有數(shù)組常量定義代碼:一般人定義數(shù)組常量,就會像下面代碼一樣,定義一個公有數(shù)組常量/** 例子工具類 */。
publicfinalclassExampleHelper {/** 常量值數(shù)組 */publicstaticfinalint[] CONST_VALUES = newint[] {1, 2, 3}; ... }
使用代碼:使用也很方便,直接通過"類名.常量名"使用// 使用常量值數(shù)組int[] constValues = ExampleHelper.CONST_VALUES;存在問題:但是,可以通過下標(biāo)修改數(shù)組值,導(dǎo)致數(shù)組常量的值可變。
所以,這種方法定義的數(shù)組常量,并不是一個真正意義上的數(shù)組常量//修改常量值數(shù)組ExampleHelper.CONST_VALUES[1]=20;//[1,20,3]6.2. 定義公有集合常量定義代碼:可以通過上一章定義集合常量的方法,返回一個公有集合常量。
/** 例子工具類 */publicfinalclassExampleHelper{ /** 常量值列表 */publicstaticfinalList CONST_VALUE_LIST = Collections.unmodifiableList(Arrays.asList(
1, 2, 3)); ... }使用代碼:要想得到數(shù)組常量,就把集合常量轉(zhuǎn)化為數(shù)組常量// 使用常量值列表int[] constValues = ExampleHelper.CONST_VALUE_LIST.stream() .mapToInt(Integer::intValue).toArray();。
存在問題:每一次都會把集合常量轉(zhuǎn)化為數(shù)組常量,導(dǎo)致程序運行效率降低6.3. 最佳定義方式最佳法"私有數(shù)組常量+公有克隆方法"的解決方案如下代碼所示:先定義一個私有數(shù)組常量,保證不會被外部類使用;在定義一個獲取數(shù)組常量方法,并返回一個數(shù)組常量的克隆值。
定義代碼:這里,提供一個"私有數(shù)組常量+公有克隆方法"的解決方案如下代碼所示:先定義一個私有數(shù)組常量,保證不會被外部類使用;在定義一個獲取數(shù)組常量方法,并返回一個數(shù)組常量的克隆值/** 例子工具類 */。
publicfinalclassExampleHelper {/** 常量值數(shù)組 */privatestaticfinalint[] CONST_VALUES = newint[] {1, 2, 3};
/** 獲取常量值數(shù)組方法 */publicstaticint[] getConstValues() { return CONST_VALUES.clone(); } ... }
使用代碼:由于每次返回的是一個克隆數(shù)組,即便修改了克隆數(shù)組的常量值,也不會導(dǎo)致原始數(shù)組常量值的修改//使用常量值方法int[]constValues=ExampleHelper.getConstValues();。
//[1,2,3]constValues[1]=20;//[1,20,3]constValues=ExampleHelper.getConstValues();//[1,2,3]7. 定義多條件表達(dá)式7.1. 利用運算符&&(或||)直接拼接
定義代碼:有時候,我們會判斷很多條件,需求用&&(或||)連接多個條件表達(dá)式/** 獲取審核結(jié)果方法 */private static Integer getAuditResult(AuditDataVO 。
data) { if (isPassed(data.getAuditItem1()) && isPassed(data.getAuditItem2()) ... && isPassed(
data.getAuditItem11())) { return AuditResult.PASSED; } return AuditResult.REJECTED; }
存在問題:通過SonarLint插件掃描,會存在2個問題:Rule keyRule nameDescriptionjava:S1067Expressions should not be too complex(表達(dá)式不能太復(fù)雜)
Reduce the number of conditional operators (11) used in the expression (maximum allowed 3).(減少表達(dá)式中使用的條件運算符(11個)的數(shù)量(最多允許3個)。
)java:S1541Methods should not be too complex(方法不能太復(fù)雜)The Cyclomatic Complexity of this method "getAuditResult" is 13 which is greater than 10 authorized.(方法“getAuditResult”的圈復(fù)雜度為13,大于10。
)其中,圈復(fù)雜度(Cyclomatic complexity,CC)也稱為條件復(fù)雜度,是一種衡量代碼復(fù)雜度的標(biāo)準(zhǔn),其符號為V(G)麥凱布最早提出一種稱為“基礎(chǔ)路徑測試”(Basis Path Testing)的軟件測試方式,測試程序中的每一線性獨立路徑,所需的測試用例個數(shù)即為程序的圈復(fù)雜度。
圈復(fù)雜度可以用來衡量一個模塊判定結(jié)構(gòu)的復(fù)雜程度,其數(shù)量上表現(xiàn)為獨立路徑的條數(shù),也可理解為覆蓋所有的可能情況最少使用的測試用例個數(shù)7.2. 利用運算符=和&&(或||)級聯(lián)拼接定義代碼:那么,就把&&(或||)連接符拆開,利用運算符=和&&(或||)級聯(lián)進(jìn)行拼接。
/** 獲取審核結(jié)果方法 */private static AuditResult getAuditResult(AuditDataVO data) { boolean isPassed = isPassed(
data.getAuditItem1()); isPassed = isPassed && isPassed(data.getAuditItem2()); ... isPassed = isPassed && isPassed(
data.getAuditItem11()); if (isPassed) { return AuditResult.PASSED; } return AuditResult.REJECTED; }
存在問題:通過SonarLint插件掃描,還存在1個問題:Rule keyRule nameDescriptionjava:S1541Methods should not be too complex(方法不能太復(fù)雜)
The Cyclomatic Complexity of this method "getAuditResult" is 13 which is greater than 10 authorized.(方法“getAuditResult”的圈復(fù)雜度為13,大于10。
)也就是,利用運算符=和&&(或||)級聯(lián)進(jìn)行拼接,并不能減少方法的圈復(fù)雜度7.3. 利用動態(tài)無參數(shù)Lambda表達(dá)式列表定義代碼:下面,利用動態(tài)無參數(shù)Lambda表達(dá)式列表優(yōu)化,即把每個條件表達(dá)式作為BooleanSupplier對象存在列表中,然后依次執(zhí)行條件表達(dá)式得出最后結(jié)果。
/** 獲取審核結(jié)果方法 */privatestatic AuditResult getAuditResult(AuditDataVO data) { List supplierList =
new ArrayList<>(); supplierList.add(() -> isPassed(data.getAuditItem1())); supplierList.add(() -> isPassed(data.getAuditItem2())); ... supplierList.
add(() -> isPassed(data.getAuditItem11())); for (BooleanSupplier supplier : supplierList) {
if (!supplier.getAsBoolean()) { return AuditResult.REJECTED; } } return AuditResult.PASSED; }
存在問題:通過SonarLint插件掃描,沒有提示任何問題但是,每次都動態(tài)添加Lambda表達(dá)式,就會導(dǎo)致程序效率低下那么,有沒有把Lambda表達(dá)式靜態(tài)化的方法呢?7.4. 利用靜態(tài)有參數(shù)Lambda表達(dá)式列表。
定義代碼:要想固化Lambda表達(dá)式,就必須動態(tài)傳入AuditDataVO對象這里,采用Predicate來接收Lambda表達(dá)式,在Lambda表達(dá)式中指定AuditDataVO對象data。
然后,在for循環(huán)中,依次指定AuditDataVO對象data,并計算表達(dá)式的值/** 審核結(jié)果斷言列表 */private static final List< Predicate> AUDIT_RESULT_PREDICATE_LIST = Collections.unmodifiableList(Arrays.asList(
data -> isPassed(data.getAuditItem1()), data -> isPassed(data.getAuditItem2()), ...
data -> isPassed(data.getAuditItem11()))); /** 獲取審核結(jié)果方法 */private static AuditResult getAuditResult(AuditDataVO
data) { for (Predicate predicate : AUDIT_RESULT_PREDICATE_LIST) { if (!predicate.test(
data)) { return AuditResult.REJECTED; } } return AuditResult.PASSED; }適用條件:
適合于&&(或||)連接大量條件表達(dá)式的情況;適合于每個條件表達(dá)式都需要傳入相同參數(shù)的情況,如果每個條件表達(dá)式傳入?yún)?shù)不同,只能使用動態(tài)無參數(shù)Lambda表達(dá)式列表方法;如果需要傳入兩個參數(shù),可以使用BiPredicate類型來接收Lambda表達(dá)式;如果需要傳入多個參數(shù),則需要自定義方法接口。
后記明代思想家王陽明在《傳習(xí)錄》中說道:初種根時,只管栽培灌溉,勿作枝想,勿作葉想,勿作花想,勿作實想懸想何益?但不忘栽培之功,怕沒有枝葉花實?這也是我們高德研發(fā)團(tuán)隊的人才宗旨——不論學(xué)歷、不論經(jīng)歷、不論年齡、不論性別,只要有緣來到我們的團(tuán)隊,我們都將一視同仁地“栽培灌溉”;力求讓每一個新人都能夠茁壯成長,綻放出最完美的“枝葉花實”。
作者 | 常意本文為阿里云原創(chuàng)內(nèi)容,未經(jīng)允許不得轉(zhuǎn)載。