最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解Java中Stream流的用法和原理

 更新時(shí)間:2023年10月07日 10:57:46   作者:會(huì)飛的喵喵  
最近編碼的時(shí)候用到了Stream這個(gè)東西,以前也用過(guò),但是對(duì)它沒(méi)有一個(gè)系統(tǒng)的認(rèn)知,在好奇心的驅(qū)動(dòng)下還是決定花一些時(shí)間去系統(tǒng)地學(xué)一學(xué),不了解Stream的同學(xué)可以看看本文,對(duì)大家的學(xué)習(xí)和工作有一定的幫助

一、創(chuàng)建不可變的集合

不可變的集合,顧名思義,就是不想讓別人修改集合中的內(nèi)容,也無(wú)法修改。如何創(chuàng)建呢?

(一)創(chuàng)建格式

在List、Set、Map接口中,都存在靜態(tài)的of方法,可以獲取一個(gè)不可變的集合:

  • static List of(E...elements) 創(chuàng)建一個(gè)具有指定元素的List集合對(duì)象。
  • static Set of(E...elements) 創(chuàng)建一個(gè)具有指定元素的Set集合對(duì)象。
  • static <K , V> Map<K,V> of(E...elements) 創(chuàng)建一個(gè)具有指定元素的Map集合對(duì)象。

(List.of在jdk8中沒(méi)有,需要jdk9及以上的版本。)

public static void main(String[] args) {
    List<String> list = List.of("張三","李四","王五");
    for(String tmp : list){
        System.out.println(tmp);
    }
    System.out.println("----------------------------");
    Set<Integer> set = Set.of(1,2,3,4);
    for(int x : set){
        System.out.println(x);
    }
    System.out.println("-----------------------------");
    Map<String, Integer> map = Map.of("王五", 1, "李四", 2);
    Set<Map.Entry<String, Integer>> entries = map.entrySet();
    for(Map.Entry<String, Integer> entry : entries){
        System.out.println(entry.getKey() + ":" + entry.getValue());
    }
    System.out.println("------------------------------");
}

  • 這些集合不能添加,不能刪除,不能修改,如果修改會(huì)拋異常:
    public static void main(String[] args) {
        List<String> list = List.of("張三","李四","王五");
        list.remove(0);
    }

結(jié)果:

  • 這里的Set集合中不能有相同的值,Map不能有相同的key,否則拋異常。
public static void main(String[] args) {
    Set<Integer> set = Set.of(1,1,2,3,4);
}

  • Map.of()里的參數(shù)最多傳 10 個(gè)鍵值對(duì),源碼里of()方法參數(shù)最多的也就10對(duì)。

那為什么不用可變參數(shù)呢?因?yàn)榭勺儏?shù)只能有一個(gè),并且要在參數(shù)列表的末尾。如果想要存超過(guò)10個(gè)的鍵值對(duì),我們可以利用數(shù)組->可變參數(shù)

    public static void main(String[] args) {
        Map<Integer,String> map = new HashMap<>();
        map.put(1,"a");
        map.put(2,"b");
        map.put(3,"c");
        map.put(4,"d");
        map.put(5,"e");
        map.put(6,"f");
        map.put(7,"g");
        map.put(8,"h");
        map.put(9,"i");
        map.put(10,"j");
        map.put(11,"k");
        map.put(12,"l");
        //獲取所有的鍵值對(duì)
        Set<Map.Entry<Integer,String>> entries = map.entrySet();
        //把entries變成一個(gè)數(shù)組
        //如果集合的長(zhǎng)度 〉數(shù)組的長(zhǎng)度﹔數(shù)據(jù)在數(shù)組中放不下,此時(shí)會(huì)根據(jù)實(shí)際數(shù)據(jù)的個(gè)數(shù),重新創(chuàng)建數(shù)組
        //如果集合的長(zhǎng)度〈=數(shù)組的長(zhǎng)度:數(shù)據(jù)在數(shù)組中放的下,此時(shí)不會(huì)創(chuàng)建新的數(shù)組,而是直接用原來(lái)的數(shù)組
        Map.Entry[] array = entries.toArray(new Map.Entry[0]);
        //生成不可變map集合,ofEntries()的參數(shù)是可變參數(shù),可變參數(shù)可以使用數(shù)組。
        Map map1 = Map.ofEntries(array);
    }

