Java Stream流式编程

Stream流式编程

不可变集合

  • 什么是不可变集合

是一个长度不可变,内容也无法修改的集合

  • 使用场景

​ 如果某个数据不能被修改,把它防御性地拷贝到不可变集合中是个很好的实践。

​ 当集合对象被不可信的库调用时,不可变形式是安全的。

如:斗地主的54张牌,是不能添加,不能删除,不能修改的

  • 不可变集合分类
  1. 不可变的list集合

    public static void main(String[] args) {
            //创建不可变的List集合, "张三", "李四", "王二", "麻子"
            //一旦创建完毕之后,是无法进行修改的,在下面的代码中,只能进行查询操作
            List<String> list = List.of("张三", "李四", "王二", "麻子");
    }
    
  2. 不可变的set集合

     public static void main(String[] args) {
           
            //创建不可变的Set集合,"张三", "李四", "王二", "麻子"  
            //注:当我们要获取一个不可变的Set集合时,里面的参数一定要保证唯一性
            //一旦创建完毕之后,是无法进行修改的,在下面的代码中,只能进行查询操作
            Set<String> set = Set.of("张三","张三", "李四", "王二", "麻子"
    
  3. 不可变的map集合

    键值对个数小于等于10

 public static void main(String[] args) {
       /*
        创建Map的不可变集合
            细节1:
                键是不能重复的
            细节2:
                Map里面的of方法,参数是有上限的,最多只能传递20个参数,10个键值对
            细节3:
                如果我们要传递多个键值对对象,数量大于10个,在Map接口中还有一个方法
        */
        //一旦创建完毕之后,是无法进行修改的,在下面的代码中,只能进行查询操作
        Map<String, String> map = Map.of("张三", "南京", "张三", "北京", "王五", "上海",
                "赵六", "广州", "孙七", "深圳", "周八", "杭州",
                "吴九", "宁波", "郑十", "苏州", "刘一", "无锡",
                "陈二", "嘉兴");

        Set<String> keys = map.keySet();
        for (String key : keys) {
            String value = map.get(key);
            System.out.println(key + "=" + value);
        }

        System.out.println("--------------------------");

        Set<Map.Entry<String, String>> entries = map.entrySet();
        for (Map.Entry<String, String> entry : entries) {
            String key = entry.getKey();
            String value = entry.getValue();
            System.out.println(key + "=" + value);
        }
        System.out.println("--------------------------");
    }

键值对个数大于10

public static void main(String[] args) {

        /*
            创建Map的不可变集合,键值对的数量超过10个
        */

        //1.创建一个普通的Map集合
        HashMap<String, String> hm = new HashMap<>();
        hm.put("张三", "南京");
        hm.put("李四", "北京");
        hm.put("王五", "上海");
        hm.put("赵六", "北京");
        hm.put("孙七", "深圳");
        hm.put("周八", "杭州");
        hm.put("吴九", "宁波");
        hm.put("郑十", "苏州");
        hm.put("刘一", "无锡");
        hm.put("陈二", "嘉兴");
        hm.put("aaa", "111");

        //2.利用上面的数据来获取一个不可变的集合
/*
        //获取到所有的键值对对象(Entry对象)
        Set<Map.Entry<String, String>> entries = hm.entrySet();
        //把entries变成一个数组
        Map.Entry[] arr1 = new Map.Entry[0];
        //toArray方法在底层会比较集合的长度跟数组的长度两者的大小
        //如果集合的长度 > 数组的长度 :数据在数组中放不下,此时会根据实际数据的个数,重新创建数组
        //如果集合的长度 <= 数组的长度:数据在数组中放的下,此时不会创建新的数组,而是直接用
        Map.Entry[] arr2 = entries.toArray(arr1);
        //不可变的map集合
        Map map = Map.ofEntries(arr2);
        map.put("bbb","222");*/


        //Map<Object, Object> map = Map.ofEntries(hm.entrySet().toArray(new Map.Entry[0]));

        Map<String, String> map = Map.copyOf(hm);
        map.put("bbb","222");
    }

Stream流

Stream流的优点
  • 直接阅读代码的字面意思即可完美展示无关逻辑方式的语义:获取流、过滤数据、逐一打印
  • Stream流把真正的函数式编程风格引入到Java中
  • 代码简洁
Stream流的常见生成方式
Stream流的三类方法
  • 获取Stream流

    • 创建一条流水线,并把数据放到流水线上准备进行操作
  • 中间方法

    • 流水线上的操作
    • 一次操作完毕之后,还可以继续进行其他操作
  • 终结方法

    • 一个Stream流只能有一个终结方法

    • 是流水线上的最后一个操作

生成Stream流的方式
  • Collection体系集合

    使用默认方法stream()生成流, default Stream stream()

    public class CollectionStreamDemo {
        public static void main(String[] args) {
            //Collection的集合可以使用默认方法stream()生成流
            //List生成流
            List<String> list = new ArrayList<>();
            Stream<String> listStream = list.stream();
            //Set生成流
            Set<String> set = new HashSet<>();
            Stream<String> setStream = set.stream();
        }
    }
    
  • Map体系集合

    把Map转成Set集合,间接的生成流

    public class MapStreamDemo {
        public static void main(String[] args) {
            //Map体系的集合间接的生成流
            Map<String,String> map = new HashMap<>();
            Stream<String> keyStream = map.keySet().stream();
            Stream<String> valuesStream = map.values().stream();
            Stream<Map.Entry<String, String>> entryStream = map.entrySet().stream();
    
        }
    }
    
  • 数组

    通过Arrays中的静态方法stream生成流

    public class ArrayStreamDemo {
        public static void main(String[] args) {
            //数组可以通过Arrays中的静态方法stream生成流
            int[] array1 = {1,2,3,4,5,6};
            IntStream intStream = Arrays.stream(array1);
            String[] array2 = {"a","b","c","d"};
            Stream<String> stringStream = Arrays.stream(array2);
        }
    }
    
  • 同种数据类型的多个数据

    通过Stream接口的静态方法of(T… values)生成流

public class OtherStreamDemo {
    public static void main(String[] args) {
        //同种数据类型的多个数据可以通过Stream接口的静态方法of(T... values)生成流
        Stream<String> Stream1 = Stream.of("hello", "world", "java");
        Stream<Integer> Stream2 = Stream.of(10, 20, 30);
    }
}
Stream流中间操作方法

中间操作的意思是,执行完此方法之后,Stream流依然可以继续执行其他操作

  • 常见方法
方法名说明
Stream filter(Predicate predicate)用于对流中的数据进行过滤(过滤)
Stream limit(long maxSize)返回此流中的元素组成的流,截取前指定参数个数的数据(截取)
Stream skip(long n)跳过指定参数个数的数据,返回由该流的剩余元素组成的流(跳过)
static Stream concat(Stream a, Stream b)合并a和b两个流为一个流(合流)
Stream distinct()返回由该流的不同元素(根据Object.equals(Object) )组成的流(去重)
  • filter代码演示
public class StreamFilterDemo {
    public static void main(String[] args) {
        //创建集合list
        List<String> list = new ArrayList<>();
        //往集合添加数据
        Collections.addAll(list,"张三","李四","王二","麻子","李太白","张三丰","李白");
        //过滤姓李的
        list.stream().filter(new Predicate<String>() {
            @Override               // s表示流中的每一个数据
            public boolean test(String s) {
                //      若为true,当前数据保留,若为false当前数据不予保留
                boolean result = s.startsWith("李");
                return result;
            }   //  遍历过滤后的数据   得到结果  李四 李太白 李白
        }).forEach(s -> System.out.println(s));
        //因为Predicate接口中只有一个抽象方法test,所以我们可以使用lambda表达式来简化
        System.out.println("========================================");
        //lambda表达式如下
        list.stream().filter(s -> s.startsWith("李")).forEach(s -> System.out.println(s));
    }
}
  • limit&skip代码演示
public class StreamLimitAndSkipDemo {
    public static void main(String[] args) {
        //创建集合
        ArrayList<String> list = new ArrayList<>();
        //在集合中批量存储数据
        Collections.addAll(list,"张三","李四","王二","麻子","李太白","张三丰","李白");
        //limit(2)截取集合中前两个数据          输出结果为: 张三 李四  
        list.stream().limit(2).forEach(s -> System.out.println(s));
        System.out.println("===================================");
        //skip(4)跳过前四个数据输出            输出结果为: 李太白 张三丰 李白
        list.stream().skip(4).forEach(s -> System.out.println(s));
        System.out.println("===================================");
        //截取前5个且在此结果集中跳过前三个              输出结果为: 麻子 李太白
        list.stream().limit(5).skip(3).forEach(s -> System.out.println(s));
    }
}
  • concat&distinct代码演示
public class StreamConcatAndDistinctDemo {
    public static void main(String[] args) {
        //创建集合
        ArrayList<String> list = new ArrayList<>();
        //在集合中批量存储数据
        Collections.addAll(list, "张三", "李四", "王二", "麻子", "李太白", "张三丰", "李白");
        //截取集合前四个元素返回新的流limitStream
        Stream<String> limitStream = list.stream().limit(4);
        //跳过集合前两个元素返回新的流skipStream
        Stream<String> skipStream = list.stream().skip(2);
        //合并流做遍历操作,遍历结果:张三 李四 王二 麻子 王二 麻子 李太白 张三丰 李白
        //流只能使用一次,下方需要测试distinct(去重),因此注释掉这行代码
        //Stream.concat(limitStream, skipStream).forEach(s -> System.out.println(s));
        
        //合并流去重后做遍历操作,遍历结果:张三 李四 王二 麻子 李太白 张三丰 李白
        Stream.concat(limitStream,skipStream).distinct().forEach(s -> System.out.println(s));
    }
}
Stream流终结操作方法

终结操作的意思是,执行完此方法之后,Stream流将不能再执行其他操作

  • 常见方法
方法名说明
void forEach(Consumer action)对此流的每个元素执行操作
long count()返回此流中的元素数
  • 代码演示
public class StreamForEachAndCountDemo {
    public static void main(String[] args) {
        //创建集合
        ArrayList<String> list = new ArrayList<>();
        //在集合中批量存储数据
        Collections.addAll(list,"张三","李四","王二","麻子","李太白","张三丰","李白");
        //调用count()返回集合中元素个数
        long count = list.stream().count();
        //输出count值  输出结果为:7
        System.out.println(count);
        System.out.println("=========================");
        //在forEach方法的底层,会循环获取到流中的每一个数据.
        //并循环调用accept方法,并把每一个数据传递给accept方法
        //s就依次表示了流中的每一个数据.
        //所以,我们只要在accept方法中,写上处理的业务逻辑就可以了.
        list.stream().forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        });
        System.out.println("=========================");
        //因为Consumer接口中,只有一个accept方法,可以使用lambda表达式的简化格式
        list.stream().forEach(s -> System.out.println(s));
    }
}
Stream流的收集操作

