代碼出錯了,IDE竟然不報錯?太詭異了....
小伙伴好哇,我是Tom哥。
今天分享一個寫代碼時遇到的詭異問題,如何排查解決的。
從事互聯網的人都懂,一般遇到問題時,首先會想用谷歌、百度等搜索引擎,看看前輩們是如何解決的。
但有些問題比較抽象,不知道如何來描述,怎么辦?或者勉強描述清楚了,搜出來的答案也很難滿足要求,整個過程猶如大海撈針。最后求助 ChatGPT 瞬間解決,給大家分享下解決思路。
問題的來龍去脈
正在開發一個項目,倉儲層有一個接口類(IProductReadRepository),其中一個方法的入參使用了 Java 泛型,具體如下:
List<SpuVO> batchQuerySpuBySpuIdsFromDB(ProductQueryWrapper<List<Long>> req);
在上層的領域服務中,有一處調用這個方法的代碼,具體如下:
ProductQueryWrapper productQueryWrapper = ProductQueryWrapper.builder()
.bizCode(BusinessCodeEnum.SMART.getCode())
.bizScene(BusinessSceneEnum.RETAIL.getCode())
.storeId(multiPackageVO.getStoreId())
.bizParams(spuIds)
.build();
List<ProductSummaryVO> productSummaryVOS = productReadRepository.batchQuerySpuBySpuIdsFromDB(productQueryWrapper);
if (CollectionUtils.isEmpty(productSummaryVOS)) {
bizResult.error(BizErrorCode.MULTI_PACKAGE_PRODUCT_NOT_EXIST);
return bizResult;
}
其中,List<ProductSummaryVO> productSummaryVOS = productReadRepository.batchQuerySpuBySpuIdsFromDB(productQueryWrapper); 這行代碼非常詭異
返回的結果List<ProductSummaryVO>并不匹配,但在IDEA中卻沒有報錯,這讓我們感到非常困擾。
這是怎么回事?
當時懷疑是錯覺,仔細對比了兩個方法,確實是對的。
又懷疑是 IDEA 的緩存干擾導致,所以將工程重新 build 了一次還是不行!
接下來,能想到的各種招數都招呼上,比如:
- 在終端執行 mvn clean install -U,重新編譯代碼,并強制 Maven 更新所有依賴的快照版本(Snapshot)
- 手動將 maven 的本地倉庫的依賴包全部刪除,重新拉取
- 將本地工程文件中的 target 文件刪除
- .....
最后,使出絕招,將本地的工程代碼全部刪除,然后重新從 git 上拉取最新代碼,編譯,導入到 IDEA 工程。
但,但,但,問題依然存在,真讓人崩潰。
難道是 IDEA 中的錯誤檢查失效了,于是人為制造了一些錯誤,發現 IDEA 也都能識別出來。
實在沒招了。。。。。。。
最后,還是問下 ChatGPT 吧
首先,先把問題描述清楚,ChatGPT 特懂人情世故,你跟他講清楚問題,他也會給你一個清楚的答案。
有一個接口內的方法定義如下:
List<SpuVO> batchQuerySpuBySpuIdsFromDB(ProductQueryWrapper<List<Long>> req);
使用下面的代碼來調用 batchQuerySpuBySpuIdsFromDB,返回的 List<SpuVO> 結果并不匹配,但在 IDEA 中沒有報錯,是什么原因?
ProductQueryWrapper productQueryWrapper = ProductQueryWrapper.builder()
.bizCode(BusinessCodeEnum.SMART.getCode())
.bizScene(BusinessSceneEnum.RETAIL.getCode())
.storeId(multiPackageVO.getStoreId())
.bizParams(spuIds)
.build();
List<ProductSummaryVO> productSummaryVOS = productReadRepository.batchQuerySpuBySpuIdsFromDB(productQueryWrapper);
if (CollectionUtils.isEmpty(productSummaryVOS)) {
bizResult.error(BizErrorCode.MULTI_PACKAGE_PRODUCT_NOT_EXIST);
return bizResult;
}
ChatGPT 很快就給出了答案。
問題可能出在泛型擦除和編譯時類型檢查上。由于Java泛型的擦除機制,在運行時無法獲取泛型的實際類型,這可能導致類型不匹配的問題。
那我們就按照它的思路來,將這行代碼 ProductQueryWrapper productQueryWrapper = ProductQueryWrapper.builder()
修改為 ProductQueryWrapper<List<Long>> productQueryWrapper = ProductQueryWrapper.<List<Long>>builder()
在構建 ProductQueryWrapper 對象時, 指定泛型參數的具體類型,以便在運行時能夠正確地識別參數類型。
然后,問題真的解決了。
如下圖所示,第二處紅框位置的代碼開始報錯。因為接口的規范(返回結果)調整了,此處確實應該報錯提示。
后面,我們根據錯誤提示,將 ProductSummaryVO 類替換成 SpuVO 類。
最終,不但編譯不報錯,單元測試也能跑通。問題完美解決。
背后的原因
為何在 IDEA 中沒有直接報錯呢?這里牽扯到Java泛型的類型推斷機制。
上述代碼中,雖然使用了原始類型 ProductQueryWrapper ,但沒有指定具體的泛型類型。
Java 7 及以后的版本引入了菱形操作符(Diamond Operator),允許在創建對象時不再重復指定泛型類型,而是通過上下文進行類型推斷。
這就意味著在你的代碼中,雖然沒有明確指定泛型類型,但由于在 ProductQueryWrapper.builder() 上下文中,編譯器會嘗試根據調用方的期望類型來推斷泛型參數。
這種類型推斷機制使得在 IDEA 開發工具不會直接報錯,也就出現了上文說到的那個問題。
今天的分享就到這里,我們下回再見。