当前位置: 首页 > article >正文

Java Map集合详解与实战

集合进阶Map集合一、Map集合1.1 Map概述体系各位同学前面我们已经把单列集合学习完了接下来我们要学习的是双列集合。首先我们还是先认识一下什么是双列集合。所谓双列集合就是说集合中的元素是一对一对的。格式:{key1value1 , key2value2 , key3value3 , ...}Map集合中的每一个元素是以keyvalue的形式存在的一个keyvalue就称之为一个键值对而且在Java中有一个类叫Entry类Entry的对象用来表示键值对对象Map集合也被叫做“键值对集合”。所有的Map集合有如下的特点所有键是不允许重复的值可以重复键和值是一一对应的每一个键只能找到自己对应的值。下面我们先写一个Map集合保存几个键值对体验一下Map集合的特点public class MapTest1 { public static void main(String[] args) { // MapString, Integer map new HashMap(); // 一行经典代码。按照键: 无序不重复无索引。 MapString, Integer map new LinkedHashMap(); // 特点: 有序不重复无索引。 map.put(手表, 100); map.put(手表, 220); // 后面重复的数据会覆盖前面的数据键 map.put(手机, 2); map.put(Java, 2); map.put(null, null); System.out.println(map); ​ MapInteger, String map1 new TreeMap(); // 可排序不重复无索引 map1.put(23, Java); map1.put(23, MySQL); map1.put(19, 李四); map1.put(20, 王五); System.out.println(map1); } }Map集合也有很多种在Java中使用不同的类来表示的每一种Map集合其键的特点是有些差异的值是键的一个附属值所以我们只关注键的特点就可以了。总结: 1. Map集合是什么什么时候可以考虑使用Map集合 Map集合是键值对集合 需要存储一一对应的数据时就可以考虑使用Map集合来做 ​ 2. Map集合的实现类有哪些各自的特点是 HashMap: 元素按照键是无序不重复无索引值不做要求。 LinkedHashMap: 元素按照键是有序不重复无索引值不做要求。 TreeMap元素按照建是排序不重复无索引的值不做要求。关于Map集合是什么以及Map集合的体系我们先了解到这里接下来就具体学习一下Map集合的通用方法。1.2 Map集合的常用方法各位同学上节课我们已经认识了Map集合接下来我们学习一下Map集合提供了那些方法供我们使用。由于Map是所有双列集合的父接口所以我们只需要学习Map接口中每一个方法是什么含义那么所有的Map集合方法你就都会用了。public class MapTest2 { public static void main(String[] args) { // 1.添加元素: 无序不重复无索引。 MapString, Integer map new HashMap(); map.put(手表, 100); map.put(手表, 220); map.put(手机, 2); map.put(Java, 2); map.put(null, null); System.out.println(map); // map {nullnull, 手表220, Java2, 手机2} ​ // 2.public int size():获取集合的大小 System.out.println(map.size()); ​ // 3、public void clear():清空集合 //map.clear(); //System.out.println(map); ​ // 4.public boolean isEmpty(): 判断集合是否为空为空返回true ,反之 System.out.println(map.isEmpty()); ​ // 5.public V get(Object key)根据键获取对应值 int v1 map.get(手表); System.out.println(v1); System.out.println(map.get(手机)); // 2 System.out.println(map.get(张三)); // null ​ // 6. public V remove(Object key)根据键删除整个元素(删除键会返回键的值) System.out.println(map.remove(手表)); System.out.println(map); ​ // 7.public boolean containsKey(Object key): 判断是否包含某个键 包含返回true ,反之 System.out.println(map.containsKey(手表)); // false System.out.println(map.containsKey(手机)); // true System.out.println(map.containsKey(java)); // false System.out.println(map.containsKey(Java)); // true ​ // 8.public boolean containsValue(Object value): 判断是否包含某个值。 System.out.println(map.containsValue(2)); // true System.out.println(map.containsValue(2)); // false ​ // 9.public SetK keySet(): 获取Map集合的全部键。 SetString keys map.keySet(); System.out.println(keys); ​ // 10.public CollectionV values(); 获取Map集合的全部值。 CollectionInteger values map.values(); System.out.println(values); ​ // 11.把其他Map集合的数据倒入到自己集合中来。(拓展) MapString, Integer map1 new HashMap(); map1.put(java1, 10); map1.put(java2, 20); MapString, Integer map2 new HashMap(); map2.put(java3, 10); map2.put(java2, 222); map1.putAll(map2); // putAll把map2集合中的元素全部倒入一份到map1集合中去。 System.out.println(map1); System.out.println(map2); } }1.3 Map集合遍历方式1Map集合一共有三种遍历方式:我们先来学习第一种他需要用到下面的两个方法/** * 目标掌握Map集合的遍历方式1键找值 */ public class MapTest3 { public static void main(String[] args) { // 准备一个Map集合。 MapString, Double map new HashMap(); map.put(蜘蛛精, 162.5); map.put(蜘蛛精, 169.8); map.put(紫霞, 165.8); map.put(至尊宝, 169.5); map.put(牛魔王, 183.6); System.out.println(map); // map {蜘蛛精169.8, 牛魔王183.6, 至尊宝169.5, 紫霞165.8} ​ // 1、获取Map集合的全部键 SetString keys map.keySet(); // System.out.println(keys); // [蜘蛛精, 牛魔王, 至尊宝, 紫霞] // key // 2、遍历全部的键根据键获取其对应的值 for (String key : keys) { // 根据键获取对应的值 double value map.get(key); System.out.println(key value); } } }1.4 Map集合遍历方式2各位同学接下来我们学习Map集合的第二种遍历方式这种遍历方式更加符合面向对象的思维。前面我们给大家介绍过Map集合是用来存储键值对的而每一个键值对实际上是一个Entry对象。这里Map集合的第二种方式是直接获取每一个Entry对象把Entry存储到Set集合中去再通过Entry对象获取键和值。/** * 目标掌握Map集合的第二种遍历方式键值对。 */ public class MapTest4 { public static void main(String[] args) { MapString, Double map new HashMap(); map.put(蜘蛛精, 169.8); map.put(紫霞, 165.8); map.put(至尊宝, 169.5); map.put(牛魔王, 183.6); System.out.println(map); // map {蜘蛛精169.8, 牛魔王183.6, 至尊宝169.5, 紫霞165.8} // entries [(蜘蛛精169.8), (牛魔王183.6), (至尊宝169.5), (紫霞165.8)] // entry (蜘蛛精169.8) // entry (牛魔王183.6) // ... ​ // 调用Map集合提供entrySet方法把Map集合转换成键值对类型的Set集合 SetMap.EntryString, Double entries map.entrySet(); for (Map.EntryString, Double entry : entries) { String key entry.getKey(); double value entry.getValue(); System.out.println(key ---- value); } } }1.5 Map集合遍历方式3Map集合的第三种遍历方式需要用到下面的一个方法forEach而这个方法是JDK8版本以后才有的。调用起来非常简单最好是结合的lambda表达式一起使用。/** * 目标掌握Map集合的第二种遍历方式键值对。 */ public class MapTest5 { public static void main(String[] args) { MapString, Double map new HashMap(); map.put(蜘蛛精, 169.8); map.put(紫霞, 165.8); map.put(至尊宝, 169.5); map.put(牛魔王, 183.6); System.out.println(map); // map {蜘蛛精169.8, 牛魔王183.6, 至尊宝169.5, 紫霞165.8} ​ //遍历map集合传递匿名内部类 map.forEach(new BiConsumerString, Double() { Override public void accept(String k, Double v) { System.out.println(k ---- v); } }); System.out.println(---------------------); //遍历map集合传递Lambda表达式 map.forEach((k, v) - { System.out.println(k ---- v); }); } }1.6 Map集合案例学习完Map集合的基本用法之后接下来我们做一个综合案例将Map集合运用一下。先分析需求再考虑怎么用代码实现1.首先可以将80个学生选择的景点放到一个集合中去也就是说集合中的元素是80个任意的ABCD元素 2.准备一个Map集合用来存储景点以及景点被选择的次数 3.遍历80个学生选择景点的集合得到每一个景点判断Map集合中是否包含该景点 如果不包含则存储景点1 如果包含则存获取该景点原先的值再存储景点原来的值1; 此时新值会覆盖旧值/** * 目标完成Map集合的案例统计投票人数。 */ public class MapDemo { public static void main(String[] args) { // 1、把80个学生选择的景点数据拿到程序中来。 ListString data new ArrayList(); String[] selects {A, B, C, D}; Random r new Random(); for (int i 1; i 80; i) { // 每次模拟一个学生选择一个景点存入到集合中去。 int index r.nextInt(4); // 0 1 2 3 data.add(selects[index]); } System.out.println(data); ​ // 2、开始统计每个景点的投票人数 // 准备一个Map集合用于统计最终的结果 MapString, Integer result new HashMap(); ​ // 3、开始遍历80个景点数据 for (String s : data) { // 问问Map集合中是否存在该景点 if(result.containsKey(s)){ // 说明这个景点之前统计过。其值1. 存入到Map集合中去 result.put(s, result.get(s) 1); }else { // 说明这个景点是第一次统计存入景点1 result.put(s, 1); } } System.out.println(result); } }二、Map实现类同学们我们已经学习了Map集合的常用方法以及遍历方式。下面我们要学习的是Map接口下面的是三个实现类HashMap、LinkedHashMap、TreeMap。实际上这三个实现类并没有什么特有方法需要我们学习它们的方法就是前面学习Map的方法。这里我们主要学习它们的底层原理。2.1 HashMap首先我们学习HashMap集合的底层原理。前面我们学习过HashSet的底层原理实际上HashMap底层原理和HashSet是一样的。为什么这么说呢因为我们往HashSet集合中添加元素时实际上是把元素添加到了HashMap集合中。下面是Map集合的体系结构HashMap集合的特点是由键决定的它的键是无序、不能重复而且没有索引的。再各种Map集合中也是用得最多的一种集合。刚才我们说HashSet底层就是HashMap我们可以看源码验证这一点如下图所示我们可以看到创建HashSet集合时底层帮你创建了HashMap集合往HashSet集合中添加添加元素时底层却是调用了Map集合的put方法把元素作为了键来存储。所以实际上根本没有什么HashSet集合把HashMap的集合的值忽略不看就是HashSet集合。HashSet的原理我们之前已经学过了所以HashMap是一样的底层是哈希表结构。HashMap底层数据结构: 哈希表结构 JDK8之前的哈希表 数组链表 JDK8之后的哈希表 数组链表红黑树 哈希表是一种增删改查数据性能相对都较好的数据结构 往HashMap集合中键值对数据时底层步骤如下 第1步当你第一次往HashMap集合中存储键值对时底层会创建一个长度为16的数组 第2步把键然后将键和值封装成一个对象叫做Entry对象 第3步再根据Entry对象的键计算hashCode值和值无关 第4步利用hashCode值和数组的长度做一个类似求余数的算法会得到一个索引位置 第5步判断这个索引的位置是否为null如果为null,就直接将这个Entry对象存储到这个索引位置 如果不为null则还需要进行第6步的判断 第6步继续调用equals方法判断两个对象键是否相同 如果equals返回false则以链表的形式往下挂 如果equals方法true,则认为键重复此时新的键值对会替换就的键值对。 HashMap底层需要注意这几点 1.底层数组默认长度为16如果数组中有超过12个位置已经存储了元素则会对数组进行扩容2倍 数组扩容的加载因子是0.75意思是16*0.7512 2.数组的同一个索引位置有多个元素、并且在8个元素以内(包括8)则以链表的形式存储 JDK7版本链表采用头插法新元素往链表的头部添加 JDK8版本链表采用尾插法新元素我那个链表的尾部添加 3.数组的同一个索引位置有多个元素、并且超过了8个则以红黑树形式存储从HashMap底层存储键值对的过程中我们发现决定键是否重复依赖于两个方法一个是hashCode方法、一个是equals方法。有两个键计算得到的hashCode值相同并且两个键使用equals比较为true就认为键重复。所以往Map集合中存储自定义对象作为键为了保证键的唯一性我们应该重写hashCode方法和equals方法。比如有如下案例往HashMap集合中存储Student对象作为键学生的家庭住址当做值。要求当学生对象的姓名和年龄相同时就认为键重复。public class Student implements ComparableStudent { private String name; private int age; private double height; ​ // this o Override public int compareTo(Student o) { return this.age - o.age; // 年龄升序排序 } ​ Override public boolean equals(Object o) { if (this o) return true; if (o null || getClass() ! o.getClass()) return false; Student student (Student) o; return age student.age Double.compare(student.height, height) 0 Objects.equals(name, student.name); } ​ Override public int hashCode() { return Objects.hash(name, age, height); } ​ public Student() { } ​ public Student(String name, int age, double height) { this.name name; this.age age; this.height height; } ​ //...get,set方法自己补全.... ​ Override public String toString() { return Student{ name name \ , age age , height height }; } }写一个测试类在测试类中创建HashMap集合键是Student类型值是Stirng类型/** * 目标掌握Map集合下的实现类HashMap集合的底层原理。 */ public class MapTest1 { public static void main(String[] args) { // 创建Map集合 MapStudent, String map new HashMap(); map.put(new Student(蜘蛛精, 25, 168.5), 盘丝洞); map.put(new Student(蜘蛛精, 25, 168.5), 水帘洞); map.put(new Student(至尊宝, 23, 163.5), 水帘洞); map.put(new Student(牛魔王, 28, 183.5), 牛头山); System.out.println(map); } }上面存储的键有两个蜘蛛精但是打印出只会有最后一个。1、HashMap的特点和底层原理 由键决定无序、不重复、无索引。HashMap底层是哈希表结构的。 HashMap集合是一种增删改查数据性能都较好的集合 但是它是无序不能重复没有索引支持的由键决定特点 HashMap的键依赖hashCode方法和equals方法保证键的唯一 如果键存储的是自定义类型的对象可以通过重写hashCode和equals方法这样可以保证多个对象内容一样时HashMap集合就能认为是重复的。 ​ 2、HashMap如何实现键的唯一性的 依赖hashCode方法和equals方法保证键的唯一。 如果键要存储的是自定义对象需要重写hashCode和equals方法。2.2 LinkedHashMap学习完HashMap集合的特点以及底层原理。接下来我们学习一下LinkedHashMap集合。LinkedHashMap集合的特点也是由键决定的有序的、不重复、无索引。/** * 目标掌握LinkedHashMap的底层原理。 */ public class MapTest2 { public static void main(String[] args) { // MapString, Integer map new HashMap(); // 按照键 无序不重复无索引。 LinkedHashMapString, Integer map new LinkedHashMap(); // 按照键 有序不重复无索引。 map.put(手表, 100); map.put(手表, 220); map.put(手机, 2); map.put(Java, 2); map.put(null, null); System.out.println(map); } }运行上面代码发现如果是LinedHashMap集合键存储和取出的顺序是一样的如果是HashMap键存储和取出的顺序是不一致的LinkedHashMap的底层原理和LinkedHashSet底层原理是一样的。底层多个一个双向链表来维护键的存储顺序。取元素时先取头节点元素然后再依次取下一个几点一直到尾结点。所以是有序的。2.3 TreeMap最后我们再学习Map集合下面的另一个子类叫TreeMap。根据我们前面学习其他Map集合的经验我们应该可以猜出TreeMap有什么特点。TreeMap集合的特点也是由键决定的默认按照键的升序排列键不重复也是无索引的。TreeMap集合和TreeSet也是一样的底层都是红黑树实现的。所以可以对键进行排序。比如往TreeMap集合中存储Student对象作为键排序方法有两种。直接看代码吧排序方式1写一个Student类让Student类实现Comparable接口//第一步先让Student类实现Comparable接口 public class Student implements ComparableStudent{ private String name; private int age; private double height; //无参数构造方法 public Student(){} //全参数构造方法 public Student(String name, int age, double height){ this.namename; this.ageage; this.heightheight; } //...get、set、toString()方法自己补上.. //按照年龄进行比较只需要在方法中让this.age和o.age相减就可以。 /* 原理 在往TreeSet集合中添加元素时add方法底层会调用compareTo方法根据该方法的 结果是正数、负数、还是零决定元素放在后面、前面还是不存。 */ Override public int compareTo(Student o) { //this表示将要添加进去的Student对象 //o: 表示集合中已有的Student对象 return this.age-o.age; } }排序方式2在创建TreeMap集合时直接传递Comparator比较器对象。/** * 目标掌握TreeMap集合的使用。 */ public class MapTest3 { public static void main(String[] args) { MapStudent, String map new TreeMap(new ComparatorStudent() { Override public int compare(Student o1, Student o2) { return Double.compare(o1.getHeight(), o2.getHeight()); } }); // MapStudent, String map new TreeMap(( o1, o2) - Double.compare(o2.getHeight(), o1.getHeight())); map.put(new Student(蜘蛛精, 25, 168.5), 盘丝洞); map.put(new Student(蜘蛛精, 25, 168.5), 水帘洞); map.put(new Student(至尊宝, 23, 163.5), 水帘洞); map.put(new Student(牛魔王, 28, 183.5), 牛头山); System.out.println(map); } }这种方式都可以对TreeMap集合中的键排序。注意只有HashMap的键才能排序HashMap值不能排序。总结: 1、TreeMap集合的特点、原理是怎么样的 根据键可排序、不重复、无索引 底层基于红黑树实现排序增删改查性能较好 ​ 2、TreeMap集合对自定义类型的对象排序有几种方式指定排序规则 2种。 ①类实现Comparable接口重写比较规则。 ②集合自定义Comparator比较器对象重写比较规则。2.4 集合嵌套各位同学到现在为止我们把Map集合和Collection集合的都已经学习完了。但是在实际开发中可能还会存在一种特殊的用法。就是把一个集合当做元素存储到另一个集合中去我们把这种用法称之为集合嵌套。下面通过一个案例给大家演示一下案例分析1.从需求中我们可以看到有三个省份每一个省份有多个城市 Map省份, List集合市 我们可以用一个Map集合的键表示省份名称而值表示省份有哪些城市 2.而又因为一个省份有多个城市同一个省份的多个城市可以再用一个List集合来存储。 所以Map集合的键是String类型而值是List集合类型 HashMapString, ListString map new HashMap();代码如下/** * 目标理解集合的嵌套。 * 江苏省 南京市,扬州市,苏州市,无锡市,常州市 * 湖北省 武汉市,孝感市,十堰市,宜昌市,鄂州市 * 河北省 石家庄市,唐山市, 邢台市, 保定市, 张家口市 */ public class MapDemo { public static void main(String[] args) { // 定义一个Map集合存储全部的省份信息和其对应的城市信息。 MapString, ListString map new HashMap(); ​ ListString cities1 new ArrayList(); Collections.addAll(cities1, 南京市,扬州市,苏州市 ,无锡市,常州市); map.put(江苏省, cities1); ​ ListString cities2 new ArrayList(); Collections.addAll(cities2, 武汉市,孝感市,十堰市,宜昌市,鄂州市); map.put(湖北省, cities2); ​ ListString cities3 new ArrayList(); Collections.addAll(cities3, 石家庄市,唐山市, 邢台市, 保定市, 张家口市); map.put(河北省, cities3); System.out.println(map); ​ ListString cities map.get(湖北省); for (String city : cities) { System.out.println(city); } ​ map.forEach((p, c) - { System.out.println(p ----- c); }); } }三、JDK8新特性Stream流各位同学接下来我们学习一个全新的知识叫做Stream流也叫Stream API。它是从JDK8以后才有的一个新特性是专业用于对集合或者数组进行便捷操作的。有多方便呢什么是Stream也叫Stream流是JDK8开始新增的一套API (java.util.stream.*)可以用于操作集合或者数组的数据。优势Stream流大量的结合了Lambda的语法风格来编程提供了一种更加强大更加简单的方式操作集合或者数组中的数据代码更简洁可读性更好。我们用一个案例体验一下然后再详细学习。3.1 Stream流体验案例需求有一个List集合元素有张三丰,张无忌,周芷若,赵敏,张强找出姓张且是3个字的名字存入到一个新集合中去。public class StreamTest { public static void main(String[] args) { // 创建集合 ListString names new ArrayList(); // 批量存储数据 Collections.addAll(names, 张三丰,张无忌,周芷若,赵敏,张强); // 打印集合 System.out.println(names); } }用传统方式来做代码是这样的// 找出姓张且是3个字的名字存入到一个新集合中去。 ListString list new ArrayList(); for (String name : names) { if(name.startsWith(张) name.length() 3){ list.add(name); } } System.out.println(list);用Stream流来做代码是这样的ps: 是不是想流水线一样一句话就写完了ListString list2 names.stream().filter(s - s.startsWith(张) s.length() 3) .collect(Collectors.toList()); System.out.println(list2); ​ System.out.println(-----------------------------); ​ ListString list3 names.stream().filter(s - s.startsWith(张)).filter(a - a.length() 3).collect(Collectors.toList()); System.out.println(list3);先不用知道这里面每一句话是什么意思具体每一句话的含义待会再一步步学习。现在只是体验一下。学习Stream流我们接下来会按照下面的步骤来学习。3.2 Stream流的创建好接下来我们正式来学习Stream流。先来学习如何创建Stream流、或者叫获取Stream流。如何获取Stream流?获取 集合 的Stream流Collection提供的如下方法说明default StreamE stream()获取当前集合对象的Stream流获取 数组 的Stream流Arrays类提供的如下 方法说明public static T StreamT stream(T[] array)获取当前数组的Stream流Stream类提供的如下 方法说明public staticT StreamTof(T... values)获取当前接收数据的Stream流直接上代码演示/** * 目标掌握Stream流的创建。 */ public class StreamTest2 { public static void main(String[] args) { // 1. 如何获取list集合的Stream流 ListString list new ArrayList(); Collections.addAll(list, 张三丰,张无忌,周芷若,赵敏,张强); StreamString stream list.stream(); ​ // 2. 如何获取set集合的Stream流 SetString set new HashSet(); Collections.addAll(set, 刘德华,张曼玉,蜘蛛精,马德,德玛西亚); StreamString stream1 set.stream(); ​ // 3. 如何获取map集合的Stream流 MapString, Double map new HashMap(); map.put(古力娜扎, 172.3); map.put(迪丽热巴, 168.3); map.put(马尔扎哈, 166.3); map.put(卡尔扎巴, 168.3); // 通过获取所有key 再获取stream流 SetString keys map.keySet(); StreamString ks keys.stream(); // 通过获取所有value 再获取stream流 CollectionDouble values map.values(); StreamDouble vs values.stream(); ​ // 通过获取entry对象 再获取stream流 SetMap.EntryString, Double entries map.entrySet(); StreamMap.EntryString, Double kvs entries.stream(); kvs.filter(s - s.getKey().contains(扎)).collect(Collectors.toList()) .forEach(s - System.out.println(s.getKey() -- s.getValue())); ​ // 4. 如何获取数组的Stream流 String[] names {张翠山, 东方不败, 唐大山, 独孤求败}; StreamString s1 Arrays.stream(names); StreamString s2 Stream.of(names); } }3.3 Stream流中间方法在上一节我们学习了创建Stream流的方法。接下来我们再来学习Stream流中间操作的方法。中间方法指的是调用完方法之后其结果是一个新的Stream流于是可以继续调用方法这样一来就可以支持链式编程或者叫流式编程。话不多说直接上代码演示/** * 目标掌握Stream流提供的常见中间方法。 */ public class StreamTest3 { public static void main(String[] args) { // 创建list集合 ListDouble scores new ArrayList(); Collections.addAll(scores, 88.5, 100.0, 60.0, 99.0, 9.5, 99.6, 25.0); System.out.println(scores); // 需求1找出成绩大于等于60分的数据并升序后再输出。 scores.stream().filter(s - s 60).sorted().forEach(s - System.out.println(s)); ​ System.out.println(------------------------------------------------); ​ ListStudent students new ArrayList(); Student s1 new Student(蜘蛛精, 26, 172.5); Student s2 new Student(蜘蛛精, 26, 172.5); Student s3 new Student(紫霞, 23, 167.6); Student s4 new Student(白晶晶, 25, 169.0); Student s5 new Student(牛魔王, 35, 183.3); Student s6 new Student(牛夫人, 34, 168.5); Collections.addAll(students, s1, s2, s3, s4, s5, s6); // 需求2找出年龄大于等于23,且年龄小于等于30岁的学生并按照年龄降序输出. students.stream().filter(s - s.getAge() 23 s.getAge() 30) .sorted(((o1, o2) - o2.getAge() - o1.getAge())) .forEach(s - System.out.println(s)); ​ System.out.println(------------------------------------------------); ​ // 需求3取出身高最高的前3名学生并输出。 students.stream().sorted(((o1, o2) - Double.compare(o2.getHeight(), o1.getHeight()))) .limit(3) .forEach(s - System.out.println(s)); ​ System.out.println(------------------------------------------------); ​ // 需求4取出身高倒数的2名学生并输出。 s1 s2 s3 s4 s5 s6 students.stream().sorted(((o1, o2) - Double.compare(o2.getHeight(), o1.getHeight()))) .skip(students.size() - 2) .forEach(s - System.out.println(s)); ​ System.out.println(------------------------------------------------); ​ // 需求5找出身高超过168的学生叫什么名字要求去除重复的名字再输出。 students.stream().filter(s - s.getHeight() 168) .map(Student::getName) .distinct() .forEach(System.out::println); ​ System.out.println(------------------------------------------------); ​ // distinct去重复自定义类型的对象希望内容一样就认为重复重写hashCode,equals students.stream().filter(s - s.getHeight() 168) .distinct() .forEach(System.out::println); ​ System.out.println(------------------------------------------------); ​ // 合并a和b两个流为一体 StreamString st1 Stream.of(张三, 李四); StreamString st2 Stream.of(张三2, 李四2, 王五); StreamString allSt Stream.concat(st1, st2); allSt.forEach(System.out::println); } }3.4 Stream流终结方法最后我们再学习Stream流的终结方法。这些方法的特点是调用完方法之后其结果就不再是Stream流了所以不支持链式编程。我列举了下面的几个终结方法接下来用几个案例来一个一个给同学们演示。收集Stream流就是把Stream流操作后的结果转回到集合或者数组中去返回。Stream流方便操作集合/数组的手段集合/数组才是开发中的目的。话不多说直接上代码/** * 目标Stream流的终结方法 */ public class StreamTest4 { public static void main(String[] args) { ListStudent students new ArrayList(); Student s1 new Student(蜘蛛精, 26, 172.5); Student s2 new Student(蜘蛛精, 26, 172.5); Student s3 new Student(紫霞, 23, 167.6); Student s4 new Student(白晶晶, 25, 169.0); Student s5 new Student(牛魔王, 35, 183.3); Student s6 new Student(牛夫人, 34, 168.5); Collections.addAll(students, s1, s2, s3, s4, s5, s6); // 需求1请计算出身高超过168的学生有几人。 long size students.stream().filter(s - s.getHeight() 168).count(); System.out.println(size); ​ // 需求2请找出身高最高的学生对象并输出。 Student s students.stream().max((o1, o2) - Double.compare(o1.getHeight(), o2.getHeight())).get(); System.out.println(s); ​ // 需求3请找出身高最矮的学生对象并输出。 Student ss students.stream().min((o1, o2) - Double.compare(o1.getHeight(), o2.getHeight())).get(); System.out.println(ss); ​ // 需求4请找出身高超过170的学生对象并放到一个新集合中去返回。 // 流只能收集一次。 ListStudent students1 students.stream().filter(a - a.getHeight() 170).collect(Collectors.toList()); System.out.println(students1); ​ SetStudent students2 students.stream().filter(a - a.getHeight() 170).collect(Collectors.toSet()); System.out.println(students2); ​ // 需求5请找出身高超过170的学生对象并把学生对象的名字和身高存入到一个Map集合返回。 MapString, Double map students.stream().filter(a - a.getHeight() 170) .distinct().collect(Collectors.toMap(a - a.getName(), a - a.getHeight())); System.out.println(map); ​ // Object[] arr students.stream().filter(a - a.getHeight() 170).toArray(); Student[] arr students.stream().filter(a - a.getHeight() 170).toArray(len - new Student[len]); System.out.println(Arrays.toString(arr)); } }到这里关于Stream流的操常见操作我们就已经学习完了。当然Stream流还有一些其他的方法同学们遇到了也可以自己再研究一下。

相关文章:

Java Map集合详解与实战

集合进阶(Map集合)一、Map集合1.1 Map概述体系各位同学,前面我们已经把单列集合学习完了,接下来我们要学习的是双列集合。首先我们还是先认识一下什么是双列集合。所谓双列集合,就是说集合中的元素是一对一对的。格式:…...

专业联发科设备bootloader解锁与安全绕过实战指南

专业联发科设备bootloader解锁与安全绕过实战指南 【免费下载链接】mtkclient-gui GUI tool for unlocking bootloader and bypassing authorization on Mediatek devices (Not maintained anymore) 项目地址: https://gitcode.com/gh_mirrors/mt/mtkclient-gui mtkclie…...

计算机专业生打 CTF 全指南:从新手小白到赛事拿分,附实战避坑手册_ctf比赛自己带电脑吗

作为计算机专业毕业的过来人,我始终觉得:CTF 比赛是大学生把课本知识落地成硬技能的最佳载体。 刚上大二时,我还是个只会敲基础代码、对 网络安全停留在课本概念的小白,靠着 3 次参赛经历,不仅吃透了操作系统、计算机…...

FRED案例:矩形微透镜阵列

介绍小透镜阵列可应用在很多方面,其中包含光束均匀化。本文演示了一个用于在探测器上创建均匀的非相干照度的成像微透镜阵列的设计。输入光束具有高斯轮廓,半宽度等于微透镜阵列大小,并且显示了其功率轮廓被微透镜阵列消除掉。系统输出简单示…...

【紧急更新】Midjourney 6.3毛发引擎重大变更!旧版Prompt失效预警+4套即插即用迁移方案(含兼容性检测脚本)

更多请点击: https://kaifayun.com 第一章:Midjourney 6.3毛发引擎重大变更全景速览 Midjourney v6.3 引入了全新重构的毛发渲染子系统(Fur Rendering Engine),标志着其在生物细节生成能力上的关键跃迁。该引擎不再依…...

英雄联盟Akari助手:一键智能配置,释放你的游戏潜能 [特殊字符]

英雄联盟Akari助手:一键智能配置,释放你的游戏潜能 🚀 【免费下载链接】League-Toolkit An all-in-one toolkit for LeagueClient. Gathering power 🚀. 项目地址: https://gitcode.com/gh_mirrors/le/League-Toolkit 还在…...

酷安UWP桌面客户端:在Windows电脑上高效刷酷安的完整指南

酷安UWP桌面客户端:在Windows电脑上高效刷酷安的完整指南 【免费下载链接】Coolapk-UWP 一个基于 UWP 平台的第三方酷安客户端 项目地址: https://gitcode.com/gh_mirrors/co/Coolapk-UWP 还在为手机小屏幕刷酷安而感到眼睛酸痛吗?想在27寸大屏幕…...

Windows 10/11(64位)上安装 WinQSB——无需虚拟机

以下是在 Windows 10/11(64位) 上安装 WinQSB 的完整步骤,无需虚拟机,并安装在 D 盘。原理说明 WinQSB 是一个 16位 Windows 程序,64位 Windows 原生不支持运行它。解决方案是使用 winevdm(otvdm&#xff0…...

黎阳之光人员无感技术——赋能边防与城市智慧发展

无感戍边 数筑屏障|黎阳之光人员无感技术赋能智慧边防建设在国家边境安全防控体系建设中,边防工作始终承担着守护国土、防范风险、维护边境稳定的重要职责。我国边境线地理环境复杂,涵盖高原、荒漠、口岸、界江等多元场景,气候条件…...

强烈推荐!这款顶伯 工具拯救了我的日更视频账号

强烈推荐!这款顶伯 TTS 工具拯救了我的日更视频账号做日更视频账号最痛苦的是什么?是配音。 以前我每天花两小时录音、降噪、剪辑,嗓子还经常哑。直到用了顶伯文字转语音工具,一切都变了。它基于微软 TTS 技术,音质自然…...

【紧急更新】Midjourney 6.2已悄悄禁用glass关键词!替代方案+3套可直接复用的prompt模板(限24小时公开)

更多请点击: https://intelliparadigm.com 第一章:Midjourney 6.2玻璃质感禁用事件全貌解析 2024年7月,Midjourney官方悄然更新至v6.2版本,并在未发布正式公告的情况下,对部分高精度材质描述词实施了隐性限制——其中…...

多角色对话配音方案:顶伯 一键生成有声剧,支持角色区分

多角色对话配音方案:顶伯 一键生成有声剧,支持角色区分在制作有声剧、播客或短视频时,多角色对话配音往往是最耗时的一环。传统方法需要为每个角色分别录制、剪辑、混音,不仅效率低下,还容易因音色不统一而影响沉浸感。…...

Whisky完全指南:在macOS上轻松运行Windows程序的终极方案

Whisky完全指南:在macOS上轻松运行Windows程序的终极方案 【免费下载链接】Whisky A modern Wine wrapper for macOS built with SwiftUI 项目地址: https://gitcode.com/gh_mirrors/wh/Whisky 还在为macOS上无法运行某些Windows专属软件而烦恼吗&#xff1f…...

情感演绎有多强?顶伯实测愤怒、喜悦、悲伤等 9 种语气

🎭 微软 TTS 的情感演绎有多强?顶伯实测愤怒、喜悦、悲伤等 9 种语气🎯 引言:语音合成的情感革命在人工智能语音合成领域,情感表达一直是技术难点。微软 TTS(文本转语音)通过深度学习模型&#…...

如何在Hermes Agent项目中自定义Provider接入Taotoken多模型服务

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 如何在Hermes Agent项目中自定义Provider接入Taotoken多模型服务 Hermes Agent 是一个功能强大的AI代理框架,它允许开发…...

2026年AI大模型API中转站主流服务商实测排名 性能成本与落地能力全维度深度对比

五大主流平台核心维度综合能力横向盘点2026年AI大模型已经全面跨入规模化落地阶段,国内日均AI Token调用总量突破140万亿量级,API聚合中转平台早已脱离最初简单协议转发层的定位,成为支撑企业AI能力落地的核心关键网关。平台运行稳定性、多协…...

Frida+Fart实战:在ART Dex加载临界点精准dump二代壳内存Dex

1. 这不是“又一个脱壳教程”,而是对Android加固演进逻辑的现场解剖你打开一个市面上主流的金融类App,用adb shell pm list packages | grep bank随手一搜,发现它被某知名商业加固厂商打了“二代壳”——启动慢、内存占用高、关键so文件加密、…...

Unity PC端软键盘唤醒实战:Windows osk.exe兼容性攻坚

1. 这不是“调个API”就能解决的事:PC端软键盘唤醒的现实困境Unity项目上线前一周,测试同事在Windows台式机上点开登录框,手指悬在键盘上方三秒——没反应。他下意识摸了摸键盘,又点了一次输入框,还是没弹出任何软键盘…...

Files.md:打造私密思考空间,兼具简洁实用与多样同步功能!

Files.md:专注思考的私密空间Files.md 是一款简洁的 .md 文件应用,为用户打造一个私密、安静的思考空间。用户可以用它存储生活中的一切,如笔记、文档、项目、日记、习惯记录、待办清单和任务等,所有内容都以纯 .md 文件形式保存&…...

在自动化脚本中使用Taotoken实现多模型备援与降级策略

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 在自动化脚本中使用Taotoken实现多模型备援与降级策略 构建高可用的AI应用时,服务的稳定性直接影响终端用户体验。当单…...

如何用Win11Debloat免费为Windows系统瘦身:终极优化指南

如何用Win11Debloat免费为Windows系统瘦身:终极优化指南 【免费下载链接】Win11Debloat A simple, lightweight PowerShell script that allows you to remove pre-installed apps, disable telemetry, as well as perform various other changes to declutter and …...

AntiMicroX手柄映射技术方案:解决PC游戏输入兼容性难题的终极方案

AntiMicroX手柄映射技术方案:解决PC游戏输入兼容性难题的终极方案 【免费下载链接】antimicrox Graphical program used to map keyboard buttons and mouse controls to a gamepad. Useful for playing games with no gamepad support. 项目地址: https://gitcod…...

如何5分钟部署小鹿快传:零基础P2P文件传输终极指南

如何5分钟部署小鹿快传:零基础P2P文件传输终极指南 【免费下载链接】deershare 小鹿快传,一款在线P2P文件传输工具,使用WebSocket WebRTC技术 项目地址: https://gitcode.com/gh_mirrors/de/deershare 小鹿快传(DeerShare…...

如何选择Windows图片查看器?这款开源图像浏览器让你不再纠结

如何选择Windows图片查看器?这款开源图像浏览器让你不再纠结 【免费下载链接】ImageGlass 🏞 A lightweight, versatile image viewer 项目地址: https://gitcode.com/gh_mirrors/im/ImageGlass 还在为Windows自带的图片查看器功能简陋而烦恼&…...

9大网盘直链下载助手:告别限速,免费实现高速下载自由

9大网盘直链下载助手:告别限速,免费实现高速下载自由 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘 / 中国移动云…...

2026 毕业季 AI 论文工具硬核横评:从初稿到定稿,9 款神器帮你告别熬夜焦虑

paperxie-免费查重复率aigc检测/开题报告/毕业论文/智能排版/文献综述/AI PPThttps://www.paperxie.cn/ai/dissertationhttps://www.paperxie.cn/ai/dissertation 引言:毕业季论文困局,AI 工具成破局关键 又到一年毕业季,本科毕业论文成为无…...

抖音直播数据采集:如何用Golang构建实时弹幕监控系统

抖音直播数据采集:如何用Golang构建实时弹幕监控系统 【免费下载链接】douyin-live-go 抖音(web) 弹幕爬虫 golang 实现 项目地址: https://gitcode.com/gh_mirrors/do/douyin-live-go 在直播电商和内容创作日益火爆的今天,数据驱动的运营决策变得…...

10分钟快速上手:VSCode Cortex-Debug调试插件终极指南

10分钟快速上手:VSCode Cortex-Debug调试插件终极指南 【免费下载链接】cortex-debug Visual Studio Code extension for enhancing debug capabilities for Cortex-M Microcontrollers 项目地址: https://gitcode.com/gh_mirrors/co/cortex-debug 还在为嵌入…...

CIO与CHRO携手合作,共同留住企业AI核心人才

Gartner上周发布的一项研究显示,到2027年,缺乏完善AI人才战略的企业,将有半数面临顶尖AI人才流失至竞争对手的风险。为完成这份报告,Gartner在今年第一季度对逾12000名企业员工和管理者进行了调研,重点了解AI对工作的影…...

Audio Slicer:智能音频切片工具终极指南,告别手动剪辑烦恼

Audio Slicer:智能音频切片工具终极指南,告别手动剪辑烦恼 【免费下载链接】audio-slicer A simple GUI application that slices audio with silence detection 项目地址: https://gitcode.com/gh_mirrors/aud/audio-slicer 还在为繁琐的音频剪辑…...