IDEA代碼警告(warning)整理以及解決方案
背景
在日常開發(fā)中,IDEA
可能會(huì)通過下方的problems
窗口以及編輯窗口最右方的黃色標(biāo)記提示給我們一些警告:
或者向git
提交commit時(shí)同樣有可能提示警告:
大多數(shù)情況下,無視這些警告并不會(huì)影響我們的程序結(jié)果,但卻說明了我們的代碼或多或少有一些問題,還有優(yōu)化的空間,也有可能有潛在的風(fēng)險(xiǎn),而且有強(qiáng)迫癥同學(xué)同樣也不想看到這些警告。這篇文章整理了我在平時(shí)開發(fā)中遇到的一些IDEA警告,以便后續(xù)碰到同樣的問題可以作為參考。
注意:不是所有警告都需要處理,需要自行判斷是否有處理的必要。(如我們對(duì)變量進(jìn)行了縮寫,而IDEA認(rèn)為是一個(gè)錯(cuò)誤的單詞)。
如何檢查代碼
默認(rèn)情況下,problems
窗口的Current File
頁簽中會(huì)展示的當(dāng)前文件的錯(cuò)誤以及警告等。
如果想查看整個(gè)項(xiàng)目、某一模塊或某個(gè)條件下的文件時(shí),需要依次點(diǎn)擊最上方菜單欄上的Code
-> Inspect Code
在彈出的窗口中可以選擇檢查哪些文件的代碼,如整個(gè)項(xiàng)目,某個(gè)模塊,未提交的文件等,也可以自己配置檢查哪些項(xiàng):
警告分析
X can be simplified to Y
原因:寫法比較啰嗦,有簡(jiǎn)化寫法。
public class Demo { boolean result; public boolean test() { return result == true; } } // 'result == true' can be simplified to 'result'
解決辦法:
按照提示將X修改為Y即可。
public class Demo { boolean result; public boolean test() { // 直接返回布爾值即可。 return result; } }
‘OptionalInt.getAsInt()’ without ‘isPresent()’ check
Pattern pattern = Pattern.compile("^(" + name + "\\()(\\d+)(\\))$"); int max = apps.stream() .mapToInt(app -> { Matcher matcher = pattern.matcher(app.getName()); if (matcher.find()) { // 取第二部分表示版本號(hào) String group = matcher.group(2); // 正則表達(dá)式過濾都數(shù)字,不用擔(dān)心轉(zhuǎn)換異常 return Integer.parseInt(group); } return 1; }) .max() .getAsInt(); return max + 1;
示例代碼中,apps為一個(gè)對(duì)象列表,經(jīng)過一些列處理變?yōu)槟硞€(gè)int值最后取最大值。
提示的原因是因?yàn)閙ap中有if的判斷,所以有可能全部不匹配,此時(shí)max()可能返回一個(gè)類似Optional為空的一個(gè)東西,需要進(jìn)行類似處理,將getAsInt改為orElse即可
Pattern pattern = Pattern.compile("^(" + name + "\\()(\\d+)(\\))$"); int max = apps.stream() .mapToInt(app -> { Matcher matcher = pattern.matcher(app.getName()); if (matcher.find()) { // 取第二部分表示版本號(hào) String group = matcher.group(2); // 正則表達(dá)式過濾都數(shù)字,不用擔(dān)心轉(zhuǎn)換異常 return Integer.parseInt(group); } return 1; }) .max() // 給一個(gè)默認(rèn)值 .orElse(1); return max + 1;
Iteration can be replaced with bulk ‘Collection.addAll’ call
原因:采用循環(huán)一個(gè)一個(gè)向集合中添加,比較麻煩。
List<String> list1 = new ArrayList(); List<String> list2 = xxxx; for (String str : list2) { list1.add(str); }
解決辦法:使用addAll
方法。
List<String> list1 = new ArrayList(); List<String> list2 = xxxx; list1.addAll(list2);
More arguments provided (1) than placeholders specified (0)
為SLF4J日志功能的警告
... LOGGER.error("user {0} is not found ", userId); ...
問題分析:
SL4FJ
中占位符不像MessageFormat
需要指定index,而是直接使用{}
即可
解決辦法:直接使用{}
... LOGGER.error("user {} is not found ", userId); ...
Call to ‘asList()’ with only one argument
原因:使用Arrays.asList
時(shí)只向其中添加了一個(gè)元素。
List<String> list = Arrays.asList("a");
解決方法:使用Collections.singletonList
代替
List<String> list = Collections.singletonList("a");
Raw use of parameterized class xx
原因:一般為沒有指定泛型
例1:如有一個(gè)類定義為
public class ResponseDto<T> { }
在實(shí)例化的時(shí)候按照如下所示
ResponseDto<String> response = new ResponseDto();
雖然引用加上了泛型,但是對(duì)象沒有加泛型,此時(shí)就會(huì)出現(xiàn)警告
解決方法:在對(duì)象上也加上泛型,但是無需寫全部,只需寫<>
即可,否則IDE會(huì)覺得多余并發(fā)出警告
// 無需寫全 // ResponseDto<String> response = new ResponseDto<String>(); ResponseDto<String> response = new ResponseDto<>();
例2:在單元測(cè)試中使用mockito來虛擬一個(gè)feign客戶端時(shí),如果參數(shù)為list那么會(huì)按照如下方式虛擬
XXClient client = mock(XXClient.class); when(client.listByIds(anyList())).thenAnswer(invocation -> { // Do something }
此時(shí)IDE會(huì)給予警告
因?yàn)槲覀兊慕涌趨?shù)指定了list的泛型
List<XX> listByIds(List<Long> ids);
但是mock時(shí)調(diào)用的方法anyList
的返回值并沒有指定泛型
所以IDE給出警告
解決辦法:調(diào)用mockito中提供的其他可以指定泛型的方法,如
when(client.listByIds(anyListOf(Long.class))).thenAnswer(invocation -> { ... }
Passing a non-null argument to ‘Optional’
原因:向Optional.ofNullable
傳遞一個(gè)非null
對(duì)象。
User user = xxxx; if (user != null) { Optional.ofNullable(user).xxx; }
解決辦法,如果可以明確對(duì)象非null,則直接使用of
。
User user = xxxx; if (user != null) { Optional.of(user).xxx; }
Method ‘xx()’ recurses infinitely, and can only end by throwing an exception
原因:提示為無限遞歸,只能通過觸發(fā)異常的方式結(jié)束。
public void method1() { method1(); }
解決辦法:
一般來說為錯(cuò)誤的調(diào)用了自己(如想調(diào)用重載的其他方法,最后由于馬虎又重新調(diào)用了自己),或是遞歸方法寫的有問題,需要具體檢查代碼。
‘if’ statement replaceable with ‘switch’ statement
原因:為if…else…判斷條件太多導(dǎo)致,IDEA
認(rèn)為應(yīng)該替換為swtich
語句
if (condition1) { // Do something } else if (condition2) { // Do something } else if (condition3) { // Do something } else if (condition4) { // Do something } else if (condition5) { // Do something } else if (condition6) { // Do something } else { // Do something }
解決辦法:建議通過表驅(qū)動(dòng)、多態(tài)、設(shè)計(jì)模式等方式消除這么多的判斷,如果不得不進(jìn)行判斷,那么可以根據(jù)提示修改為switch
。
switch(xxx) { case condition1: xxx; break; case condition2: xxx; break; ... }
Result of ‘XX’ is ignored
原因:調(diào)用一個(gè)有返回值的方法,但是沒有使用該返回值。
File folder = new File("xx"); if (!folder.exists()) { folder.mkdir(); }
由于mkdir()
方法會(huì)返回boolean
類型的返回值,但是我們沒有使用,所以編譯器會(huì)報(bào)出警告。
解決辦法:可以使用返回值輸出一些日志等,如果實(shí)在不想使用返回值,那么可以在方法上標(biāo)注以下注解來壓制警告。
@SuppressWarnings("ResultOfMethodCallIgnored")
Statement lambda can be replaced with expression lambda
users.forEach(u -> { u.setState(xxx); })
當(dāng)有以上寫法時(shí)會(huì)有警告,可以看出lambda表達(dá)式方法體內(nèi)只有一行代碼,此時(shí)可以將花括號(hào)去掉進(jìn)行簡(jiǎn)寫
解決辦法:去掉大括號(hào)
users.forEach(u -> u.setState(xxx))
Lambda can be replaced with method reference
names.stream(). map(n -> n.toUpperCase()) ...
當(dāng)有如上寫法時(shí)會(huì)出現(xiàn)警告。
解決辦法:可以替換為方法調(diào)用的簡(jiǎn)寫形式
names.stream(). map(String::toUpperCase) ...
Condition ‘x != null’ covered by subsequent condition ‘x instanceof List’
原因:后面的判斷條件包含了前面的判斷條件
public boolean test(Object obj) { if (obj != null && obj instanceof String) { // Do sth... } }
上例中,如果obj
為null
,則自然obj instanceof String
為false
,所以不用重復(fù)判斷
解決辦法:去掉多余判斷
public boolean test(Object obj) { if (obj instanceof String) { // Do sth... } }
Actual value of parameter ‘xxx’ is always ‘yyy’
原因:調(diào)用某個(gè)方法時(shí),某個(gè)參數(shù)的值目前來說一直是固定的一個(gè)值。
解決辦法:
- 考慮是否一直是固定值,如果是,則將傳參改為局部變量或常量等。
- 如果該參數(shù)確實(shí)需要傳遞,只不過目前來說是一個(gè)值,將來不確定,可以考慮將其壓制
@SuppressWarnings("SameParameterValue")
Unchecked generics array creation for varargs parameter
解決辦法:在方法上添加注解
@SafeVarargs
XXX is deprecated
原因:調(diào)用某個(gè)標(biāo)記為@Deprecated
方法或?qū)傩詴r(shí),會(huì)報(bào)此警告。意為提示調(diào)用者這是個(gè)過時(shí)的方法或?qū)傩?,再未來的某個(gè)版本有可能會(huì)消失,不應(yīng)該調(diào)用該方法。
但是某種情況下我們確實(shí)需要調(diào)用過時(shí)的方法,比如我們開發(fā)工具類需要兼容老版本,或我們將一個(gè)方法標(biāo)記了過時(shí)之后,單元測(cè)試依舊調(diào)用此方法。
解決辦法:
- 如果可能的話,嘗試使用替代方法。一般來說在此方法的Javadoc中指引出新的方法。
- 如果確實(shí)需要調(diào)用過時(shí)的方法或?qū)傩?,可以考慮將其壓制
@SuppressWarnings("deprecation")
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java?Swing實(shí)現(xiàn)畫板的簡(jiǎn)單操作
這篇文章主要介紹了Java?Swing實(shí)現(xiàn)畫板的簡(jiǎn)單操作,修改顏色,更改圖形,清除,任務(wù)欄按鈕,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-06-06Invalid?bound?statement?(not?found)出現(xiàn)原因以及解決辦法
這篇文章主要給大家介紹了關(guān)于Invalid?bound?statement?(not?found)出現(xiàn)原因以及解決辦法的相關(guān)資料,文中給出了詳細(xì)的解決方法,需要的朋友可以參考下2023-07-07mybatis同一張表多次連接查詢相同列賦值問題小結(jié)
這篇文章主要介紹了mybatis同一張表多次連接查詢相同列賦值問題,非常不錯(cuò),具有參考借鑒價(jià)值,需要的的朋友參考下2017-01-01SpringBoot項(xiàng)目Docker部署三種方式
本文主要介紹了SpringBoot項(xiàng)目Docker部署三種方式,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-08-08關(guān)于Spring?Boot內(nèi)存泄露排查的記錄
這篇文章主要介紹了關(guān)于Spring?Boot內(nèi)存泄露排查的記錄,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06springboot CompletableFuture并行計(jì)算及使用方法
CompletableFuture基于 Future 和 CompletionStage 接口,利用線程池、回調(diào)函數(shù)、異常處理、組合操作等機(jī)制,提供了強(qiáng)大而靈活的異步編程功能,這篇文章主要介紹了springboot CompletableFuture并行計(jì)算及使用方法,需要的朋友可以參考下2024-05-05