第二種方式,但是要jdk10及以上:

    public static void main(String[] args) {
        Map<Integer,String> map = new HashMap<>();
        map.put(1,"a");
        map.put(2,"b");
        map.put(3,"c");
        map.put(4,"d");
        map.put(5,"e");
        map.put(6,"f");
        map.put(7,"g");
        map.put(8,"h");
        map.put(9,"i");
        map.put(10,"j");
        map.put(11,"k");
        map.put(12,"l");
        //生成不可變集合
        Map<Integer,String> map1 = Map.copyOf(map);
    }

(二)不可變集合的作用

  • 保證線程安全:不可變集合是一種在創(chuàng)建之后就不再變更的對(duì)象,這種特性使得它們天生支持線程安全。
  • 防止數(shù)據(jù)被篡改:不可變集合可以用于封裝一些敏感或重要的數(shù)據(jù),防止它們被外部程序或不可信的庫(kù)修改或破壞。

二、Stream 流

(一)Stream 的思想

Stream 為什么叫流?可以通過(guò)下面的案例來(lái)引入這個(gè)概念。

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("陳大帥");
        list.add("陳小帥");
        list.add("小紅");
        list.add("李四");
        list.add("陳四");
        //篩選姓陳的,并且名字是3個(gè)字的人
        list.stream().filter(name->name.startsWith("陳"))
                     .filter(name->name.length()==3)
                     .forEach(name-> System.out.println(name));
    }

Stream 就像流水線一樣,這個(gè)流水線第一道工序就是過(guò)濾掉不姓陳的,第二道工序過(guò)濾掉字的數(shù)量不等于3的,最后的工序就是打印。

(二)Stream流的使用步驟

  • 得到一條Stream流水線,把數(shù)據(jù)放上去。
  • 利用Stream流中的API進(jìn)行各種操作。

    中間方法:方法調(diào)用后還可以調(diào)用其它方法,如上面的filter。

    終結(jié)方法:最后一步,調(diào)用后不能調(diào)用其它方法。

1.把數(shù)據(jù)放到流水線上

獲取方式方法名說(shuō)明
單列集合default Stream stream()collection中的默認(rèn)方法(由于單列集合實(shí)現(xiàn)了Collection接口,可以直接.stream())
雙列集合(Map等)無(wú)無(wú)法直接使用stream流
數(shù)組public static Stream stream(T[] array)Arrays工具類中的靜態(tài)方法
零碎數(shù)據(jù)public static Stream stream(T[] array)Stream接口中的靜態(tài)方法
    public static void main(String[] args) {
        //1.單列集合
        List<String> list = new ArrayList<>();
        Collections.addAll(list,"a","b","b","b","c","d","e");//添加數(shù)據(jù)
        list.stream().forEach(s -> System.out.println(s));//流水線操作
        //2.雙列集合
        Map<Integer,String> map = new HashMap<>();
        map.put(1,"a");
        map.put(2,"b");
        map.put(3,"c");
        map.put(4,"d");
        map.put(5,"e");
        map.put(6,"f");
        map.keySet().stream().forEach(s-> System.out.println(s));//方式1:獲取key的流水線,利用key與value的關(guān)系來(lái)操作整體
        map.entrySet().stream().forEach(entry-> System.out.println(entry));//方式2:獲取鍵值對(duì)的流水線
        //3.數(shù)組
        int[] arr = {1,2,3,4,5,6,7,8};
        Arrays.stream(arr).forEach(x-> System.out.println(x));//利用 Arrays 工具類來(lái)獲取流
        String[] strs = {"a","b","c"};
        Arrays.stream(strs).forEach(str-> System.out.println(str));
        //4.零散的數(shù)據(jù)
        Stream.of("a","b","c","d","e").forEach(x-> System.out.println(x));//利用 Stream 來(lái)獲取
    }

2.中間方法

Stream方法中文解釋作用
Stream filter(Predicate<? super T> predicate)篩選過(guò)濾出符合條件的元素
Stream limit(long maxSize)限制截取前maxSize個(gè)元素
Stream skip(long n)跳過(guò)跳過(guò)前n個(gè)元素
Stream distinct()去重去除重復(fù)的元素(根據(jù)hashCode和equals方法)
static Stream concat(Stream a, Stream b)合并將兩個(gè)Stream合并為一個(gè)
Stream map(Function<T, R> mapper)映射將每個(gè)元素轉(zhuǎn)換為另一種類型或形式

注意1:每個(gè)中間方法都是返回新的Stream流,原來(lái)的Stream流只能使用一次,建議使用鏈?zhǔn)骄幊獭?/p>

