目录
一.不可变集合
1.介绍
什么是不可变集合:
是一个长度不可变,内容也无法修改的集合
使用场景:
如果某个数据不能被修改,把它防御性地拷贝到不可变集合中是个很好的实践。
当集合对象被不可信的库调用时,不可变形式是安全的。
简单理解: 不想让别人修改集合中的内容
比如说:斗地主的54张牌,是不能添加,不能删除,不能修改的
斗地主的打牌规则:单张,对子,三张,顺子等,也是不能修改的
用代码获取的操作系统硬件信息,也是不能被修改的
2. 不可变的list集合
public class ImmutableDemo1 { public static void main(String[] args) { /* 创建不可变的List集合 "张三", "李四", "王五", "赵六" */ //一旦创建完毕之后,是无法进行修改的,在下面的代码中,只能进行查询操作 List<String> list = List.of("张三", "李四", "王五", "赵六"); System.out.println(list.get(0)); System.out.println(list.get(1)); System.out.println(list.get(2)); System.out.println(list.get(3)); System.out.println("---------------------------"); for (String s : list) { System.out.println(s); } System.out.println("---------------------------"); Iterator<String> it = list.iterator(); while(it.hasNext()){ String s = it.next(); System.out.println(s); } System.out.println("---------------------------"); for (int i = 0; i < list.size(); i++) { String s = list.get(i); System.out.println(s); } System.out.println("---------------------------"); //list.remove("李四"); //list.add("aaa"); list.set(0,"aaa"); } }
3. 不可变的Set集合
public class ImmutableDemo2 { public static void main(String[] args) { /* 创建不可变的Set集合 "张三", "李四", "王五", "赵六" 细节: 当我们要获取一个不可变的Set集合时,里面的参数一定要保证唯一性 */ //一旦创建完毕之后,是无法进行修改的,在下面的代码中,只能进行查询操作 Set<String> set = Set.of("张三", "张三", "李四", "王五", "赵六"); for (String s : set) { System.out.println(s); } System.out.println("-----------------------"); Iterator<String> it = set.iterator(); while(it.hasNext()){ String s = it.next(); System.out.println(s); } System.out.println("-----------------------"); //set.remove("王五"); } }
4. 不可变的Map集合
键值对个数小于等于10:
public class ImmutableDemo3 { 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 class ImmutableDemo4 { 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.利用上面的数据来获取一个不可变的集合 Map<String, String> map = Map.copyOf(hm); map.put("bbb","222"); } }
二. Stream流
1.体验Stream流【理解】
按照下面的要求完成集合的创建和遍历
创建一个集合,存储多个字符串元素
把集合中所有以"张"开头的元素存储到一个新的集合
把"张"开头的集合中的长度为3的元素存储到一个新的集合
遍历上一步得到的集合
原始方式示例代码:
public class MyStream1 { public static void main(String[] args) { //集合的批量添加 ArrayList<String> list1 = new ArrayList<>(List.of("张三丰","张无忌","张翠山","王二麻子","张良","谢广坤")); //list.add() //遍历list1把以张开头的元素添加到list2中。 ArrayList<String> list2 = new ArrayList<>(); for (String s : list1) { if(s.startsWith("张")){ list2.add(s); } } //遍历list2集合,把其中长度为3的元素,再添加到list3中。 ArrayList<String> list3 = new ArrayList<>(); for (String s : list2) { if(s.length() == 3){ list3.add(s); } } for (String s : list3) { System.out.println(s); } } }使用Stream流示例代码:
public class StreamDemo { public static void main(String[] args) { //集合的批量添加 ArrayList<String> list1 = new ArrayList<>(List.of("张三丰","张无忌","张翠山","王二麻子","张良","谢广坤")); //Stream流 list1.stream().filter(s->s.startsWith("张")) .filter(s->s.length() == 3) .forEach(s-> System.out.println(s)); } }Stream流的好处
直接阅读代码的字面意思即可完美展示无关逻辑方式的语义:获取流、过滤姓张、过滤长度为3、逐一打印
Stream流把真正的函数式编程风格引入到Java中
代码简洁
2.Stream流的思想和获取Stream流
Stream流的思想:
Stream流的三类方法:
获取Stream流
创建一条流水线,并把数据放到流水线上准备进行操作
中间方法
流水线上的操作
一次操作完毕之后,还可以继续进行其他操作
终结方法
一个Stream流只能有一个终结方法
是流水线上的最后一个操作
生成Stream流的方式:
单列集合:
//单列集合 default Stream<E stream() //1、单列集合获取Stream流 ArrayList<String> list = new ArrayList<>(); Collections.addAll(list,"1","2","3","4","5"); //获取到一条流水线,并把集合中的数据放到流水线上使用终结方法打印一下流水线上所有数据 list.stream().forEach(s-> System.out.println(s));双列集合:
//双列集合 //1.创建双列集合 HashMap<String,Integer> hm=new HashMap<>(); //2. 添加数据 hm.put("aaa",11); hm.put("bbb",22); hm.put("ccc",33); hm.put("ddd",44); //3.第一种获取stream流 hm.keySet().stream().forEach(s -> System.out.println(s)); //4.第二种获取stream流 hm.entrySet().stream().forEach(s-> System.out.println(s) );数组:
//数组 public static <T> Stream<T> stream(T[] array) Arrays工具类中的静态方法 //1.创建数组 int[] arr1={1,2,3,4,5,6,7,8,9,10}; String[] arr2= {"a","b","c"}; //2.获取stream流 Arrays.stream(arr1).forEach(s -> System.out.println(s)); System.out.println("----------"); Arrays.stream(arr2).forEach(s -> System.out.println(s)); //注意:Stream接口中静态方法of的细节 //方法的形参是一个可变参数,可以传递一堆零散的数据,也可以传递数组 //但是数组必须是引用数据类型的,如果传递基本数据类型,是会把整个数组当做一个元素,放到stream当中 Stream.of(arr1).forEach(s -> System.out.println(s));零散数据:
//一堆零散数据 public static <T> Stream<T> of(T... values) Streeam接口中的静态方法 Stream.of(1, 2, 3,4,5).forEach(s-> System.out.println(s)); Stream.of("a","b","c").forEach(s-> System.out.println(s));
3.Stream流的中间方法
//注意1:中间方法,返回新的stream流,原来的stream流只能使用一次,建议使用链式编程 //注意2:修改stream流中的数据,不会影响原来集合或者数组中的数据 ArrayList<String> list = new ArrayList<>(); ArrayList<String> list2 = new ArrayList<>(); ArrayList<String> list3 = new ArrayList<>(); Collections.addAll(list,"张无忌","周芷若","赵敏","赵敏","赵敏","张强","张三丰","张小四","张小五"); Collections.addAll(list2,"小王","小李"); Collections.addAll(list3,"小王-23","小李-24"); //filter 过滤 list.stream().filter(s -> s.startsWith("张")) .filter(s -> s.length()==3) .forEach(s -> System.out.println(s)); //limit 获取前几个元素 list.stream().limit(3).forEach(s -> System.out.println(s)); //skip 跳过前几个元素 list.stream().skip(4).forEach(s -> System.out.println(s)); //distinct 元素去重,依赖(hashCode和equals) list.stream().distinct().forEach(s -> System.out.println(s)); //concat 合并a和b两个流为一个流 Stream.concat(list.stream(),list2.stream()).forEach(s -> System.out.println(s)); //map 转换流中的数据类型 //第一个类型:流中原本的数据类型 //第二个类型:要转成之后的类型 //apply的形参s:依次表示流里面的每一个数据 //返回值:表示转换之后的数据 //当map方法执行完毕之后,流上的数据就变成了整数 //所以在下面forEach当中,s依次表示流里面的每一个数据,这个数据现在就是整数了 list3.stream().map(new Function<String, Integer>() { @Override public Integer apply(String s) { String[] arr = s.split("-"); String ageStr = arr[1]; int age=Integer.parseInt(ageStr); return age; }} ).forEach(s -> System.out.println(s)); list3.stream() .map(s -> Integer.parseInt(s.split("-")[1])) .forEach(s -> System.out.println(s));
4.Stream的终结方法
ArrayList<String> list = new ArrayList<>(); Collections.addAll(list,"1","2","3","4","5"); //void forEach(Consumer action) 遍历 list.stream().forEach(s -> System.out.println(s)); //long count() 统计 long num= list.stream().count(); System.out.println( num); //toArray() 收集流中的数据,放到数组中 Object[] arr1=list.stream().toArray(); System.out.println(Arrays.toString(arr1)); //IntFunction的泛型:具体类型的数组 //apply的形参:流中数据的个数,要跟数组的长度保持一致 //apply的返回值:具体类型的数组 //方法体:就是创建数组 //toArray方法的参数的作用:负责创建一个指定类型的数组 //toArray方法的底层,会依次得到流里面的每一个数据,并把数据放到数组当中 // toArray方法的返回值:是一个装着流里面所有数据的数组 String[] arr2=list.stream().toArray(new IntFunction<String[]>() { @Override public String[] apply(int value) { return new String[value]; } }); System.out.println(Arrays.toString(arr2)); String[] arr3=list.stream().toArray(value -> new String[value]); System.out.println(Arrays.toString(arr3));//collect(Collector collector) 收集流中的数据,放到集合中 //注意点:如果我们要收集到Map集合中,键不能重复,否则会报错 ArrayList<String> list = new ArrayList<>(); Collections.addAll(list, "张无忌-男-15", "周芷若-女-14", "张三-男-23", "小昭-女-18", "李四-男-21"); //收集list集合当中 //需求:把所有男性收集起来 List<String> newList1 = list.stream() .filter(s -> "男".equals(s.split("-") [1])).collect(Collectors.toList()); System.out.println(newList1); //收集Set集合当中 //需求:把所有男性收集起来 Set<String> newList2 = list.stream().filter (s -> "男".equals(s.split("-")[1])).collect (Collectors.toSet()); System.out.println(newList2); //收集Map集合当中 //谁作为键,谁作为值 //我要把所有的男性手机起来 //键:姓名 值:年龄 张无忌-男-15 /* toMap:参数一表示键的生成规则 参数二表示值的生成规则 参数一: Function泛型一:表示流中每一个数据的类型 泛型二:表示Map集合中键的数据类型 方法apply形参:依次表示流里面的每一个数据 方法体:生成键的代码 返回值:已经生成的键 参数二:Function泛型一:表示流中每一个数据的类型 泛型二:表示Map集合中值的数据类型 方法apply形参:依次表示流里面的每一个数据 方法体:生成值的代码 返回值:已经生成的值 */ Map<String, Integer> map = list.stream().filter(s -> "男" .equals(s.split("-")[1])) .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("-")[2]); } } )); System.out.println(map); Map<String, Integer> map2 = list.stream().filter (s -> "男".equals(s.split("-")[1])) .collect(Collectors.toMap( s -> s.split("-")[0], s -> Integer.parseInt(s.split("-")[2]) )); System.out.println(map2);



1326

被折叠的 条评论
为什么被折叠?



