亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

目錄
1. 背景與需求分析
2. 傳統(tǒng)迭代方式的實(shí)現(xiàn)與局限
3. 使用Java Stream API實(shí)現(xiàn)高效轉(zhuǎn)換
3.1 Collectors.groupingBy與Collectors.mapping
3.2 初步嘗試與優(yōu)化
4. 注意事項(xiàng)
5. 總結(jié)
首頁(yè) Java java教程 Java Stream實(shí)現(xiàn)復(fù)雜字符串?dāng)?shù)據(jù)分組與映射

Java Stream實(shí)現(xiàn)復(fù)雜字符串?dāng)?shù)據(jù)分組與映射

Oct 15, 2025 am 10:51 AM

Java Stream實(shí)現(xiàn)復(fù)雜字符串?dāng)?shù)據(jù)分組與映射

本文詳細(xì)介紹了如何利用Java Stream API,特別是Collectors.groupingBy和Collectors.mapping組合,將一個(gè)特定格式的字符串高效地轉(zhuǎn)換成Map>結(jié)構(gòu)。通過(guò)對(duì)比傳統(tǒng)迭代方式與Stream流式處理,演示了如何通過(guò)鏈?zhǔn)讲僮骱皖A(yù)處理優(yōu)化,以簡(jiǎn)潔、聲明式的方式實(shí)現(xiàn)復(fù)雜的數(shù)據(jù)分組與值映射,極大地提升代碼的可讀性和簡(jiǎn)潔性。

1. 背景與需求分析

在數(shù)據(jù)處理中,我們經(jīng)常會(huì)遇到需要將特定格式的原始字符串?dāng)?shù)據(jù)轉(zhuǎn)換成更易于操作的集合類型。例如,給定一個(gè)包含多個(gè)城市信息,以逗號(hào)分隔,每個(gè)城市信息又包含區(qū)域代碼和城市名稱,并以$$分隔的字符串:

String data = "010$$fengtai,010$$chaoyang,010$$haidain,027$$wuchang,027$$hongshan,027$$caidan,021$$changnin,021$$xuhui,020$$tianhe";

我們的目標(biāo)是將其轉(zhuǎn)換成一個(gè)Map>,其中Map的鍵(Key)是區(qū)域代碼($$之前的部分),值(Value)是該區(qū)域下所有城市名稱的列表($$之后的部分)。預(yù)期的結(jié)果示例如下:

{
  027=[wuchang, hongshan, caidan],
  020=[tianhe],
  010=[fengtai, chaoyang, haidain],
  021=[changnin, xuhui]
}

2. 傳統(tǒng)迭代方式的實(shí)現(xiàn)與局限

在Java 8之前,或者不熟悉Stream API時(shí),我們通常會(huì)采用傳統(tǒng)的循環(huán)迭代方式來(lái)完成此類轉(zhuǎn)換。以下是這種方法的示例:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class TraditionalParser {

    public Map<string list>> parseDataTraditional(String inputData) {
        // 第一步:按逗號(hào)分隔,并進(jìn)一步按$$分隔
        List<string> splitDataList = Arrays.stream(inputData.split(","))
            .map(s -> s.split("\\$\\$"))
            .collect(Collectors.toList()); // 這里仍使用了Stream,但后續(xù)是傳統(tǒng)迭代

        // 第二步:迭代處理,構(gòu)建Map
        Map<string list>> resultMap = new HashMap();
        for (String[] entry : splitDataList) {
            String key = entry[0];
            String value = entry[1];

            // 檢查Map中是否已存在該Key對(duì)應(yīng)的列表
            List<string> list = resultMap.get(key);
            if (list == null) {
                // 如果不存在,則創(chuàng)建新列表并添加元素
                list = new ArrayList();
                list.add(value);
                resultMap.put(key, list);
            } else {
                // 如果存在,則直接向現(xiàn)有列表中添加元素
                list.add(value);
            }
        }
        return resultMap;
    }
}</string></string></string></string>