注意2:修改Stream流中的數(shù)據(jù),不會(huì)影響原來(lái)集合或者數(shù)組中的數(shù)據(jù)。

  • filter
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("陳大帥");
        list.add("陳小帥");
        list.add("小紅");
        list.add("李四");
        list.add("陳四");
        //篩選姓陳的,并且名字是3個(gè)字的人
        list.stream().filter(new Predicate<String>() {
            @Override
            public boolean test(String s) {
                //如果返回值為true,表示當(dāng)前數(shù)據(jù)留下
                //如果返回值為false,表示當(dāng)前數(shù)據(jù)舍棄不要
                return s.startsWith("陳");
            }
        }).forEach(s -> System.out.println(s));//通過(guò)匿名內(nèi)部類
        list.stream().filter(s->s.startsWith("陳")).forEach(s -> System.out.println(s));//通過(guò) lambda
    }

  • limit
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("陳大帥");
        list.add("陳小帥");
        list.add("小紅");
        list.add("李四");
        list.add("陳四");
        //截取前 3 個(gè)數(shù)據(jù)
        list.stream().limit(3).forEach(s -> System.out.println(s));
    }

  • skip
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("陳大帥");
        list.add("陳小帥");
        list.add("小紅");
        list.add("李四");
        list.add("陳四");
        //跳過(guò)前 3 個(gè)數(shù)據(jù)
        list.stream().skip(3).forEach(s -> System.out.println(s));
    }

  • distinct
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("陳大帥");
        list.add("陳大帥");
        list.add("陳大帥");
        list.add("陳大帥");
        list.add("陳小帥");
        list.add("陳小帥");
        list.add("陳小帥");
        list.add("陳小帥");
        list.add("小紅");
        list.add("李四");
        list.add("陳四");
        //去重
        list.stream().distinct().forEach(s -> System.out.println(s));
    }

  • concat
public static void main(String[] args) {
    List<String> list = new ArrayList<>();
    list.add("陳大帥");
    list.add("陳小帥");
    list.add("小紅");
    list.add("李四");
    list.add("陳四");
    List<String> list2 = new ArrayList<>();
    list2.add("a");
    list2.add("b");
    list2.add("c");
    //合并,如果類型不相同,類型就會(huì)變?yōu)楣餐母割?
    Stream.concat(list.stream(),list2.stream()).forEach(s -> System.out.println(s));
}

  • 將每個(gè)元素轉(zhuǎn)換為另一種類型或形式
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("陳大帥-20");
        list.add("陳小帥-19");
        list.add("小紅-11");
        list.add("李四-12");
        list.add("陳四-13");
        list.stream().map(new Function<String, Integer>() {
            //第一個(gè)類型:流中原本的數(shù)據(jù)類型
            // 第二個(gè)類型:要轉(zhuǎn)成之后的類型
            @Override
            public Integer apply(String s) {
                //apply的形參s:依次表示流里面的每一個(gè)數(shù)據(jù)
                //返回值:表示轉(zhuǎn)換之后的數(shù)據(jù)
                String[] split = s.split("-");
                int age = Integer.parseInt(split[1]);
                return age;
            }
        }).forEach(age-> System.out.println(age));//內(nèi)部類
        list.stream().map(s->Integer.parseInt(s.split("-")[1])).forEach(age-> System.out.println(age));//lambda
    }

3.終結(jié)方法