对数据使用Stream流的方式操作完毕后,可以把流中的数据收集到集合中

  • 常用方法
方法名说明
R collect(Collector collector)把结果收集到集合中
  • 工具类Collectors提供了具体的收集方式
方法名说明
public static Collector toList()把元素收集到List集合中
public static Collector toSet()把元素收集到Set集合中
public static Collector toMap(Function keyMapper,Function valueMapper)把元素收集到Map集合中
  • 代码演示
public class StreamCollectDemo {
    public static void main(String[] args) {
        // toList和toSet方法演示
        ArrayList<Integer> list1 = new ArrayList<>();
        for (int i =1;i<=10;i++){
            list1.add(i);
        }
        Collections.addAll(list1,10,10,10,10);
        //filter负责过滤数据的.
        //collect负责收集数据.
        //获取流中剩余的数据,但是他不负责创建容器,也不负责把数据添加到容器中.
        //Collectors.toList() : 在底层会创建一个List集合.并把所有的数据添加到List集合中.
        List<Integer> collect = list1.stream().filter(s->s%2==0).collect(Collectors.toList());
        System.out.println(collect); //[2, 4, 6, 8, 10, 10, 10, 10, 10]
        System.out.println("==============================");
        Set<Integer> collect1 = list1.stream().filter(s->s%2==0).collect(Collectors.toSet());
        System.out.println(collect1); //[2, 4, 6, 8, 10]

        // toMap方法演示
        ArrayList<String> list2 = new ArrayList<>();
        list2.add("zhangsan,23");
        list2.add("lisi,24");
        list2.add("wangwu,25");

        System.out.println("==============================");
        //保留年龄大于等于24岁的人,并将结果收集到Map集合中,姓名为键,年龄为值
        Map<String, Integer> map = list2.stream()
                //过滤年龄大于等于24岁的人
                .filter(s -> Integer.parseInt(s.split(",")[1]) >= 24)
                .collect(Collectors.toMap(
                    //第一个lambda表达式就是如何获取到Map中的键
                    //第二个lambda表达式就是如何获取Map中的值
                    s -> s.split(",")[0],
                    s -> Integer.parseInt(s.split(",")[1])));
        System.out.println(map);//{lisi=24, wangwu=25}
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值