Java雙重for循環(huán)的優(yōu)化示例
在工作中,經(jīng)常性的會(huì)出現(xiàn)在兩張表中查找相同ID的數(shù)據(jù),許多開(kāi)發(fā)者會(huì)使用兩層for循環(huán)嵌套,雖然實(shí)現(xiàn)功能沒(méi)有問(wèn)題,但是效率極低,一下是一個(gè)簡(jiǎn)單的優(yōu)化過(guò)程,代碼耗時(shí)湊從26856ms優(yōu)化到了748ms。
功能場(chǎng)景
有兩份List類型的數(shù)據(jù),分別是UestList(用戶表)和AccountList(賬戶表),要根據(jù)用戶的id從AccountList表中查找對(duì)應(yīng)的賬戶信息,并進(jìn)行后續(xù)的處理,示例如下:
存數(shù)據(jù)(偽代碼):5w條user數(shù)據(jù),3w條Account數(shù)據(jù)
@Data class User{ private Long userId; private String name; } @Data class Account{ private Long userId; private String content; } public class NestedLoopOptimization{ public static List<User> getUserList(){ List<User> users =new ArrayList<>(); for(inti =1; i <=50000; i++) { User user =newUser(); user.setName(UUID.randomUUID().toString()); user.setUserId((long) i); users.add(user); } return users; } public static List<UserMemo> getAccountTestList(){ List<Account> accountList =newArrayList<>(); for(inti =30000; i >=1; i--) { Account account =new Account(); account.setContent(UUID.randomUUID().toString()); account.setUserId((long) i); accountList.add(account); } return accountList; } // ... 后續(xù)代碼
最直接的實(shí)現(xiàn)方式(未優(yōu)化的代碼):
public static void nestedLoop(List<User> usersList, List<UserMemo> accountList) { for (User user : usersList) { Long userId = user.getUserId(); for (Account account : accountList) { if (userId.equals(account.getUserId())) { String content = account.getContent(); // System.out.println("模擬數(shù)據(jù)content 業(yè)務(wù)處理......" + content); // 避免打印影響測(cè)試結(jié)果 } } } }
耗時(shí):約數(shù)萬(wàn)毫秒,效率很低,數(shù)據(jù)量小的話無(wú)關(guān)緊要,如果隨著系統(tǒng)的迭代數(shù)據(jù)量驟增的時(shí)候,就會(huì)極其耗時(shí)。
第一步優(yōu)化:添加break
每個(gè)userId在AccountList中只有一條對(duì)應(yīng)的數(shù)據(jù),所以找到匹配項(xiàng)之后就可以跳出內(nèi)循環(huán):
public static void nestedLoop(List<User> usersList, List<UserMemo> accountList) { for (User user : usersList) { Long userId = user.getUserId(); for (Account account : accountList) { if (userId.equals(account.getUserId())) { String content = account.getContent(); // System.out.println("模擬數(shù)據(jù)content 業(yè)務(wù)處理......" + content); // 避免打印影響測(cè)試結(jié)果 break; } } } }
第一步優(yōu)化結(jié)束之后任需要很多耗時(shí),但是比起嵌套循環(huán)好很多。
第二步優(yōu)化:使用Map優(yōu)化
public static void mapOptimizedLoop(List<User> userTestList, List<UserMemo> accountList) { Map<Long, String> contentMap = accountList.stream().collect(Collectors.toMap(UserMemo::getUserId, UserMemo::getContent)); for (User user : userTestList) { Long userId = user.getUserId(); String content = contentMap.get(userId); if (StringUtils.hasLength(content)) { // System.out.println("模擬數(shù)據(jù)content 業(yè)務(wù)處理......" + content); // 避免打印影響測(cè)試結(jié)果 } } }
做以上優(yōu)化之后,耗時(shí)顯著減少,通常在數(shù)百毫秒級(jí)別。
原理:
兩層 for 循環(huán)嵌套的時(shí)間復(fù)雜度為 O(n*m),其中 n 和 m 分別為兩個(gè)列表的長(zhǎng)度。使用 Map 后,get 操作的時(shí)間復(fù)雜度接近 O(1),整體時(shí)間復(fù)雜度降為 O(n+m),避免了內(nèi)循環(huán)的重復(fù)遍歷。HashMap 的 get 方法內(nèi)部使用了 getNode 方法來(lái)查找鍵值對(duì)。getNode 方法利用哈希表結(jié)構(gòu),快速定位到目標(biāo)鍵值對(duì)。雖然在極端情況下(所有鍵的哈希值都相同),getNode 的時(shí)間復(fù)雜度會(huì)退化為 O(n),但在實(shí)際應(yīng)用中,哈希沖突的概率很低,HashMap 的 get 操作效率通常很高。因此無(wú)需過(guò)于擔(dān)心 O(n) 的最壞情況。
通過(guò)以上優(yōu)化之后,可以顯著的提高代碼的執(zhí)行效率,已經(jīng)其健壯性,尤其是在處理大數(shù)據(jù)量的時(shí)候,使用Map優(yōu)化,可以帶來(lái)巨大的性能提升,避免了不必要的計(jì)算,從而實(shí)現(xiàn)了代碼的性能。
到此這篇關(guān)于Java雙重for循環(huán)的優(yōu)化示例的文章就介紹到這了,更多相關(guān)Java雙重for循環(huán)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解Spring Boot實(shí)戰(zhàn)之Filter實(shí)現(xiàn)使用JWT進(jìn)行接口認(rèn)證
本篇文章主要介紹了詳解Spring Boot實(shí)戰(zhàn)之Filter實(shí)現(xiàn)使用JWT進(jìn)行接口認(rèn)證,具有一定的參考價(jià)值,有興趣的可以了解一下2017-07-07java正則表達(dá)式獲取指定HTML標(biāo)簽的指定屬性值且替換的方法
下面小編就為大家?guī)?lái)一篇java正則表達(dá)式獲取指定HTML標(biāo)簽的指定屬性值且替換的方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-12-12Java應(yīng)用多機(jī)器部署解決大量定時(shí)任務(wù)問(wèn)題
這篇文章主要介紹了Java應(yīng)用多機(jī)器部署解決大量定時(shí)任務(wù)問(wèn)題,兩臺(tái)服務(wù)器同時(shí)部署了同一套代碼, 代碼中寫(xiě)有spring自帶的定時(shí)任務(wù),但是每次執(zhí)行定時(shí)任務(wù)時(shí)只需要一臺(tái)機(jī)器去執(zhí)行,需要的朋友可以參考下2019-07-07關(guān)于java中@Async異步調(diào)用詳細(xì)解析附代碼
本文主要介紹了java關(guān)于@Async異步調(diào)用詳細(xì)解析附代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07FastJson時(shí)間格式化問(wèn)題避坑經(jīng)驗(yàn)分享
這篇文章主要為大家介紹了FastJson時(shí)間格式化問(wèn)題避坑經(jīng)驗(yàn)分享,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08