Stream方法中文解釋作用
void forEach(Consumer action)遍歷對(duì)每個(gè)元素執(zhí)行指定的操作
long count()統(tǒng)計(jì)返回元素的個(gè)數(shù)
toArray()收集到數(shù)組返回一個(gè)包含所有元素的數(shù)組
collect(Collector collector)收集到集合返回一個(gè)包含所有元素的集合,可以指定集合的類型和特性
  • forEach
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("陳大帥-20");
        list.add("陳小帥-19");
        list.add("小紅-11");
        list.add("李四-12");
        list.add("陳四-13");
        // consumer的泛型:表示流中數(shù)據(jù)的類型
        list.stream().forEach(new Consumer<String>() {
            //accept方法的形參s:依次表示流里面的每一個(gè)數(shù)據(jù)
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        });
        list.stream().forEach(s -> System.out.println(s));//lambda
    }
  • count
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("陳大帥-20");
        list.add("陳小帥-19");
        list.add("小紅-11");
        list.add("李四-12");
        list.add("陳四-13");
        //統(tǒng)計(jì)集合中的個(gè)數(shù)
        long count = list.stream().count();
        System.out.println(count);
    }

  • toArray
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("陳大帥-20");
        list.add("陳小帥-19");
        list.add("小紅-11");
        list.add("李四-12");
        list.add("陳四-13");
        //方式一:
        //收集集合中的數(shù)據(jù)到數(shù)組
        Object[] array = list.stream().toArray();
        System.out.println(Arrays.toString(array));
        //方式二:指定對(duì)于類型
        //IntFunction的泛型:具體類型的數(shù)組
        //toArray方法的參數(shù):負(fù)責(zé)創(chuàng)建一個(gè)指定類型的數(shù)組
        //toArray方法的底層:會(huì)依次得到流里面的每一個(gè)數(shù)據(jù),并把數(shù)據(jù)放到數(shù)組當(dāng)中
        String[] strings = list.stream().toArray(new IntFunction<String[]>() {
            /**
             *
             * @param value 流中數(shù)據(jù)的個(gè)數(shù),要跟數(shù)組長(zhǎng)度保持一致
             * @return 具體類型的數(shù)組
             */
            @Override
            public String[] apply(int value) {
                return new String[value];
            }
        });
        System.out.println(Arrays.toString(strings));
        //方式三:使用 lambda 表達(dá)式
        String[] array1 = list.stream().toArray(value -> new String[value]);//lambda
        System.out.println(Arrays.toString(array1));
    }

  • collect

收集到List、Set中:

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("陳大帥");
        list.add("陳大帥");
        list.add("陳大帥");
        list.add("陳小帥");
        list.add("陳小帥");
        list.add("陳小帥");
        list.add("小紅");
        list.add("李四");
        list.add("陳四");
        //收集到list中
        List<String> newList = list.stream().filter(s->s.startsWith("陳")).collect(Collectors.toList());
        System.out.println(newList);
        //收集到Set中,自動(dòng)去重
        Set<String> set = list.stream().filter(s -> s.startsWith("陳")).collect(Collectors.toSet());
        System.out.println(set);
    }

收集到Map中:

    public static void main(String[] args) {
        List<String> list2 = new ArrayList<>();
        list2.add("陳大帥-20");
        list2.add("陳小帥-12");
        list2.add("小紅-15");
        list2.add("李四-15");
        list2.add("陳四-38");
        //收集到Map中,鍵:姓名 值:年齡,注意:收集到Map中的時(shí)候,流中數(shù)據(jù) key 不能重復(fù)
        Map<String,Integer> map = list2.stream()
                .filter(s->s.startsWith("陳"))
                /**
                 * toMap:參數(shù)一表示鍵的生成規(guī)則
                 *        參數(shù)二表示值的生成規(guī)則
                 * 參數(shù)一:
                 *      Function 泛型一:表示流中數(shù)據(jù)類型
                 *               泛型二:表示Map集合中key的數(shù)據(jù)類型
                 *      方法 apply 形參:依次表示流里面的每一個(gè)數(shù)據(jù)
                 *                返回值: Map 的 key
                 * 參數(shù)二:
                 *      Function 泛型一:表示流中數(shù)據(jù)類型
                 *               泛型二:表示Map集合中value的數(shù)據(jù)類型
                 *      方法 apply 形參:依次表示流里面的每一個(gè)數(shù)據(jù)
                 *                返回值:Map 的 value
                 */
                .collect(Collectors.toMap(new Function<String, String>() {
                    @Override
                    public String apply(String s) {
                         return s.split("-")[0];
                    }
                }, new Function<String, Integer>() {
                    @Override
                    public Integer apply(String s) {
                        return Integer.parseInt(s.split("-")[1]);
                    }
                }));
        System.out.println(map);
        //使用 lambda 表達(dá)式
        Map<String,Integer> map2 =
                list2.stream()
                .filter(s->s.startsWith("陳"))
                .collect(Collectors.toMap(s->s.split("-")[0],s->Integer.parseInt(s.split("-")[1])));
        System.out.println(map2);
    }

結(jié)果:

如果流中有重復(fù)的key,集合到Map時(shí)會(huì)報(bào)錯(cuò),這跟集合到List不一樣。

    public static void main(String[] args) {
        List<String> list2 = new ArrayList<>();
        list2.add("陳大帥-20");
        list2.add("陳大帥-21");
        list2.add("陳小帥-12");
        list2.add("小紅-15");
        list2.add("李四-15");
        list2.add("陳四-38");
        //使用 lambda 表達(dá)式
        Map<String,Integer> map2 =
                list2.stream()
                .filter(s->s.startsWith("陳"))
                .collect(Collectors.toMap(s->s.split("-")[0],s->Integer.parseInt(s.split("-")[1])));
        System.out.println(map2);
    }

