生活随笔
收集整理的這篇文章主要介紹了
findbugs常见错误总结
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
一、前置說(shuō)明:
??官網(wǎng)提供了所有的bug描述信息:官網(wǎng)bug描述鏈接 ,根據(jù)findbugs掃碼結(jié)果中的關(guān)鍵字搜索即可找到bug的描述信息甚至是修復(fù)方案。
二、findbugs常見(jiàn)錯(cuò)誤
Method concatenates strings using + in a loop (SBSC_USE_STRINGBUFFER_CONCATENATION) 錯(cuò)誤的示范如下:字符串拼接性能太差。應(yīng)改用StringBuilder實(shí)例的append方法。
UC_USELESS_OBJECT 錯(cuò)誤的示范如下:存在無(wú)效的對(duì)象。修正方式。刪除無(wú)效代碼即可。
UPM_UNCALLED_PRIVATE_METHOD 存在從未調(diào)用的私有方法,刪除無(wú)效代碼即可
NP_NULL_ON_SOME_PATH_EXCEPTION 在執(zhí)行的邏輯中,可能報(bào)空指針異常。見(jiàn)5. 下面的錯(cuò)誤示范
NP_NULL_ON_SOME_PATH 在某些路徑上存在空指針。 下面的錯(cuò)誤示范。若這種bug是業(yè)務(wù)需要,可以在忽略文件中配置。
@Override
public Result<Integer> addPromotion(PromotionDTO promotionDTO) {Long id = null;try {log.info("promotionDTO = {}", promotionDTO);// NP_NULL_ON_SOME_PATHif (promotionDTO == null) {return Result.wrapError(1, "參數(shù)異常");}// 省略部分代碼id = pmpPromotionConfigService.addPromotion(promotionDTO);} catch (Exception e) {// 省略部分代碼}log.info("id = {}", id);// 這里可能報(bào)異常return Result.wrapSuccess(id.intValue());
}
DB_DUPLICATE_BRANCHES 復(fù)制分支 使用相同的代碼實(shí)現(xiàn)條件分支的兩個(gè)分支。檢查以確保這不是編碼錯(cuò)誤。
@Override
public Boolean transformDataIntoMongo(Long promotionId) {try {// 省略部分代碼// 狀態(tài)為2 和 else中執(zhí)行的邏輯相同,請(qǐng)檢查邏輯是否有問(wèn)題if (status == 2) {promotionMongoDao.save(promotionMongoPO);} else {promotionMongoDao.save(promotionMongoPO);}} catch (Exception e) {logger.error(e.getMessage(), promotionId);return false;}return true;
}
RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE 包含對(duì)已知非空值的冗余檢查。
if (StringUtils.isNotEmpty(configStr)) {String[] split = configStr.split(",");// 沒(méi)必要再次檢查了if (split != null) {itemTemp.setVoucherList(Arrays.asList(split));}
}
WMI_WRONG_MAP_ITERATOR 錯(cuò)誤的map迭代器
// 初始化一個(gè)map
Map<Integer, List<MarketingActivityPO>> voucherMap = packageMarketingActivityVoucher();
for (Integer key : voucherMap.keySet()) {List<MarketingActivityVoucherPO> voucherPOList = voucherMap.get(key);// 省略部分代碼
}
KeySet(): 將Map中所有的鍵存入到set集合中。因?yàn)閟et具備迭代器。所有可以迭代方式取出所有的鍵,再根據(jù)get方法。獲取每一個(gè)鍵對(duì)應(yīng)的值。 keySet():迭代后只能通過(guò)get()取key
entrySet(): Set<Map.Entry<K,V>> entrySet() //返回此映射中包含的映射關(guān)系的 Set 視圖。 Map.Entry表示映射關(guān)系。entrySet():迭代后可以e.getKey(),e.getValue()取key和value。返回的是Entry接口 。
雖然使用keyset及entryset來(lái)進(jìn)行遍歷能取得相同的結(jié)果,但兩者的遍歷速度是有差別的。
keySet():迭代后只能通過(guò)get()取key entrySet():迭代后可以e.getKey(),e.getValue()取key和value。
說(shuō)明:keySet()的速度比entrySet()慢了很多,也就是keySet方式遍歷Map的性能不如entrySet性能好 為了提高性能,以后多考慮用entrySet()方式來(lái)進(jìn)行遍歷。
RC_REF_COMPARISON 引用類(lèi)型的比較,應(yīng)該用equals方法。
private List<FullFreeRuleItems> packageRuleDTO2Param(List<PromotionRuleDTO> ruleDTOList, Long fullFreemeteId) {// 省略for (PromotionRuleDTO ruleDTO : ruleDTOList) {// 不良的比較方式if (ruleDTO.getPromotionMetaId() == fullFreemeteId) {// ......}}
}
UCF_USELESS_CONTROL_FLOW 包含一個(gè)無(wú)用的控制流語(yǔ)句,在該語(yǔ)句中,無(wú)論是否采用分支,控制流都將繼續(xù)到同一位置。比如由if語(yǔ)句的語(yǔ)句塊為空導(dǎo)致的:
// 官網(wǎng)demo1,分支下無(wú)代碼
if (argv.length == 0) {// TODO: handle this case
}// 官網(wǎng)demo2,空語(yǔ)句導(dǎo)致
if (argv.length == 1);System.out.println("Hello, " + argv[0]);// 項(xiàng)目中的實(shí)例
if (area.getAreaType() == 4) { // 級(jí)別定位到微倉(cāng)級(jí) 城市大區(qū)都要有g(shù)etAreaType4(singlePromotion, areaCode);
} else if (area.getAreaType() == 3) { // 級(jí)別定位到城市級(jí) 大區(qū)要有 微倉(cāng)為全部微倉(cāng)getAreaType3(singlePromotion, areaCode);
} else if (area.getAreaType() == 2) {// 定位到大區(qū)級(jí)別 不管是全國(guó)還是大區(qū),城市 微倉(cāng) 全部getAreaType(singlePromotion, areaCode);
// 空語(yǔ)句
} else if (area.getAreaType() == 1) {}
DM_BOXED_PRIMITIVE_FOR_PARSING 自動(dòng)裝箱再拆箱,eg如下:
String reduceStep = "123";
// 把字符串轉(zhuǎn)成基本類(lèi)型、然后封裝成包裹類(lèi)型,參與比較時(shí)又要自動(dòng)拆箱
if (perReduce.intValue() >= Integer.valueOf(reduceStep))) {// 省略部分邏輯
}
源碼解釋: 改為parseXXX方法較為合適。
// valueOf把字符串轉(zhuǎn)成基本類(lèi)型、然后封裝成包裹類(lèi)型。
public static Integer valueOf(String s, int radix) throws NumberFormatException {return Integer.valueOf(parseInt(s,radix));
}
// parseXXX方法可以把字符串轉(zhuǎn)成基本類(lèi)型
public static int parseInt(String s, int radix) throws NumberFormatException
RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE 某個(gè)值雖然在某處有被判斷是否為null,但是這個(gè)值在該處并不可以為null,因?yàn)檫@個(gè)值被提前引用了,如果他有可能是null,在被引用的時(shí)候就會(huì)產(chǎn)生空指針異常,所以這里的判斷也就是多余的,而在該判斷之前的引用也可能是錯(cuò)誤的。
原因 判斷某個(gè)值是否為null的時(shí)機(jī)錯(cuò)誤 解決方案
List<Integer> activityIdList = new ArrayList<>();
// 被重新賦值后,有可能變?yōu)閚ull
activityIdList = activityDao.getXXX(searchDTO);
logger.info("查找到的活動(dòng)個(gè)數(shù):{}", activityIdList.size());
// 上一行已經(jīng)使用過(guò)該引用,下一行再判空,為時(shí)已晚。需要更改判空的時(shí)機(jī)
if (activityIdList == null) {// 省略部分邏輯
}
RV_RETURN_VALUE_IGNORED_NO_SIDE_EFFECT
@Override
@Transactional(rollbackFor = Exception.class)
public Result<Integer> batchCheckPromotion(List<String> idList, String userName) {if (CollectionUtils.isEmpty(idList)) {// 該調(diào)用沒(méi)有副作用,且返回值還被忽略了Result.wrapError(1, "傳入的id列表為空!");}// 省略部分邏輯
}
總結(jié)
以上是生活随笔 為你收集整理的findbugs常见错误总结 的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔 網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔 推薦給好友。