欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

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

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

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

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

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

(List.of在jdk8中沒有,需要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("------------------------------");
}

  • 這些集合不能添加,不能刪除,不能修改,如果修改會拋異常:
    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 個鍵值對,源碼里of()方法參數(shù)最多的也就10對。

那為什么不用可變參數(shù)呢?因為可變參數(shù)只能有一個,并且要在參數(shù)列表的末尾。如果想要存超過10個的鍵值對,我們可以利用數(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");
        //獲取所有的鍵值對
        Set<Map.Entry<Integer,String>> entries = map.entrySet();
        //把entries變成一個數(shù)組
        //如果集合的長度 〉數(shù)組的長度﹔數(shù)據(jù)在數(shù)組中放不下,此時會根據(jù)實際數(shù)據(jù)的個數(shù),重新創(chuàng)建數(shù)組
        //如果集合的長度〈=數(shù)組的長度:數(shù)據(jù)在數(shù)組中放的下,此時不會創(chuàng)建新的數(shù)組,而是直接用原來的數(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)建之后就不再變更的對象,這種特性使得它們天生支持線程安全。
  • 防止數(shù)據(jù)被篡改:不可變集合可以用于封裝一些敏感或重要的數(shù)據(jù),防止它們被外部程序或不可信的庫修改或破壞。

二、Stream 流

(一)Stream 的思想

Stream 為什么叫流?可以通過下面的案例來引入這個概念。

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

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

(二)Stream流的使用步驟

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

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

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

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

獲取方式方法名說明
單列集合default Stream stream()collection中的默認(rèn)方法(由于單列集合實現(xiàn)了Collection接口,可以直接.stream())
雙列集合(Map等)無法直接使用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)系來操作整體
        map.entrySet().stream().forEach(entry-> System.out.println(entry));//方式2:獲取鍵值對的流水線
        //3.數(shù)組
        int[] arr = {1,2,3,4,5,6,7,8};
        Arrays.stream(arr).forEach(x-> System.out.println(x));//利用 Arrays 工具類來獲取流
        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 來獲取
    }

2.中間方法

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

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

注意2:修改Stream流中的數(shù)據(jù),不會影響原來集合或者數(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個字的人
        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));//通過匿名內(nèi)部類
        list.stream().filter(s->s.startsWith("陳")).forEach(s -> System.out.println(s));//通過 lambda
    }

  • limit
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("陳大帥");
        list.add("陳小帥");
        list.add("小紅");
        list.add("李四");
        list.add("陳四");
        //截取前 3 個數(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("陳四");
        //跳過前 3 個數(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");
    //合并,如果類型不相同,類型就會變?yōu)楣餐母割?
    Stream.concat(list.stream(),list2.stream()).forEach(s -> System.out.println(s));
}

  • 將每個元素轉(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>() {
            //第一個類型:流中原本的數(shù)據(jù)類型
            // 第二個類型:要轉(zhuǎn)成之后的類型
            @Override
            public Integer apply(String s) {
                //apply的形參s:依次表示流里面的每一個數(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)遍歷對每個元素執(zhí)行指定的操作
long count()統(tǒng)計返回元素的個數(shù)
toArray()收集到數(shù)組返回一個包含所有元素的數(shù)組
collect(Collector collector)收集到集合返回一個包含所有元素的集合,可以指定集合的類型和特性
  • 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:依次表示流里面的每一個數(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)計集合中的個數(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));
        //方式二:指定對于類型
        //IntFunction的泛型:具體類型的數(shù)組
        //toArray方法的參數(shù):負(fù)責(zé)創(chuàng)建一個指定類型的數(shù)組
        //toArray方法的底層:會依次得到流里面的每一個數(shù)據(jù),并把數(shù)據(jù)放到數(shù)組當(dāng)中
        String[] strings = list.stream().toArray(new IntFunction<String[]>() {
            /**
             *
             * @param value 流中數(shù)據(jù)的個數(shù),要跟數(shù)組長度保持一致
             * @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中,自動去重
        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ù)據(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 形參:依次表示流里面的每一個數(shù)據(jù)
                 *                返回值: Map 的 key
                 * 參數(shù)二:
                 *      Function 泛型一:表示流中數(shù)據(jù)類型
                 *               泛型二:表示Map集合中value的數(shù)據(jù)類型
                 *      方法 apply 形參:依次表示流里面的每一個數(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時會報錯,這跟集合到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流的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java WeakHashMap案例詳解

    Java WeakHashMap案例詳解

    這篇文章主要介紹了Java WeakHashMap案例詳解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • Java數(shù)據(jù)結(jié)構(gòu)學(xué)習(xí)之樹

    Java數(shù)據(jù)結(jié)構(gòu)學(xué)習(xí)之樹

    這篇文章主要介紹了Java數(shù)據(jù)結(jié)構(gòu)學(xué)習(xí)之樹,文中有非常詳細(xì)的代碼示例,對正在學(xué)習(xí)java數(shù)據(jù)結(jié)構(gòu)的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-05-05
  • java向上轉(zhuǎn)型發(fā)生的時機(jī)知識點(diǎn)詳解

    java向上轉(zhuǎn)型發(fā)生的時機(jī)知識點(diǎn)詳解

    在本篇文章里小編給大家整理分享的是關(guān)于java向上轉(zhuǎn)型發(fā)生的時機(jī)知識點(diǎn)內(nèi)容,有興趣的讀者們可以參考下。
    2021-05-05
  • Springsession nginx反向代理集成過程

    Springsession nginx反向代理集成過程

    這篇文章主要介紹了Springsession nginx反向代理集成過程,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-04-04
  • springboot項目同時啟動web服務(wù)和grpc服務(wù)的方法

    springboot項目同時啟動web服務(wù)和grpc服務(wù)的方法

    本文主要介紹了springboot項目同時啟動web服務(wù)和grpc服務(wù)的方法,通過實際代碼示例展示了實現(xiàn),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-02-02
  • SpringBoot接收參數(shù)使用的注解實例講解

    SpringBoot接收參數(shù)使用的注解實例講解

    這篇文章主要介紹了詳解SpringBoot接收參數(shù)使用的幾種常用注解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • 如何使用Java調(diào)用Spark集群

    如何使用Java調(diào)用Spark集群

    這篇文章主要介紹了如何使用Java調(diào)用Spark集群,我搭建的Spark集群的版本是2.4.4,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2024-02-02
  • Maven在Windows中的配置以及IDE中的項目創(chuàng)建(圖文教程)

    Maven在Windows中的配置以及IDE中的項目創(chuàng)建(圖文教程)

    這篇文章主要介紹了Maven在Windows中的配置以及IDE中的項目創(chuàng)建(圖文教程),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-09-09
  • SpringCloud-Alibaba-Sentinel-配置持久化策略詳解

    SpringCloud-Alibaba-Sentinel-配置持久化策略詳解

    這篇文章主要介紹了SpringCloud-Alibaba-Sentinel-配置持久化策略,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-03-03
  • 解決Idea報錯There is not enough memory to perform the requested operation問題

    解決Idea報錯There is not enough memory 

    在使用Idea開發(fā)過程中,可能會遇到因內(nèi)存不足導(dǎo)致的閃退問題,出現(xiàn)"There is not enough memory to perform the requested operation"錯誤時,可以通過調(diào)整Idea的虛擬機(jī)選項來解決,方法是在Idea的Help菜單中選擇Edit Custom VM Options
    2024-11-11

最新評論