結(jié)果:

以上就是詳解Java中Stream流的用法和原理的詳細(xì)內(nèi)容,更多關(guān)于Java Stream流的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 深入學(xué)習(xí)spring cloud gateway 限流熔斷

    深入學(xué)習(xí)spring cloud gateway 限流熔斷

    這篇文章主要介紹了深入學(xué)習(xí)spring cloud gateway 限流熔斷,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • 使用mybatis 實(shí)現(xiàn)量表關(guān)聯(lián)并且統(tǒng)計(jì)數(shù)據(jù)量的步驟和代碼

    使用mybatis 實(shí)現(xiàn)量表關(guān)聯(lián)并且統(tǒng)計(jì)數(shù)據(jù)量的步驟和代碼

    本文介紹了使用SpringBoot+MyBatis+EasyExcel技術(shù)棧實(shí)現(xiàn)數(shù)據(jù)庫(kù)查詢結(jié)果導(dǎo)出為Excel文件的步驟,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2025-10-10
  • SpringBoot整合JSP的實(shí)現(xiàn)示例

    SpringBoot整合JSP的實(shí)現(xiàn)示例

    JSP是一種動(dòng)態(tài)網(wǎng)頁(yè)技術(shù),允許開(kāi)發(fā)者在 HTML中嵌入Java代碼,將 Spring Boot與JSP 合,可以創(chuàng)建具有傳統(tǒng)服務(wù)器端渲染能力的現(xiàn)代 Web 應(yīng)用,下面就來(lái)詳細(xì)的介紹一下,感興趣的可以了解一下
    2025-12-12
  • Spring Bean的線程安全問(wèn)題

    Spring Bean的線程安全問(wèn)題

    Spring容器中的Bean是否線程安全,本文主要介紹了Spring Bean的線程安全問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • SpringBoot+Mybatis使用Enum枚舉類型總是報(bào)錯(cuò)No enum constant XX問(wèn)題

    SpringBoot+Mybatis使用Enum枚舉類型總是報(bào)錯(cuò)No enum constant&n

    這篇文章主要介紹了SpringBoot+Mybatis使用Enum枚舉類型總是報(bào)錯(cuò)No enum constant XX問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • JavaSwing FlowLayout 流式布局的實(shí)現(xiàn)

    JavaSwing FlowLayout 流式布局的實(shí)現(xiàn)

    這篇文章主要介紹了JavaSwing FlowLayout 流式布局的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • spring boot 配置HTTPS代碼實(shí)例

    spring boot 配置HTTPS代碼實(shí)例

    這篇文章主要介紹了spring boot 配置HTTPS代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11
  • Spring Boot 中的 CommandLineRunner 原理及使用示例解析

    Spring Boot 中的 CommandLineRunner 原理及使用示例

    CommandLineRunner 是 Spring Boot 提供的一個(gè)非常有用的接口,可以幫助你在應(yīng)用程序啟動(dòng)后執(zhí)行初始化任務(wù),本文通過(guò)多個(gè)示例詳細(xì)介紹了如何在實(shí)際項(xiàng)目中使用 CommandLineRunner,感興趣的朋友一起看看吧
    2025-04-04
  • Java實(shí)現(xiàn)上傳網(wǎng)絡(luò)圖片到七牛云存儲(chǔ)詳解

    Java實(shí)現(xiàn)上傳網(wǎng)絡(luò)圖片到七牛云存儲(chǔ)詳解

    這篇文章主要為大家詳細(xì)介紹了Java如何實(shí)現(xiàn)上傳網(wǎng)絡(luò)圖片到七牛云存儲(chǔ),文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2022-12-12
  • java JSONArray 遍歷方式(2種)

    java JSONArray 遍歷方式(2種)

    這篇文章主要介紹了java JSONArray 遍歷方式(2種),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12

最新評(píng)論

陕西省| 察雅县| 包头市| 凉城县| 陵水| 双桥区| 宁城县| 米易县| 尼勒克县| 东安县| 保山市| 库尔勒市| 南康市| 盐城市| 沂源县| 大方县| 广灵县| 利辛县| 随州市| 巴里| 凤山县| 乌审旗| 怀仁县| 宝清县| 安达市| 木兰县| 蛟河市| 顺平县| 图木舒克市| 双流县| 濮阳市| 石首市| 霍邱县| 高平市| 融水| 泾阳县| 和平县| 南投县| 博客| 岳池县| 星子县|