這種方法雖然能夠?qū)崿F(xiàn)功能,但存在以下局限性:

  • 代碼冗長(zhǎng):需要顯式地創(chuàng)建HashMap和ArrayList,并包含大量的if-else邏輯來(lái)處理列表的創(chuàng)建和元素添加。
  • 可讀性差:業(yè)務(wù)邏輯被分散在多行代碼中,不易一眼看出其核心意圖——分組和映射。
  • 命令式編程:側(cè)重于“如何做”,而不是“做什么”,降低了代碼的聲明性。

3. 使用Java Stream API實(shí)現(xiàn)高效轉(zhuǎn)換

Java 8引入的Stream API提供了一種更簡(jiǎn)潔、更具聲明性的方式來(lái)處理集合數(shù)據(jù)。對(duì)于本例中的分組和映射需求,Collectors.groupingBy和Collectors.mapping是理想的組合。

3.1 Collectors.groupingBy與Collectors.mapping

  • Collectors.groupingBy(Function super T, ? extends K> classifier): 這是一個(gè)非常強(qiáng)大的收集器,用于根據(jù)提供的分類器函數(shù)(classifier)對(duì)Stream中的元素進(jìn)行分組。它將Stream中的元素轉(zhuǎn)換為Map>,其中K是分類器函數(shù)返回的鍵,List是屬于該鍵的所有原始元素的列表。

  • Collectors.groupingBy(Function super T, ? extends K> classifier, Collector super T, A, D> downstream): 這是groupingBy的重載版本,允許我們指定一個(gè)“下游收集器”(downstream)。這個(gè)下游收集器將應(yīng)用于每個(gè)分組內(nèi)部的元素,從而改變Map值的類型。例如,如果想讓Map的值不是List而是Set,或者像我們這里需要進(jìn)一步映射成List,就可以使用下游收集器。

  • Collectors.mapping(Function super T, ? extends U> mapper, Collector super U, A, R> downstream): mapping收集器本身并不是終端操作,它通常作為另一個(gè)收集器(如groupingBy的下游收集器)的參數(shù)。它的作用是先將Stream中的每個(gè)元素通過(guò)mapper函數(shù)進(jìn)行轉(zhuǎn)換,然后將轉(zhuǎn)換后的結(jié)果傳遞給其自身的下游收集器。

3.2 初步嘗試與優(yōu)化

讓我們回顧一下最初的Stream嘗試:

// 初始嘗試
Map<string list>> result =  Arrays.stream(data.split(","))
    .collect(Collectors.groupingBy(s -> s.split("\\$\\$")[0]));</string>

這個(gè)嘗試的問(wèn)題在于,它只完成了分組,但Map的值類型會(huì)是List,其中String是原始的完整字符串(例如"010$$fengtai"),而不是我們想要的僅包含城市名稱的List。為了解決這個(gè)問(wèn)題,我們需要在groupingBy中引入mapping作為下游收集器:

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class StreamParser {

    public Map<string list>> parseDataStream(String inputData) {
        return Arrays.stream(inputData.split(",")) // 1. 按逗號(hào)分隔原始字符串,得到Stream<string>
            .collect(Collectors.groupingBy(
                s -> s.split("\\$\\$")[0], // 2. 定義分組鍵:使用"$$"前綴作為Key
                Collectors.mapping(
                    s -> s.split("\\$\\$")[1], // 3. 定義值映射:使用"$$"后綴作為Value
                    Collectors.toList()       // 4. 定義下游收集器:將映射后的值收集到List中
                )
            ));
    }
}</string></string>

這個(gè)方案已經(jīng)非常接近目標(biāo),并且實(shí)現(xiàn)了“一句話”式的Stream操作。然而,仔細(xì)觀察可以發(fā)現(xiàn),s.split("\\$\\$")這個(gè)操作在groupingBy的分類器函數(shù)和mapping的映射函數(shù)中都被調(diào)用了兩次。對(duì)于每個(gè)元素,字符串都會(huì)被分割兩次,這可能帶來(lái)輕微的性能開(kāi)銷。

