深入IDEA Debug問題透析詳解
引言
本來通過問題引入,透析 IDEA Debug。通過閱讀本文可以學(xué)習(xí)如何通過 IDEA 的 Debug 功能解決實(shí)際問題。本文適合剛剛參加工作并且有使用 Spring 以及 JPA 經(jīng)驗(yàn)的朋友。
問題引入
最近看了 eclipse 開源的集合 Eclipse Collections,覺得它的 api 相比 JDK 集合 api 簡(jiǎn)潔,想在實(shí)際項(xiàng)目中使用,如下。
JDK api
// users is List<String> users.stream.map(user -> user.getName()).collect(Collectors.toList());
Eclipse Collections api
//users is MutableList users.collect(user -> user.getName);
項(xiàng)目實(shí)際開發(fā)中使用集合最多的地方還是來自數(shù)據(jù)庫(kù)查詢,如下。
JDK api
List<User> findByCity(String city);
我想改成
MutableList<User> findByCity(String city);
然而報(bào)錯(cuò)了
org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.util.ArrayList<?>] to type [org.eclipse.collections.api.list.MutableList<?>] for value '[]'; nested exception is java.lang.IllegalArgumentException: Unsupported Collection interface: org.eclipse.collections.api.list.MutableList
at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:47)
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:192)
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:175)
太長(zhǎng)不看直接結(jié)論是改成下列代碼。
FastList<User> findByCity(String city);
Debug
對(duì)代碼簡(jiǎn)單分析
報(bào)錯(cuò)的地方都是 Spring
的包,證明我們使用的 Spring Data JPA
訪問數(shù)據(jù)庫(kù),事實(shí)上也是。
查看類名稱,方法名稱。 有 convert.ConversionFailedException
/convert.support.ConversionUtils.invokeConverter
/convert.support.GenericConversionService.convert
等等,關(guān)鍵詞 convert
,我應(yīng)該聯(lián)想到這段代碼的功能是把什么類型 convert
到什么類型。
再分析報(bào)錯(cuò)的那一行我們會(huì)更清晰一點(diǎn)。
result
是轉(zhuǎn)換的結(jié)果。converter
是轉(zhuǎn)換器,結(jié)合上面的結(jié)論,這個(gè)類肯定是真正執(zhí)行轉(zhuǎn)換的類,我們要的核心代碼肯定在這里,如果你直接去看的話,它肯定是一個(gè)接口,面向接口編程。sourceType
源類型,結(jié)合上述分析肯定是原始類型。targetType
目標(biāo)類型,同上不贅述。
打斷點(diǎn)
IDEA 可以直接點(diǎn)擊報(bào)錯(cuò) class 定位到源文件,這里我們先點(diǎn)擊 ConversionFailedException
,再點(diǎn)擊 ConversionUtils.java:47
,發(fā)現(xiàn)都是報(bào)錯(cuò)的異常,對(duì)我們沒有幫助。最后我們點(diǎn)擊 GenericConversionService.java:192
,終于看到一行代碼了。
Object result = ConversionUtils.invokeConverter(converter, source, sourceType, targetType);
斷點(diǎn)分析
執(zhí)行過程會(huì)停留在斷點(diǎn)處,我們可以查看上下文變量類的實(shí)例。這里我們以 converter
為例。按照數(shù)字步驟點(diǎn)擊,如下。
可能的 converter
如下:
1. java.lang.String -> java.lang.Enum 2. NO_OP 3. java.lang.Boolean -> java.lang.String // 等等。。。。。
由于是底層方法,被調(diào)用的次數(shù)很多,在這個(gè)斷點(diǎn)停留的次數(shù)也很多。很多次不是我們想要的 converter
。
條件斷點(diǎn)
顧名思義 IDEA 會(huì)通過我們添加的條件來判斷這個(gè)斷點(diǎn)是否需要被處理。
我們想要的 converter
是什么呢?回到代碼分析階段,我們想要的 converter
是 sourceType
→ targetType
,targetType
類型是什么呢?回到我們自己寫的代碼。
MutableList<User> findByAdress(String address);
可以看到我們需要 targetType
是 MutableList
class。
下面添加條件斷點(diǎn):
完整的條件如下:
MutableList.class.isAssignableFrom(targetType.getType());
添加成功的標(biāo)志如下。
單步調(diào)試
Debug 模式啟動(dòng)程序,可以看到 IDEA 停留在我們的條件斷點(diǎn)上,并且targetType
的類型正是 MutableList
。
單步調(diào)試代碼,來到 org.springframework.core.CollectionFactory#createCollection
方法。
部分代碼如下:
//省略的代碼 // 判斷集合類型是不是 ArrayList 或者 List,顯然這里不是 else if (ArrayList.class == collectionType || List.class == collectionType) { return new ArrayList<>(capacity); } //省略的代碼 else { //如果是集合類型的接口 或者 不是集合類型拋出異常 if (collectionType.isInterface() || !Collection.class.isAssignableFrom(collectionType)) { throw new IllegalArgumentException("Unsupported Collection type: " + collectionType.getName()); } try { //如果是集合類型的類,直接通過反射實(shí)例化。 return (Collection<E>) ReflectionUtils.accessibleConstructor(collectionType).newInstance(); } }
重回代碼分析
我們的 targetType
的類型正是 MutableList
,而 MutableList
是接口,走讀代碼可以發(fā)現(xiàn)最終會(huì)執(zhí)行下面的代碼,最終導(dǎo)致拋出異常。
if (collectionType.isInterface() || !Collection.class.isAssignableFrom(collectionType)) { throw new IllegalArgumentException("Unsupported Collection type: " + collectionType.getName()); }
翻看控制臺(tái)找到了下面的異常信息,這也側(cè)面反映我們之前找的報(bào)錯(cuò)位置不是很精確。我們尋找異常時(shí)應(yīng)該選擇最原始的異常信息。
Caused by: java.lang.IllegalArgumentException: Unsupported Collection type: org.eclipse.collections.api.list.MutableList at org.springframework.core.CollectionFactory.createCollection(CollectionFactory.java:205) at org.springframework.core.convert.support.CollectionToCollectionConverter.convert(CollectionToCollectionConverter.java:81)
繼續(xù)分析源碼可以發(fā)現(xiàn),如果我們定義的類型不是接口,JPA
就會(huì)通過反射創(chuàng)建集合,即如下代碼:
return (Collection<E>) ReflectionUtils.accessibleConstructor(collectionType).newInstance();
所以我們只需要將 MutableList
換成它的實(shí)現(xiàn)類即可,比如 FastList
。最終代碼如下:
FastList<User> findByCity(String city);
總結(jié)
本來通過解決實(shí)際問題介紹了 IDEA Debug 功能的使用。還有以下幾點(diǎn)需要注意。
- 查找異常時(shí)要定位到最初始的異常,這樣往往能迅速處理問題。
- 本文的問題只有在 sping boot 2.7.0 以下才會(huì)出現(xiàn),高版本已經(jīng)修復(fù)此問題。參見提交 spring data common。
- 使用非 Java 官方集合需要進(jìn)行轉(zhuǎn)換,有微小的性能損耗,對(duì)于常規(guī)內(nèi)存操作來說影響很小。如果查詢數(shù)據(jù)上千上萬條時(shí),應(yīng)該避免轉(zhuǎn)換。
以上就是深入IDEA Debug問題透析詳解的詳細(xì)內(nèi)容,更多關(guān)于IDEA Debug問題透析的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
java根據(jù)圖片中綠色像素點(diǎn)的多少進(jìn)行排序
這篇文章主要介紹了java根據(jù)圖片中綠色像素點(diǎn)的多少進(jìn)行排序,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03Java實(shí)現(xiàn)FIFO任務(wù)調(diào)度隊(duì)列策略
在工作中,很多高并發(fā)的場(chǎng)景中,我們會(huì)用到隊(duì)列來實(shí)現(xiàn)大量的任務(wù)請(qǐng)求。當(dāng)任務(wù)需要某些特殊資源的時(shí)候,我們還需要合理的分配資源,讓隊(duì)列中的任務(wù)高效且有序完成任務(wù)。本文將為大家介紹通過java實(shí)現(xiàn)FIFO任務(wù)調(diào)度,需要的可以參考一下2021-12-12Java基于PDFbox實(shí)現(xiàn)讀取處理PDF文件
PDFbox是一個(gè)開源的、基于Java的、支持PDF文檔生成的工具庫(kù),它可以用于創(chuàng)建新的PDF文檔,修改現(xiàn)有的PDF文檔,還可以從PDF文檔中提取所需的內(nèi)容。本文將具體介紹一下PDFbox讀取處理PDF文件的示例代碼,感興趣的可以學(xué)習(xí)一下2022-02-02java基于odbc連接oracle的實(shí)現(xiàn)方法
這篇文章主要介紹了java基于odbc連接oracle的實(shí)現(xiàn)方法,結(jié)合實(shí)例形式分析了連接操作的具體步驟與相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2016-09-09Spring Boot實(shí)現(xiàn)郵件發(fā)送功能
這篇文章主要為大家詳細(xì)介紹了Spring Boot實(shí)現(xiàn)郵件發(fā)送功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06