10.不可变集合与stream流(下篇)

  • 目录

    1.不可变集合

    2.不可变集合的分类

    3. Stream流

    4. Stream流的操作方法

    5.方法引用

  • 1.不可变集合

    • 1.1不可变集合定义
      • 是一个长度不可变,内容也无法修改的集合
    • 1.2使用场景
      • 如果某个数据不能被修改,把它防御性地拷贝到不可变集合中是个很好的实践。
      • 当集合对象被不可信的库调用时,不可变形式是安全的。
      • 简单理解:不想让别人修改集合中的内容
      • 比如说:
      • 1,斗地主的54张牌,是不能添加,不能删除,不能修改的
      • 2,斗地主的打牌规则:单张,对子,三张,顺子等,也是不能修改的
      • 3,用代码获取的操作系统硬件信息,也是不能被修改的
  • 2.不可变集合的分类

    • 2.1不可变的list集合
      List<String> list = List.of("张三", "李四", "王五", "赵六"); //只能进行查询操作
    • 2.2不可变的set集合
      Set<String> set = Set.of("张三", "张三", "李四", "王五", "赵六"); //参数一定要保证唯一性且只能进行查询操作
    • 2.3不可变的map集合
      Map<String, String> map = Map.of()
      • 细节1:键是不能重复的
      • 细节2:Map里面的of方法,参数是有上限的,最多只能传递20个参数,10个键值对
      • 细节3:如果我们要传递多个键值对对象,数量大于10个,在Map接口中还有一个方法:
        Map map = Map.ofEntries(arr2);
        • 步骤1:创建一个普通的Map集合
          HashMap<String, String> hm = new HashMap<>();
        • 步骤2:
          • 1.获取到所有的键值对对象(Entry对象)
            Set<Map.Entry<String, String>> entries = hm.entrySet();
          • 2.把entries变成一个数组
            Map.Entry[] arr1 = new Map.Entry[0];
          • 3.toArray方法在底层会比较集合的长度跟数组的长度两者的大小
            Map.Entry[] arr2 = entries.toArray(arr1);
            • 集合的长度 > 数组的长度 :数据在数组中放不下,此时会根据实际数据的个数,重新创建数组
            • 集合的长度 <= 数组的长度:数据在数组中放的下,此时不会创建新的数组,而是直接用
          • 4.不可变的map集合
            Map map = Map.ofEntries(arr2);
        • 简写:Map<Object, Object> map = Map.ofEntries(hm.entrySet().toArray(new Map.Entry[0]));
        • 简写Plus:Map<String, String> map = Map.copyOf(hm);
          注意:此方法是在JDK10才出现
  • 3. Stream流

    • 3.1Stream流的思想

    • 3.2Stream流的三类方法
      • 获取Stream流
        例如:List<String> list = new ArrayList<String>();
        • 创建一条流水线,并把数据放到流水线上准备进行操作
      • 中间方法
        • 流水线上的操作
        • 一次操作完毕之后,还可以继续进行其他操作
      • 终结方法
        • 一个Stream流只能有一个终结方法
        • 是流水线上的最后一个操作
    • 3.3生成Stream流的方式
      • Collection体系集合:使用默认方法stream()生成流, default Stream<E> stream()
        • List<String> list = new ArrayList<String>();
        • Stream<String> listStream = list.stream();
      • Map体系集合:把Map转成Set集合,间接的生成流
        • 方式一:
          • Map<String,Integer> map = new HashMap<String, Integer>();
          • Stream<String> keyStream = map.keySet().stream();
          • Stream<Integer> valueStream = map.values().stream();
        • 方式二:
          • Stream<Map.Entry<String, Integer>> entryStream = map.entrySet().stream();
      • 数组:通过Arrays中的静态方法stream生成流
        • String[] strArray = {"hello","world","java"};
        • Stream<String> strArrayStream = Arrays.stream(strArray);
      • 同种数据类型的多个数据:通过Stream接口的静态方法of(T... values)生成流
        • Stream<String> strArrayStream2 = Stream.of("hello", "world", "java");
        • Stream<Integer> intStream = Stream.of(10, 20, 30);
  • 4. Stream流的操作方法

    • 注意:Stream只能使用一次,所以没有必要用变量进行接收(使用链式编程)
    • 4.1中间操作
      概念:中间操作的意思是,执行完此方法之后,Stream流依然可以继续执行其他操作
      • Stream<T> filter(Predicate predicate)
        用于对流中的数据进行过滤,建议使用链式编程
        • new Predicate<String>() {
        • @Override
        • public boolean test(String s) {
        • boolean result = s.startsWith("张");
        • return result;//结果为true,则当前的数据留
        • }
        • }
        • ).forEach(s-> System.out.println(s));
      • Stream<T> limit(long maxSize)
        返回此流中的元素组成的流,截取前指定参数个数的数据
      • Stream<T> skip(long n)
        跳过指定参数个数的数据,返回由该流的剩余元素组成的流
      • Stream<T> distinct()
        返回由该流的不同元素(根据Object.equals(Object) ,所以要重写hashcode和equals)组成的流
      • static <T> Stream<T> concat(Stream a, Stream b)
        合并a和b两个流为一个流,如果a,b类型不同,则合并之后是a与b共同的父类ab(类型的提升,但是会无法使用子类的特有功能)
        • 注意static:直接调用,Stream.concat(list1. stream(),list. stream())
      • Stream<R> map(Function<T,R> mapper)
        转换流中的数据
        T为转换类型,R为目标类型,利用函数式接口Function中的方法public R apply(T var1)
    • 4.2终结操作
      概念:终结操作的意思是,执行完此方法之后,Stream流将不能再执行其他操作
      • void forEach(Consumer action)
        对此流的每个元素执行操作,接口中是accept方法
      • long count()
        返回此流中的元素数
    • 4.3收集操作
      概念:对数据使用Stream流的方式操作完毕后,可以把流中的数据收集到集合中
      • 数组:A[] / Object[] toArray( IntFunction<A[]> generator / 空参)
        收集流中的数据,放到数组中
        注意IntFunction<A[]> generator:这里A[]是一个具体类型的数组(例如String类型:new IntFunction<String[]>())
        里面是accept方法:public A[] apply(int value){ return new A[value] } 1.其中A与上相同,2.value是流中数据的个数,要和数组保持一致,3.返回值与上相同
        • 总结:
        • toArray方法的参数:负责创建一个指定类型的数组
        • toArray方法的底层:会一次得到流里面的每一个数据,并把数据放在数组中
        • toArray方法的返回值:是一个装着流里面所有数据的数组
        • 例如:list. stream().toArray(value -> new String[value]);
      • 单列集合:
        • R collect(Collector collector)
          把结果收集到集合中,与其他收集集合进行配合(List,Set,Map)
        • 工具类Collectors提供了具体的收集方式:
        • public static <T> Collector toList()
          把元素收集到List集合中
        • public static <T> Collector toSet()
          把元素收集到Set集合中
        • 例如:List<Integer> list = list1. stream( ).filter( ).collect(Collectors.toList());
      • 双列集合:
        注意:如果我们要收集到Map集合当中,键不能重复,否则会报错
        • public static Collector toMap(Function<K,V> keyMapper,Function<K,V> valueMapper)
          把元素收集到Map集合中
  • 5.方法引用

    • 把已经有的方法拿过来用,当作函数式接口中抽象方法的方法体
      相当于传递的不是实现类或者子类,而是类或者接口中已经存在的方法
    • 5.1方法引用的条件
      • 1.引用处必须是函数式接口
        Arrays.sort(arr , new Comparator<Integer> { });
      • 2.被引用的方法必须已经存在
      • 3.被引用的方法的形参和返回值需要跟抽象方法保持一致
      • 4.被引用方法的功能要满足当前的需求
    • 5.2引用静态方法
      • 格式:类名 : : 静态方法
        Integer : : parseInt
        Integer类的方法:public static int parseInt(String s) 将此String转换为int类型数据
    • 5.3引用成员方法
      • 格式:对象 : : 成员方法
        • ①其他类:其它类对象 : : 方法名
        • ②本类:this : : 方法名
          注意:引用处不能是静态方法
        • ③父类:super : : 方法名
          注意:引用处不能是静态方法
    • 5.4引用构造方法
      • 格式:类名 : : new
      • 注意:Ⅰ.重写抽象方法之后的方法体里面返回值为new 类名(参数1,参数2...) ,则可使用引用方法。Ⅱ.类中的构造方法按照需求进行补充,引用构造方法的时候,对象便已经存在了,所以返回值不需要去管
    • 5.5其他调用方式-类名引用成员方法
      • 格式:类名 : : 成员方法
      • 独有的引用规则:
        • 1.引用处必须是函数式接口
          Arrays.sort(arr , new Comparator<Integer> { });
        • 2.被引用的方法必须已经存在
        • 3.被引用方法的形参,需要跟抽象方法的第二个形参到最后一个形参保持一致,返回值需要保持一致
        • 4.被引用方法的功能要满足当前的需求
      • 抽象方法形参的详解
        • 第一个参数:Ⅰ表示被引用方法的调用者,决定了可以引用哪些类中的方法。Ⅱ在Stream流中,第一个参数一般都表示流里面的每一个数据。Ⅲ假设流里面的数据是字符串,那么使用这种方式进行方法引用,只能引用String这个类中的方法
        • 第二个参数到最后一个参数:跟被引用方法的形参保持一致,如果没有第二个参数,说明被引用的方法需要是无参的成员方法
      • 局限性
        • 不能引用所有类中的成员方法。是跟抽象方法的第一个参数有关,这个参数是什么类型的,那么就只能引用这个类中的方法。
          例如:list. stream().map(String::toUpperCase)
          map中参数的实现类方法:public String apply(String s) { return s.toUpperCase; }
    • 5.6其他调用方式-引用数组的构造方法
      • 格式:数据类型 [] : : new
        int [ ] : : new
        就是为创建数组
      • 注意:数组的类型,需要跟流中数据的类型保持一致
        Integer[] arrr = list. stream().toArray(Integer[] : : new);
    • 5.7方法调用小技巧
      • 1. 现在有没有一个方法符合我当前的需求
      • 2. 如果有这样的方法,这个方法是否满足引用的规则
      • 静态 类名 : : 静态方法
      • 成员方法 类名 : : 成员方法/对象 : : 成员方法
      • 构造方法 类名 : : 成员方法
  • 14
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zd08

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值