為了進(jìn)一步優(yōu)化,我們可以先進(jìn)行一次預(yù)處理,將每個(gè)原始字符串元素(如"010$$fengtai")轉(zhuǎn)換成一個(gè)String[]數(shù)組(如{"010", "fengtai"}),然后再進(jìn)行分組和映射。這樣,split操作就只執(zhí)行一次:

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class OptimizedStreamParser {

    public Map> parseDataOptimizedStream(String inputData) {
        return Arrays.stream(inputData.split(",")) // 1. 按逗號(hào)分隔原始字符串,得到Stream
            .map(s -> s.split("\\$\\$"))        // 2. 預(yù)處理:將每個(gè)String元素分割成String[]數(shù)組
            .collect(Collectors.groupingBy(
                sArray -> sArray[0],             // 3. 定義分組鍵:使用數(shù)組的第一個(gè)元素作為Key
                Collectors.mapping(
                    sArray -> sArray[1],         // 4. 定義值映射:使用數(shù)組的第二個(gè)元素作為Value
                    Collectors.toList()          // 5. 定義下游收集器:將映射后的值收集到List中
                )
            ));
    }

    public static void main(String[] args) {
        String data = "010$$fengtai,010$$chaoyang,010$$haidain,027$$wuchang,027$$hongshan,027$$caidan,021$$changnin,021$$xuhui,020$$tianhe";
        OptimizedStreamParser parser = new OptimizedStreamParser();
        Map> result = parser.parseDataOptimizedStream(data);
        System.out.println(result);
        // 預(yù)期輸出: {027=[wuchang, hongshan, caidan], 020=[tianhe], 021=[changnin, xuhui], 010=[fengtai, chaoyang, haidain]}
    }
}

這個(gè)優(yōu)化后的Stream管道不僅簡(jiǎn)潔,而且在效率上也更勝一籌,因?yàn)樗苊饬酥貜?fù)的字符串分割操作。

4. 注意事項(xiàng)

  • 數(shù)據(jù)格式的健壯性:上述Stream管道假設(shè)輸入數(shù)據(jù)嚴(yán)格遵循KEY$$VALUE,KEY$$VALUE的格式。如果數(shù)據(jù)中可能出現(xiàn)以下情況,需要額外處理:
    • 缺少$$分隔符:s.split("\\$\\$")[0]或s.split("\\$\\$")[1]可能會(huì)拋出ArrayIndexOutOfBoundsException。
    • 空字符串或只有$$:可能導(dǎo)致空鍵或空值,或數(shù)組越界。
    • 多個(gè)$$:split方法會(huì)按第一個(gè)$$分割,但如果預(yù)期行為不同,則需調(diào)整正則表達(dá)式。
    • 空元素:例如"010$$fengtai,,027$$wuchang",data.split(",")會(huì)產(chǎn)生空字符串。 為了增加健壯性,可以在map操作中加入filter或try-catch邏輯,或者在split之后進(jìn)行長(zhǎng)度檢查。例如:
      .map(s -> s.split("\\$\\$"))
      .filter(arr -> arr.length == 2) // 過(guò)濾掉格式不正確的元素
      // ... 后續(xù)分組邏輯
  • 性能考量:對(duì)于非常大的數(shù)據(jù)集,Stream API的鏈?zhǔn)讲僮骺赡軙?huì)引入一定的開(kāi)銷。但在大多數(shù)常規(guī)應(yīng)用場(chǎng)景下,其帶來(lái)的代碼簡(jiǎn)潔性和可讀性優(yōu)勢(shì)遠(yuǎn)大于這點(diǎn)微小的性能差異。如果性能成為瓶頸,應(yīng)進(jìn)行基準(zhǔn)測(cè)試,并可能考慮更底層的迭代優(yōu)化。
  • 可讀性與復(fù)雜性:雖然Stream API鼓勵(lì)“一句話”式的操作,但過(guò)于復(fù)雜的Stream管道可能會(huì)降低代碼的可讀性。當(dāng)邏輯變得非常復(fù)雜時(shí),可以考慮將Stream操作拆分成多個(gè)輔助方法,或者在某些情況下,傳統(tǒng)的循環(huán)可能更易于理解和維護(hù)。

