-
不可变集合
-
如果某个数据不能被修改,把它防御性地拷贝到不可变集合中是个很好的实践。
-
或者当集合对象被不可信的库调用时,不可变形式是安全的。
概述:不想让访问者修改集合中的内容时;该集合不能添加、删除和修改;只能进行查询
方法名称 说明 stastic <E> List<E> of(E...elements) 创建一个具有指定元素的List集合对象 stastic <E> Set<E> of(E...elements) 创建一个具有指定元素的Set集合对象 stastic <K, V> Map<K, V> of(E...elements) 创建一个具有指定元素的Map集合对象 eg.
List<String> list = List.of("a", "b", "c"); //list遍历查询 for(String s : list) { sout(s); } //迭代器迭代 Iterator it = list.iterator(); while(it.hasNext()) { String s = it.next(); sout(s); } Set<String> set = Set.of("a", "b", "c"); //set查询没有索引 另外set集合具有唯一性 元素不能重复 for(String s : set) { sout(s); } //迭代器遍历 Iterator<String> it = set.iterator(); while(it.hasNext()) { String s = it.next(); sout(s); } Map<String, String> map = Map.of(k1, v1, k2, v2);//键值对自动对应 Set(String) keys = map.keySet(); for(String key : keys) { String value = map.get(key); sout(key + "=" + value); } //Map遍历键值对 键是不能重复的 Map的of方法 最多传递10个键值对(20个参数);如果要创建不可变 又有20个以上的键值对 用map.entries Set<Map.Entry(String, String)>> entries = map.entrySet(); for(Map.Entry<String, String> entry : entries) { String key = entry.getKey(); String value = entry.getValue(); sout(key + "=" + value); } HashMap<String, String> hm = new HashMap<>(); hm.put(k1, v1); ... hm.put(k10, v10); Set<Map.Entry<String, String>> entries = hm.entrySet(); //把entries变成一个数组 Map.Entry[] arr = new Map.Entry[0]; //toArray方法在底层会比较集合的长度跟数组的长度两者的大小 //如果集合的长度〉数组的长度﹔数据在数组中放不下,此时会根据实际数据的个数,重新创建数组 //如果集合的长度〈= 数组的长度:数据在数组中放的下,此时不会创建新的数组,而是直接用 Map.Entry[] arr2 = entries.toArray(arr); Map<String, String> map = Map.copyOf(hm);//jdk10以后的版本
解释:entrySet()是键值对的对象,其中同时包含了键值的信息;
-
-
Stream流
一般会结合Lambda表达式,简化集合、数组的操作;
Stream流的使用步骤:
-
先得到一条Stream流,并把数据放上去;
-
使用中间方法对流水线进行操作
-
使用终结方法对流水线进行操作
获取方式 方法名 说明 单列集合 default Stream<E> stream Collection中的默认方法 双列集合 无 无法直接使用stream流水 数组 public stastic<T> Stream<T> stream(T[] array) Arrays工具类中的静态方法 一堆零散数据 public stastic<T> Stream<T>of(T...values) Stream接口中的静态方法 //单列集合获得Stream流 ArrayList<String> list = new ArrayList<>(); Collections.addAll(list, "a", "b", "c"); list.stream().forEach(s -> sout(s)); //获取流水线 forEach中 s 表示流水线的每一条数据 打印list中的每一条数据 //双列集合获得Stream流 Map<String, Integer> hm = new HashMap<>(); hm.put("aaa", 111); hm.put("bbb", 222); //第一种获取Stream流的方法,单独取出key hm.keySet().Stream().forEach(s -> sout(s)); //第二种获取Stream流 hm.entrySet().Stream().forEach(s -> sout(s)); //数组获得Stream流 int[] arr1 = {1, 2, 3}; String[] arr2 = {"a", "b", "c"}; Arrays.stream(arr1).forEach(s -> sout(s)); Arrays.stream(arr2).forEach(s -> sout(s)); //基本和引用数据类型都可以 //一堆零散的数据获得stream流 (必须是同类型的数据) Stream.of(1, 2, 3, 4, 5).forEach(s -> sout(s)); Stream.of("a", "b", "c").forEach(s -> sout(s)); //Stream接口中静态方法of的细节 //方法的形参是一个可变参数,可以传递一堆零散的数据,也可以传递数组 //但是数组必须是引用数据类型的,如果传递基本数据类型,是会把整个数组当做一个元素,放到Stream当中。 Stream.of(arr2).forEach(s -> sout(s));//引用数据类型这样用没问题 输出 a b c Stream.of(arr1).forEach(s ->sout(s));//基本数据类型此处返回地址值
-
-
Stream流的中间方法
名称 | 说明 |
---|---|
filter | 过滤 |
limit | 获取前几个元素 |
skip | 跳过前几个元素 |
distinct | 元素去重,依赖(hashCode和equals方法) |
concat | 合并a和b两个流为一个流 |
map | 转换流中的数据类型 |
注意1:中间方法 返回新的Stream流,原来的Stream流只能使用一次,建议使用链式编程
注意2:修改Stream流中的数据,不会影响原来集合或者数组中的数据
//filter ArrayList<String> list = new ArrayList<>(); Collections.addAll(list, "张三", "李四", "王五", "张三丰", "卡卡西", "佐助", "鸣人", "张无忌"); list.stream() .filter(s -> s.startsWith("张"))//找开头是"张"的数据进入流 .filter(s -> s.length() == 3)//找长度为3的数据进入流 .forEach(s -> sout(s));//输出 //limit list.stream().limit(3)//获取集合前三个元素 .forEach(s -> sout(s)); //skip list.stream().skip(4)//集合前四个元素跳过 .forEach(s -> sout(s)); //distinct 元素去重 底层依赖hashCode和equals方法 Collections.addAll(list1, "张三", "张三", "王五", "张三丰", "卡卡西", "佐助", "鸣人", "张无忌"); list1.stream().distinct().forEach(s -> sout(s)); //concat 合并a和b两个流为一个流 Collections.addAll(list2, "雏田", "娜美"); Stream.concat(list1.stream(), list2.stream()).forEach(s -> sout(s)); //map类型转换 Collections.addAll(list3, "张三-13", "王五-29", "张三丰-100", "卡卡西-21", "佐助-12", "鸣人-12", "张无忌-23"); //泛型里面不能写基本数据类型 不能写int 要写Integer //基本数据类型不是JAVA对象, JAVA给每一个基本数据类型都创建了对应的包装类型 list3.stream().map(new Function<String, Integer>() { @Override public Integer apply(String s) { String[] arr = s.split("-");//根据"-"把字符串一分为二 arr[0]为"-"前的姓名, arr[1]为"-"后的年龄 String ageString = arr[1]; int age = Integer.parseInt(ageString);//把String转为Integer return age; } }).forEach(s->sout(s)); //当map方法执行完毕之后,流上的数据就变成了整数 //所以在上面forEach当中,s依次表示流里面的每一个数据,这个数据现在就是整数了 //Lamada改写 list3.stream() .map(s -> Integer.parseInt(s.split("-")[1])) .forEach(s -> sout(s));