5. 總結(jié)

通過(guò)本教程,我們學(xué)習(xí)了如何利用Java Stream API,特別是Collectors.groupingBy和Collectors.mapping的組合,高效且優(yōu)雅地將特定格式的字符串?dāng)?shù)據(jù)轉(zhuǎn)換成Map>。相較于傳統(tǒng)的迭代方式,Stream方案提供了更高的代碼簡(jiǎn)潔性、可讀性和聲明性,是現(xiàn)代Java開(kāi)發(fā)中處理集合數(shù)據(jù)的重要工具。同時(shí),我們也探討了如何通過(guò)預(yù)處理優(yōu)化Stream管道,并強(qiáng)調(diào)了在實(shí)際應(yīng)用中需要考慮數(shù)據(jù)健壯性和性能的平衡。掌握這些技術(shù),將有助于編寫更現(xiàn)代、更強(qiáng)大的Java應(yīng)用程序。

以上是Java Stream實(shí)現(xiàn)復(fù)雜字符串?dāng)?shù)據(jù)分組與映射的詳細(xì)內(nèi)容。更多信息請(qǐng)關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

本站聲明
本文內(nèi)容由網(wǎng)友自發(fā)貢獻(xiàn),版權(quán)歸原作者所有,本站不承擔(dān)相應(yīng)法律責(zé)任。如您發(fā)現(xiàn)有涉嫌抄襲侵權(quán)的內(nèi)容,請(qǐng)聯(lián)系admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費(fèi)脫衣服圖片

Undresser.AI Undress

Undresser.AI Undress

人工智能驅(qū)動(dòng)的應(yīng)用程序,用于創(chuàng)建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用于從照片中去除衣服的在線人工智能工具。

Stock Market GPT

Stock Market GPT

人工智能驅(qū)動(dòng)投資研究,做出更明智的決策

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費(fèi)的代碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

功能強(qiáng)大的PHP集成開(kāi)發(fā)環(huán)境

Dreamweaver CS6

Dreamweaver CS6

視覺(jué)化網(wǎng)頁(yè)開(kāi)發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

神級(jí)代碼編輯軟件(SublimeText3)

熱門話題

如何在Java中的類Path中添加JAR文件? 如何在Java中的類Path中添加JAR文件? Sep 21, 2025 am 05:09 AM

使用-cp參數(shù)可將JAR加入類路徑,使JVM能加載其內(nèi)類與資源,如java-cplibrary.jarcom.example.Main,支持多JAR用分號(hào)或冒號(hào)分隔,也可通過(guò)CLASSPATH環(huán)境變量或MANIFEST.MF配置。

如何在Java中創(chuàng)建文件 如何在Java中創(chuàng)建文件 Sep 21, 2025 am 03:54 AM

UseFile.createNewFile()tocreateafileonlyifitdoesn’texist,avoidingoverwriting;2.PreferFiles.createFile()fromNIO.2formodern,safefilecreationthatfailsifthefileexists;3.UseFileWriterorPrintWriterwhencreatingandimmediatelywritingcontent,withFileWriterover

使用Java服務(wù)提供商界面(SPI)構(gòu)建可擴(kuò)展應(yīng)用程序 使用Java服務(wù)提供商界面(SPI)構(gòu)建可擴(kuò)展應(yīng)用程序 Sep 21, 2025 am 03:50 AM

JavaSPI是JDK內(nèi)置的服務(wù)發(fā)現(xiàn)機(jī)制,通過(guò)ServiceLoader實(shí)現(xiàn)面向接口的動(dòng)態(tài)擴(kuò)展。1.定義服務(wù)接口并在META-INF/services/下創(chuàng)建以接口全名為名的文件,寫入實(shí)現(xiàn)類全限定名;2.使用ServiceLoader.load()加載實(shí)現(xiàn)類,JVM會(huì)自動(dòng)讀取配置并實(shí)例化;3.設(shè)計(jì)時(shí)應(yīng)明確接口契約、支持優(yōu)先級(jí)與條件加載、提供默認(rèn)實(shí)現(xiàn);4.應(yīng)用場(chǎng)景包括多支付渠道接入和插件化校驗(yàn)器;5.注意性能、類路徑、異常隔離、線程安全和版本兼容性;6.在Java9 可結(jié)合模塊系統(tǒng)使用provid

如何在Java中實(shí)現(xiàn)接口? 如何在Java中實(shí)現(xiàn)接口? Sep 18, 2025 am 05:31 AM

使用implements關(guān)鍵字實(shí)現(xiàn)接口,類需提供接口中所有方法的具體實(shí)現(xiàn),支持多接口時(shí)用逗號(hào)分隔,確保方法為public,Java8后默認(rèn)和靜態(tài)方法無(wú)需重寫。

了解Java仿制藥和通配符 了解Java仿制藥和通配符 Sep 20, 2025 am 01:58 AM

Javagenericsprovidecompile-timetypesafetyandeliminatecastingbyallowingtypeparametersonclasses,interfaces,andmethods;wildcards(?,?extendsType,?superType)handleunknowntypeswithflexibility.1.UseunboundedwildcardwhentypeisirrelevantandonlyreadingasObject

深入理解HTTP持久連接:在同一Socket上發(fā)送多個(gè)請(qǐng)求的策略與實(shí)踐 深入理解HTTP持久連接:在同一Socket上發(fā)送多個(gè)請(qǐng)求的策略與實(shí)踐 Sep 21, 2025 pm 01:51 PM

本文深入探討了在同一TCP Socket上發(fā)送多個(gè)HTTP請(qǐng)求的機(jī)制,即HTTP持久連接(Keep-Alive)。文章澄清了HTTP/1.x與HTTP/2協(xié)議的區(qū)別,強(qiáng)調(diào)了服務(wù)器端對(duì)持久連接支持的重要性,以及如何正確處理Connection: close響應(yīng)頭。通過(guò)分析常見(jiàn)錯(cuò)誤和提供最佳實(shí)踐,旨在幫助開(kāi)發(fā)者構(gòu)建高效且健壯的HTTP客戶端。

Java教程:如何扁平化嵌套ArrayList并將其元素填充到數(shù)組中 Java教程:如何扁平化嵌套ArrayList并將其元素填充到數(shù)組中 Sep 18, 2025 am 07:24 AM

本教程詳細(xì)介紹了在Java中如何高效地處理包含其他ArrayList的嵌套ArrayList,并將其所有內(nèi)部元素合并到一個(gè)單一的數(shù)組中。文章將通過(guò)Java 8 Stream API的flatMap操作,提供兩種核心解決方案:先扁平化為列表再填充數(shù)組,以及直接創(chuàng)建新數(shù)組,以滿足不同場(chǎng)景的需求。

如何讀取Java中的屬性文件? 如何讀取Java中的屬性文件? Sep 16, 2025 am 05:01 AM

使用Properties類可輕松讀取Java配置文件。1.將config.properties放入資源目錄,通過(guò)getClassLoader().getResourceAsStream()加載并調(diào)用load()方法讀取數(shù)據(jù)庫(kù)配置。2.若文件在外部路徑,使用FileInputStream加載。3.使用getProperty(key,defaultValue)處理缺失鍵并提供默認(rèn)值,確保異常處理和輸入驗(yàn)證。

See all articles