• Java基础 - 9 - 集合进阶(二)


    一. Collection的其他相关知识

    1.1 可变参数

    可变参数就是一种特殊形参,定义在方法、构造器的形参列表里,格式是:数据类型…参数名称;

    可变参数的特点和好处

    特点:可以不传数据给它;可以传一个或者同时传多个数据给它;也可以传一个数组给它

    好处:常常用来灵活的接收数据

    1. //demo
    2. public class demo{
    3. public static void main(String[] args){
    4. //可变参数特点
    5. method(); //不传数据
    6. method(10); //传一个数据
    7. method(10,20,30); //传多个数据
    8. method(new int[]{1,2,3,4,5}); //传一个数组给可变参数
    9. }
    10. //注意事项1:一个形参列表中,只能有一个可变参数
    11. //注意事项2:可变参数必须放在形参列表的最后面
    12. public static void method(int...nums){
    13. //可变参数在方法内部本质就是一个数组
    14. System.out.println(nums.length);
    15. System.out.println(Arrays.toString(nums));
    16. System.out.println("====================");
    17. }
    18. }

    1.2 Collections

            Collections是一个用来操作集合的工具类

    Collections提供的常用静态方法

    方法名称说明
    public static boolean addAll(Collectionc , T…elements)给集合批量添加元素
    public static void shuffle(List list)打乱List集合中的元素顺序
    public static void sort(List list)对List集合中的元素进行升序排序
    public static void sort(List list , Comparatorc)对List集合中元素,按照比较器对象指定的规则进行排序

    1. //demo
    2. public class demo{
    3. public static void main(String[] args){
    4. // 接收子类及其父类的类型
    5. //public static boolean addAll(Collectionc , T…elements) 给集合批量添加元素
    6. List names = new ArrayList<>();
    7. Collections.addAll(names,"张三","李四","王五","二麻子"); //批量添加,不用再一个个add了
    8. System.out.println(names); //[张三, 李四, 王五, 二麻子]
    9. //public static void shuffle(List list) 打乱List集合中的元素顺序(List是有序、可重复、有索引)
    10. Collections.shuffle(names);
    11. System.out.println(names); //[二麻子, 王五, 张三, 李四]
    12. //public static void sort(List list) 对List集合中的元素进行升序排序
    13. List nums = new ArrayList<>();
    14. Collections.addAll(nums,1,3,7,5,2);
    15. System.out.println(nums); //[1, 3, 7, 5, 2]
    16. Collections.sort(nums);
    17. System.out.println(nums); //[1, 2, 3, 5, 7]
    18. List cars = new ArrayList<>();
    19. Car c1 = new Car("奔驰",12.8);
    20. Car c2 = new Car("宝马",14.1);
    21. Car c3 = new Car("大众",9.9);
    22. Car c4 = new Car("未来",14.1);
    23. Collections.addAll(cars,c1,c2,c3,c4);
    24. System.out.println(cars); //[Car{name='奔驰', price=12.8}, Car{name='宝马', price=14.1}, Car{name='大众', price=9.9}, Car{name='未来', price=14.1}]
    25. //编译时异常(标红报错):因为sort不知道自定义对象按照什么规则排序
    26. //修改方式:让Car类实现Comparable(比较规则)接口,然后重写compareTo方法来指定比较规则
    27. //Collections.sort(cars);
    28. //System.out.println(cars); //[Car{name='大众', price=9.9}, Car{name='奔驰', price=12.8}, Car{name='宝马', price=14.1}, Car{name='未来', price=14.1}]
    29. //public static void sort(List list , Comparatorc) 对List集合中元素,按照比较器对象指定的规则进行排序
    30. Collections.sort(cars, new Comparator() {
    31. @Override
    32. public int compare(Car o1, Car o2) {
    33. //return Double.compare(o1.getPrice(),o2.getPrice()); //升序
    34. return Double.compare(o2.getPrice(),o1.getPrice()); //降序
    35. }
    36. });
    37. System.out.println(cars);
    38. }
    39. }
    40. //Car
    41. public class Car implements Comparable {
    42. private String name;
    43. private double price;
    44. //this代表主调 o是被调
    45. @Override
    46. public int compareTo(Car o) {
    47. //如果认为左边对象大于右边对象返回正整数
    48. //如果认为左边对象小于右边对象返回负整数
    49. //如果认为左边对象等于右边对象返回0
    50. //需求:按照价格升序排序
    51. //return (int)(this.price-o.price); //不能这样写,返回值是int类型,两个double类型相减之后强转可能会出bug
    52. //写法1
    53. // if(this.price>o.price){
    54. // return 1;
    55. // }else if(this.price
    56. // return -1;
    57. // }else{
    58. // return 0;
    59. // }
    60. //写法2
    61. return Double.compare(this.price,o.price);
    62. }
    63. //右键->生成->equals()和hashCode()
    64. @Override
    65. public boolean equals(Object o) {
    66. if (this == o) return true;
    67. if (o == null || getClass() != o.getClass()) return false;
    68. Car car = (Car) o;
    69. return Double.compare(car.price, price) == 0 &&
    70. Objects.equals(name, car.name);
    71. }
    72. @Override
    73. public int hashCode() {
    74. return Objects.hash(name, price);
    75. }
    76. public Car() {
    77. }
    78. public Car(String name, double price) {
    79. this.name = name;
    80. this.price = price;
    81. }
    82. public String getName() {
    83. return name;
    84. }
    85. public void setName(String name) {
    86. this.name = name;
    87. }
    88. public double getPrice() {
    89. return price;
    90. }
    91. public void setPrice(double price) {
    92. this.price = price;
    93. }
    94. @Override
    95. public String toString() {
    96. return "Car{" +
    97. "name='" + name + '\'' +
    98. ", price=" + price +
    99. '}';
    100. }
    101. }

    1.3 综合案例 

    1. //demo
    2. public class demo {
    3. public static void main(String[] args) {
    4. //创建房间
    5. Room r = new Room();
    6. //启动游戏
    7. r.start();
    8. }
    9. }
    10. //Room
    11. public class Room {
    12. //必须有一副牌
    13. private List allCards = new ArrayList<>();
    14. public Room(){
    15. //做出54张牌,存入到集合allCards中
    16. //点数
    17. String[] numbers = {"3","4","5","6","7","8","9","10","J","Q","K","A","2"};
    18. //花色
    19. String[] colors = {"♣","♦","♠","♥"};
    20. //遍历点数后再遍历花色,组织成牌
    21. for (int i = 0; i < numbers.length; i++) { //i不仅仅是numbers数组的索引,因为点数是按升序放在里面,所以正好还可以代表牌的大小
    22. for (int j = 0; j < colors.length; j++) {
    23. Card card = new Card(numbers[i],colors[j],i); //创建牌对象
    24. allCards.add(card); //存到集合中
    25. }
    26. }
    27. //单独存放大小王
    28. Card c1 = new Card("","👨",14); //大王
    29. Card c2 = new Card("","👩",13); //小王
    30. Collections.addAll(allCards,c1,c2); //存到集合中
    31. System.out.println("一副新牌:"+allCards);
    32. }
    33. //启动游戏
    34. public void start() {
    35. //洗牌
    36. Collections.shuffle(allCards);
    37. //创建三个玩家的手牌集合
    38. List user1 = new ArrayList<>();
    39. List user2 = new ArrayList<>();
    40. List user3 = new ArrayList<>();
    41. //发牌
    42. //最后要剩余三张
    43. for (int i = 0; i < allCards.size() - 3; i++) {
    44. if(i%3==0){
    45. user1.add(allCards.get(i));
    46. }else if(i%3==1){
    47. user2.add(allCards.get(i));
    48. }else{
    49. user3.add(allCards.get(i));
    50. }
    51. }
    52. //给玩家的牌进行降序排序
    53. sortCards(user1);
    54. sortCards(user2);
    55. sortCards(user3);
    56. //玩家手牌情况
    57. sortCards(user1);
    58. System.out.println("玩家1的手牌:" + user1);
    59. System.out.println("玩家2的手牌:" + user2);
    60. System.out.println("玩家3的手牌:" + user3);
    61. //底牌
    62. //System.out.println("底牌:" + allCards.get(51) + allCards.get(52) + allCards.get(53));
    63. List diPai = allCards.subList(allCards.size()-3,allCards.size()); //截取集合的最后三个元素
    64. System.out.println("底牌:" + diPai);
    65. //抢地主(假设抢地主的规则是:随机生成0 1 2,匹配地主)
    66. Random r = new Random();
    67. int diZhu = r.nextInt(3); //随机生成0,1,2
    68. if(diZhu==0){
    69. user1.addAll(diPai);
    70. sortCards(user1);
    71. System.out.println("玩家1抢地主后的手牌是:" + user1);
    72. }else if (diZhu==1){
    73. user2.addAll(diPai);
    74. sortCards(user2);
    75. System.out.println("玩家2抢地主后的手牌是:" + user2);
    76. }else{
    77. user3.addAll(diPai);
    78. sortCards(user3);
    79. System.out.println("玩家3抢地主后的手牌是:" + user3);
    80. }
    81. }
    82. private void sortCards(List user) {
    83. Collections.sort(user, new Comparator() {
    84. @Override
    85. public int compare(Card o1, Card o2) {
    86. //return o1.getSize() - o2.getSize(); //升序排列
    87. return o2.getSize() - o1.getSize(); //降序排列
    88. }
    89. });
    90. }
    91. }
    92. //Card
    93. public class Card {
    94. private String number;
    95. private String color;
    96. //每张牌存在大小
    97. private int size; //0,1,2……
    98. public Card() {
    99. }
    100. public Card(String number, String color, int size) {
    101. this.number = number;
    102. this.color = color;
    103. this.size = size;
    104. }
    105. public String getNumber() {
    106. return number;
    107. }
    108. public void setNumber(String number) {
    109. this.number = number;
    110. }
    111. public String getColor() {
    112. return color;
    113. }
    114. public void setColor(String color) {
    115. this.color = color;
    116. }
    117. public int getSize() {
    118. return size;
    119. }
    120. public void setSize(int size) {
    121. this.size = size;
    122. }
    123. @Override
    124. public String toString() {
    125. return color + number;
    126. }
    127. }

    二. Map集合

    · Map集合称为双列集合,格式:{key1=value1,key2=value2,key3=value3,…},一次需要存一对数据作为一个元素

    · Map集合的每个元素“key=value”称为一个键值对/键值对对象/一个Entry对象,Map集合也被叫做“键值对集合

    · Map集合的所有键是不允许重复的,但值可以重复,键和值是一一对应的,每一个键只能找到自己对应的值

    Map集合的应用场景

            需要存储一一对应的数据时,就可以考虑使用Map集合来做

    Map集合体系

    Map集合体系的特点

    注意:Map系列集合的特点都是由键决定的,值知识一个附属品,值是不做要求的

    · HashMap(由键决定特点):无序、不重复、无索引(用的最多)

    · LinkedHashMap(由键决定特点):有序、不重复、无索引

    · TreeMap(由键决定特点):按照键的大小默认升序排序、不重复、无索引

    1. //demo
    2. public class demo{
    3. public static void main(String[] args){
    4. Map map = new HashMap<>(); //多态
    5. map.put("哇哈哈",3);
    6. map.put("哇哈哈",2); //重复数据(键重复),后加的数据会覆盖前加的
    7. map.put("冰红茶",3);
    8. map.put("农夫山泉",2);
    9. map.put(null,null);
    10. System.out.println(map); //{null=null, 农夫山泉=2, 冰红茶=3, 哇哈哈=2} 无序,不重复,无索引
    11. Map map2 = new LinkedHashMap<>(); //多态
    12. map2.put("哇哈哈",3);
    13. map2.put("哇哈哈",2); //重复数据(键重复),后加的数据会覆盖前加的
    14. map2.put("冰红茶",3);
    15. map2.put("农夫山泉",2);
    16. map2.put(null,null);
    17. System.out.println(map2); //{哇哈哈=2, 冰红茶=3, 农夫山泉=2, null=null} 有序,不重复,无索引
    18. Map map3 = new TreeMap<>(); //多态
    19. map3.put(1,"哇哈哈");
    20. map3.put(2,"哇哈哈"); //重复数据(键重复),后加的数据会覆盖前加的
    21. map3.put(3,"冰红茶");
    22. map3.put(4,"农夫山泉");
    23. System.out.println(map3); //{1=哇哈哈, 2=哇哈哈, 3=冰红茶, 4=农夫山泉} 按照大小默认升序排序、不重复、无索引
    24. }
    25. }

    2.1 Map集合常用方法 

            Map是双列集合的祖宗,它的功能是全部双列集合都可以继承过来使用的

    方法名称说明
    public V put(K key,V value)添加元素
    public int size()获取集合的大小
    public void clear()清空集合
    public boolean isEmpty()判断集合是否为空,为空返回true,反之返回false
    public V get(Object key)根据键获取对应值
    public V remove(Object key)根据键删除整个元素(删除键会返回键的值)
    public boolean containsKey(Object key)判断是否包含某个键,包含返回true,反之返回false
    public boolean containsValue(Object value)判断是否包含某个值

    public Set keySet()

    获取Map集合的全部键
    public Collection values()获取Map集合的全部值
    1. //demo
    2. public class demo{
    3. public static void main(String[] args){
    4. Map map = new HashMap<>(); //多态
    5. //1.添加元素
    6. map.put("哇哈哈",3);
    7. map.put("哇哈哈",2); //重复数据(键重复),后加的数据会覆盖前加的
    8. map.put("冰红茶",3);
    9. map.put("农夫山泉",2);
    10. map.put(null,null);
    11. System.out.println(map); //{null=null, 农夫山泉=2, 冰红茶=3, 哇哈哈=2} 无序,不重复,无索引
    12. //2.public int size() 获取集合的大小
    13. System.out.println(map.size()); //4
    14. //3.public void clear() 清空集合
    15. // map.clear();
    16. // System.out.println(map); //{}
    17. //4.public boolean isEmpty() 判断集合是否为空,为空返回true,反之返回false
    18. // System.out.println(map.isEmpty()); //true
    19. //5.public V get(Object key) 根据键获取对应值
    20. System.out.println(map.get("哇哈哈")); //2
    21. System.out.println(map.get("冰红茶")); //3
    22. System.out.println(map.get(null)); //null
    23. System.out.println(map.get("怡宝")); //null 根据键获取值的时候,如果键不存在,返回值也是null
    24. //6.public V remove(Object key) 根据键删除整个元素(删除键会返回键的值)
    25. System.out.println(map.remove(null)); //null
    26. System.out.println(map); //{农夫山泉=2, 冰红茶=3, 哇哈哈=2}
    27. //7.public boolean containsKey(Object key) 判断是否包含某个键,包含返回true,反之返回false
    28. System.out.println(map.containsKey("农夫山泉")); //true
    29. System.out.println(map.containsKey("怡宝")); //false
    30. //8.public boolean containsValue(Object value) 判断是否包含某个值
    31. System.out.println(map.containsValue(2)); //true
    32. System.out.println(map.containsValue(5)); //false
    33. System.out.println(map.containsValue("2")); //false 要精确类型,整型2包含,字符2不包含
    34. //9.public Set keySet() 获取Map集合的全部键 返回是set集合(无序 不重复 无索引)
    35. System.out.println(map.keySet()); //[农夫山泉, 冰红茶, 哇哈哈]
    36. //10.public Collection values() 获取Map集合的全部值 返回是Collection集合(因为键值对的值是可重复)
    37. System.out.println(map.values()); //[2, 3, 2]
    38. //11.把其他Map集合的数据倒入到自己集合中来
    39. Map map1 = new HashMap<>();
    40. map1.put("绿茶",3);
    41. map1.put("元气森林",5);
    42. Map map2 = new HashMap<>();
    43. map2.put("脉动",5);
    44. map2.put("绿茶",4);
    45. System.out.println(map1); //{绿茶=3, 元气森林=5}
    46. System.out.println(map2); //{脉动=5, 绿茶=4}
    47. map1.putAll(map2); //把map2集合中的元素全部倒入一份到map1集合中去(map2不会改变,相当于把map2的数据复制了一份给map1)
    48. System.out.println(map1); //{脉动=5, 绿茶=4, 元气森林=5}
    49. System.out.println(map2); //{脉动=5, 绿茶=4}
    50. }
    51. }

    2.2 Map集合遍历方式

    2.2.1 键找值

            先获取Map集合全部的键,再通过遍历键来找值

    2.2.2 键值对

            把键值对堪称一个整体进行遍历

    2.2.3 Lambda表达式

            JDK1.8开始之后的新技术

    1. //demo
    2. public class demo{
    3. public static void main(String[] args){
    4. Map map = new HashMap<>(); //多态
    5. //添加元素
    6. map.put("哇哈哈",3.0);
    7. map.put("哇哈哈",2.0); //重复数据(键重复),后加的数据会覆盖前加的
    8. map.put("冰红茶",3.0);
    9. map.put("农夫山泉",2.5);
    10. map.put("脉动",5.5);
    11. System.out.println(map); //{脉动=5.5, 农夫山泉=2.5, 冰红茶=3.0, 哇哈哈=2.0} 无序,不重复,无索引
    12. System.out.println("-----------------------------");
    13. //Map集合遍历方式1——键找值
    14. //先获取Map集合全部的键
    15. Set keys_Set = map.keySet();
    16. System.out.println(keys_Set); //[脉动, 农夫山泉, 冰红茶, 哇哈哈]
    17. //再通过遍历键来找值,根据键获取其对应的值
    18. for (String s : keys_Set) {
    19. double value = map.get(s);
    20. System.out.println(s+" "+value+"元");
    21. }
    22. System.out.println("-----------------------------");
    23. //Map集合遍历方式2——键值对
    24. //把键值对堪称一个整体进行遍历
    25. //输入map.entrySet()后直接ctrl+alt+v 生成 Set> entries = map.entrySet();
    26. Set> entries = map.entrySet();
    27. System.out.println(entries); //[脉动=5.5, 农夫山泉=2.5, 冰红茶=3.0, 哇哈哈=2.0]
    28. for (Map.Entry entry : entries) {
    29. String key = entry.getKey();
    30. double value = entry.getValue();
    31. System.out.println(key+" "+value+"元");
    32. }
    33. System.out.println("-----------------------------");
    34. //Map集合遍历方式3——Lambda表达式
    35. //JDK1.8开始之后的新技术
    36. map.forEach(new BiConsumer() {
    37. @Override
    38. public void accept(String s, Double aDouble) {
    39. System.out.println(s+" "+aDouble+"元");
    40. }
    41. });
    42. //简化
    43. System.out.println("-----------------------------");
    44. map.forEach((s,aDouble) -> System.out.println(s+" "+aDouble+"元")); //map.forEach((k,v) -> System.out.println(k+" "+v+"元"));
    45. }
    46. }

    2.2.4 案例

    1. //demo
    2. public class demo{
    3. public static void main(String[] args){
    4. List list = new ArrayList<>(); //用一个list存放学生的投票结果
    5. Random r = new Random();
    6. for (int i = 0; i < 80; i++) {
    7. int choose = r.nextInt(4); //随机生成整数0,1,2,3
    8. switch (choose){
    9. case 0:
    10. list.add('A');
    11. break;
    12. case 1:
    13. list.add('B');
    14. break;
    15. case 2:
    16. list.add('C');
    17. break;
    18. case 3:
    19. list.add('D');
    20. break;
    21. default:
    22. System.out.println("学生的选择不存在~~~");
    23. }
    24. }
    25. System.out.println(list);
    26. Map map = new HashMap<>(); //创建一个map集合存放投票统计结果
    27. for (int i = 0; i < list.size(); i++) {
    28. char key = list.get(i); //用key保存当前的字符
    29. //判断是否包含某个键(c的值)
    30. if(map.containsKey(key)){ //包含(说明这个景点统计过)
    31. map.put(key,map.get(key)+1); //get方法返回的是键对应的值
    32. }else{ //不包含(说明这个景点没统计过)
    33. map.put(key,1);
    34. }
    35. }
    36. System.out.println(map);
    37. }
    38. }

    2.3 HashMap

    HashMap集合的特点

            HashMap(由键决定特点):无序、不重复、无索引(用的最多)

    HashMap集合的底层原理

            HashMap跟HashSet的底层原理是一致的,都是基于哈希表实现的(实际上,Set系列集合的底层就是基于Map实现的,只是Set集合中的元素只要键数据,不要值数据

            HashMap集合是一种增删改查数据,性能都较好的集合

            HashMap的键依赖hashCode方法和equals方法保证键的唯一

            如果键存储的是自定义类型的对象,可以通过重写hashCode和equals方法,这样可以保证多个对象内容一样时,HashMap集合就能认为是重复的

    哈希表

            JDK8之前,哈希表=数组+链表

            JDK8开始,哈希表=数组+链表+红黑树

             哈希表是一种增删改查数据,性能都较好的数据结构

    1. //demo
    2. public class demo{
    3. public static void main(String[] args){
    4. Map map = new HashMap<>();
    5. map.put(new Car("奔驰",13.14),"made in C");
    6. map.put(new Car("奔驰",13.14),"made in H");
    7. map.put(new Car("宝马",13.13),"made in C");
    8. System.out.println(map);
    9. //如果不重写HashCode方法和equals方法,会保存两个Car{name='奔驰', price=13.14}数据
    10. //{Car{name='奔驰', price=13.14}=made in H, Car{name='奔驰', price=13.14}=made in C, Car{name='宝马', price=13.13}=made in C}
    11. //重写后
    12. //{Car{name='宝马', price=13.13}=made in C, Car{name='奔驰', price=13.14}=made in H}
    13. }
    14. }
    15. //Car
    16. public class Car implements Comparable {
    17. private String name;
    18. private double price;
    19. //this代表主调 o是被调
    20. @Override
    21. public int compareTo(Car o) {
    22. //如果认为左边对象大于右边对象返回正整数
    23. //如果认为左边对象小于右边对象返回负整数
    24. //如果认为左边对象等于右边对象返回0
    25. //需求:按照价格升序排序
    26. //return (int)(this.price-o.price); //不能这样写,返回值是int类型,两个double类型相减之后强转可能会出bug
    27. //写法1
    28. // if(this.price>o.price){
    29. // return 1;
    30. // }else if(this.price
    31. // return -1;
    32. // }else{
    33. // return 0;
    34. // }
    35. //写法2
    36. return Double.compare(this.price,o.price);
    37. }
    38. //右键->生成->equals()和hashCode()
    39. @Override
    40. public boolean equals(Object o) {
    41. if (this == o) return true;
    42. if (o == null || getClass() != o.getClass()) return false;
    43. Car car = (Car) o;
    44. return Double.compare(car.price, price) == 0 &&
    45. Objects.equals(name, car.name);
    46. }
    47. @Override
    48. public int hashCode() {
    49. return Objects.hash(name, price);
    50. }
    51. public Car() {
    52. }
    53. public Car(String name, double price) {
    54. this.name = name;
    55. this.price = price;
    56. }
    57. public String getName() {
    58. return name;
    59. }
    60. public void setName(String name) {
    61. this.name = name;
    62. }
    63. public double getPrice() {
    64. return price;
    65. }
    66. public void setPrice(double price) {
    67. this.price = price;
    68. }
    69. @Override
    70. public String toString() {
    71. return "Car{" +
    72. "name='" + name + '\'' +
    73. ", price=" + price +
    74. '}';
    75. }
    76. }

    2.4 LinkedHashMap

    LinkedHashMap集合的特点

            LinkedHashMap(由键决定特点):有序、不重复、无索引

    LinkedHashMap集合的底层原理

            LinkedHashMap集合也是基于哈希表(数组、链表、红黑树)实现的,但是它的每个元素都额外的多了一个双链表的机制记录它前后元素的位置(保证有序

            实际上,LinkedHashSet集合的底层原理就是LinkedHashMap

    2.5 TreeMap

    TreeMap集合的特点

            TreeMap(由键决定特点):按照键的大小默认升序排序(只能对键排序)、不重复、无索引

    TreeMap集合的底层原理

            TreeMap和TreeSet集合的底层原理是一样的,都是基于红黑树实现的排序

    注意:

            · 对于数值类型:Integer,Double,默认按照数值本身的大小进行升序排序

            · 对于字符串类型:默认按照首字符的编号升序排序

            · 对于自定义类型如Student对象,TreeSet默认是无法直接排序的

    TreeMap集合支持两种方式来指定排序规则

    方式一

    · 让自定义的类实现Comparable接口重写里面的compareTo方法来指定比较规则

    方式二

    · 通过调用TreeSet集合有参数构造器,可以设置Comparator对象(比较器对象),用于指定比较规则

            public TreeSet(Comparator comparator)

    1. //demo
    2. public class demo{
    3. public static void main(String[] args){
    4. Map map = new TreeMap<>(new Comparator() {
    5. @Override
    6. public int compare(Car o1, Car o2) {
    7. return Double.compare(o2.getPrice(),o1.getPrice()); //降序
    8. }
    9. });
    10. // Map map = new TreeMap<>((o1, o2) -> Double.compare(o2.getPrice(),o1.getPrice()));
    11. map.put(new Car("奔驰",13.14),"made in C");
    12. map.put(new Car("奔驰",13.14),"made in H");
    13. map.put(new Car("宝马",13.13),"made in C");
    14. System.out.println(map);
    15. //对于自定义类型,TreeSet默认是无法直接排序的,会产生ClassCastException异常
    16. //升序:{Car{name='宝马', price=13.13}=made in C, Car{name='奔驰', price=13.14}=made in H}
    17. //降序:{Car{name='奔驰', price=13.14}=made in H, Car{name='宝马', price=13.13}=made in C}
    18. }
    19. }
    20. //Car
    21. public class Car implements Comparable {
    22. private String name;
    23. private double price;
    24. //this代表主调 o是被调
    25. @Override
    26. public int compareTo(Car o) {
    27. //如果认为左边对象大于右边对象返回正整数
    28. //如果认为左边对象小于右边对象返回负整数
    29. //如果认为左边对象等于右边对象返回0
    30. //需求:按照价格升序排序
    31. return Double.compare(this.price,o.price);
    32. }
    33. //右键->生成->equals()和hashCode()
    34. @Override
    35. public boolean equals(Object o) {
    36. if (this == o) return true;
    37. if (o == null || getClass() != o.getClass()) return false;
    38. Car car = (Car) o;
    39. return Double.compare(car.price, price) == 0 &&
    40. Objects.equals(name, car.name);
    41. }
    42. @Override
    43. public int hashCode() {
    44. return Objects.hash(name, price);
    45. }
    46. public Car() {
    47. }
    48. public Car(String name, double price) {
    49. this.name = name;
    50. this.price = price;
    51. }
    52. public String getName() {
    53. return name;
    54. }
    55. public void setName(String name) {
    56. this.name = name;
    57. }
    58. public double getPrice() {
    59. return price;
    60. }
    61. public void setPrice(double price) {
    62. this.price = price;
    63. }
    64. @Override
    65. public String toString() {
    66. return "Car{" +
    67. "name='" + name + '\'' +
    68. ", price=" + price +
    69. '}';
    70. }
    71. }

    2.6 集合的嵌套

            集合的嵌套指的是集合中的元素又是一个集合

    1. //demo
    2. public class demo{
    3. public static void main(String[] args){
    4. Set set1 = new HashSet<>();
    5. // set1.add("南京市");
    6. // set1.add("扬州市");
    7. // set1.add("苏州市");
    8. //用Collection批量加入
    9. Collections.addAll(set1,"南京市","扬州市","苏州市");
    10. Set set2 = new HashSet<>();
    11. // set2.add("武汉市");
    12. // set2.add("宜昌市");
    13. // set2.add("鄂州市");
    14. Collections.addAll(set2,"武汉市","宜昌市","鄂州市");
    15. Map> map = new HashMap<>();
    16. map.put("江苏省",set1);
    17. map.put("湖北省",set2);
    18. System.out.println(map);
    19. System.out.println("湖北省:"+map.get("湖北省"));
    20. //Lambda表达式 遍历
    21. map.forEach((k,v) -> System.out.println(k+":"+v));
    22. }
    23. }

    三. Stream流

            Stream也叫Stream流,是JDK8开始新增的一套API(java.util.stream.*),可以用于操作集合或者数组的数据

    优势:Stream流大量的结合了Lambda的语法风格来编程,提供了一种更加强大,更加简单的方式操作集合或者数组中的数据,代码更简洁,可读性更好

    1. //demo
    2. public class demo{
    3. public static void main(String[] args){
    4. List names = new ArrayList<>();
    5. Collections.addAll(names,"张三","李四","张二二","王五","张老六");
    6. System.out.println(names); //[张三, 李四, 张二二, 王五, 张老六]
    7. //找出姓张,且是3个字的名字,存入到一个新集合中
    8. List name_Zhang = new ArrayList<>();
    9. for (String name : names) {
    10. if(name.startsWith("张") && name.length()==3){
    11. name_Zhang.add(name);
    12. }
    13. }
    14. System.out.println(name_Zhang); //[张二二, 张老六]
    15. //用Stream流实现
    16. List name_Z = names.stream().filter(s -> s.startsWith("张"))
    17. .filter(s -> s.length()==3).collect(Collectors.toList());
    18. System.out.println(name_Z); //[张二二, 张老六]
    19. }
    20. }

    3.1 获取Stream流

            获取集合的Stream流

    Collection提供的方法说明
    default Stream stream()获取当前集合对象的Stream流

            获取数组的Stream流

    Arrays类提供的方法说明
    public static Stream stream(T[] array)获取当前数组的Stream流
    Stream类提供的方法说明
    public static Stream of(T… values)获取当前接收数据的Stream流
    1. //demo
    2. public class demo{
    3. public static void main(String[] args){
    4. //List集合的Stream流
    5. List names1 = new ArrayList<>();
    6. Collections.addAll(names1,"张三","李四","张二二","王五","张老六");
    7. System.out.println(names1); //[张三, 李四, 张二二, 王五, 张老六]
    8. Stream stream1 = names1.stream();
    9. stream1.filter(s -> s.length()==2).forEach(s -> System.out.println(s));
    10. System.out.println("====================================");
    11. //Set集合的Stream流
    12. Set names2 = new HashSet<>();
    13. Collections.addAll(names2,"周一","周二","周三","周末","小周");
    14. System.out.println(names2); //[周一, 小周, 周末, 周三, 周二]
    15. Stream stream2 = names2.stream();
    16. stream2.filter(s -> s.startsWith("周")).forEach(s -> System.out.println(s));
    17. System.out.println("====================================");
    18. //Map集合的Stream流
    19. Map map = new HashMap<>();
    20. map.put("哇哈哈",3.0);
    21. map.put("冰红茶",3.0);
    22. map.put("农夫山泉",2.5);
    23. map.put("脉动",5.5);
    24. System.out.println(map); //{脉动=5.5, 农夫山泉=2.5, 冰红茶=3.0, 哇哈哈=3.0}
    25. //不能直接map.stream(),因为stream()方法是Collection提供的
    26. Set keys = map.keySet();
    27. Stream ks = keys.stream();
    28. Collection values = map.values();
    29. Stream vs = values.stream();
    30. Set> entries = map.entrySet();
    31. Stream> kvs = entries.stream();
    32. kvs.filter(e -> e.getKey().contains("哈")).forEach(s -> System.out.println(s));
    33. System.out.println("====================================");
    34. //数组的Stream流
    35. String[] names3 = {"Nike","Nim","Mike","Helen"};
    36. System.out.println(Arrays.toString(names3));
    37. Stream stream3 = Arrays.stream(names3);
    38. Stream stream3_1 = Stream.of(names3);
    39. stream3.filter(s->s.contains("i")).forEach(s-> System.out.println(s));
    40. System.out.println("====================================");
    41. stream3_1.filter(s->s.length()==5).forEach(s-> System.out.println(s));
    42. }
    43. }

    3.2 Stream流常见的中间方法

            中间方法指的是调用完成后会返回新的Stream流,可以继续使用(支持链式编程)

    Stream提供的常用中间方法说明
    Stream filter(Predicate predicate)用于对流中的数据进行过滤
    Stream sorted()对元素进行升序排序
    Stream sorted(Comparator comparator)按照指定规则排序
    Stream limit(long maxSize)获取前几个元素
    Stream skip(long n)跳过前几个元素
    Stream distinct()去除流中重复的元素
    Stream map(Function mapper)对元素进行加工,并返回对应的新流
    static Stream concat(Stream a , Stream b)合并a和b两个流为一个流
    1. //demo
    2. public class demo{
    3. public static void main(String[] args){
    4. List prices = new ArrayList<>();
    5. Collections.addAll(prices,12.13,13.0,15.0,17.0,15.4,11.0);
    6. //需求:找出价格超过15的数据,并升序排序,再输出
    7. prices.stream().filter(s -> s>=15).sorted().forEach(s -> System.out.println(s));
    8. System.out.println("========================================");
    9. List students = new ArrayList<>();
    10. Student s1 = new Student("张三","男",79,22);
    11. Student s2 = new Student("张三","男",79,22);
    12. Student s3 = new Student("李四","男",89.5,21);
    13. Student s4 = new Student("王五","男",98,21);
    14. Student s5 = new Student("小美","女",57.5,21);
    15. Student s6 = new Student("小新","女",100,20);
    16. Student s7 = new Student("小海","男",88,19);
    17. Collections.addAll(students,s1,s2,s3,s4,s5,s6,s7);
    18. //需求:找出成绩在85-95(包括85和95)之间的学生,并按照成绩降序排序
    19. students.stream().filter(s -> s.getScore()>=85 && s.getScore()<=95)
    20. .sorted((o1, o2) -> Double.compare(o2.getScore(),o1.getScore()))
    21. .forEach(s -> System.out.println(s));
    22. System.out.println("========================================");
    23. //需求:取出成绩前三的学生,并输出
    24. //先按照成绩降序排序再取出前三名
    25. students.stream().sorted((o1,o2)->Double.compare(o2.getScore(),o1.getScore()))
    26. .limit(3).forEach(s -> System.out.println(s));
    27. System.out.println("========================================");
    28. //需求:取出年纪最小的两个学生,并输出
    29. students.stream().sorted((o1,o2) -> o1.getAge()-o2.getAge())
    30. .limit(2).forEach(s -> System.out.println(s));
    31. System.out.println("========================================");
    32. //需求:取出年纪最大的两个学生,并输出
    33. students.stream().sorted((o1,o2) -> o1.getAge()-o2.getAge())
    34. .skip(students.size()-2).forEach(s -> System.out.println(s));
    35. System.out.println("========================================");
    36. //需求:找出年纪大于20岁的学生叫什么名字,要求去除重复名字,再输出
    37. students.stream().filter(s -> s.getAge() > 20)
    38. .map(s -> s.getName()) //把这个流加工成只剩下名字
    39. .distinct().forEach(s -> System.out.println(s));
    40. //distinct去重复,针对自定义类型的对象,如果希望内容一样就认为重复,需要重写HashCode和equals方法,不重写就不会去重复
    41. students.stream().filter(s -> s.getAge() > 20)
    42. .distinct().forEach(s -> System.out.println(s));
    43. Stream st1 = Stream.of("张三","李四"); //Stream.of()获取数组的stream流
    44. Stream st2 = Stream.of("王五","李四");
    45. Stream.concat(st1,st2).forEach(System.out::println);
    46. Stream st3 = Stream.of(1,2,3);
    47. Stream st4 = Stream.of(5.2,7.7);
    48. Stream.concat(st3,st4).forEach(System.out::println);
    49. }
    50. }
    51. //Student
    52. public class Student {
    53. private String name; //姓名
    54. private String sex; //性别
    55. private double score; //成绩
    56. private int age; //年龄
    57. public Student() {
    58. }
    59. public Student(String name, String sex, double score, int age) {
    60. this.name = name;
    61. this.sex = sex;
    62. this.score = score;
    63. this.age = age;
    64. }
    65. @Override
    66. public boolean equals(Object o) {
    67. if (this == o) return true;
    68. if (o == null || getClass() != o.getClass()) return false;
    69. Student student = (Student) o;
    70. return Double.compare(student.score, score) == 0 &&
    71. age == student.age &&
    72. Objects.equals(name, student.name) &&
    73. Objects.equals(sex, student.sex);
    74. }
    75. @Override
    76. public int hashCode() {
    77. return Objects.hash(name, sex, score, age);
    78. }
    79. public String getName() {
    80. return name;
    81. }
    82. public void setName(String name) {
    83. this.name = name;
    84. }
    85. public String getSex() {
    86. return sex;
    87. }
    88. public void setSex(String sex) {
    89. this.sex = sex;
    90. }
    91. public double getScore() {
    92. return score;
    93. }
    94. public void setScore(double score) {
    95. this.score = score;
    96. }
    97. public int getAge() {
    98. return age;
    99. }
    100. public void setAge(int age) {
    101. this.age = age;
    102. }
    103. @Override
    104. public String toString() {
    105. return "Student{" +
    106. "name='" + name + '\'' +
    107. ", sex='" + sex + '\'' +
    108. ", score=" + score +
    109. ", age=" + age +
    110. '}';
    111. }
    112. }

    3.3 Stream流常见的终结方法

            终结方法指的是调用完成后,不会返回新Stream了,没有继续使用流了

    Stream提供的常用终结方法说明
    void forEach(Consumer action)对此流运算后的元素执行遍历
    long count()统计此流运算后的元素个数
    Optional max(Comparator comparator)获取此流运算后的最大值元素
    Optional min(Comparator comparator)获取此流运算后的最小值元素

    收集Stream流

            收集Stream流就是把Stream流操作后的结果转回到集合或者数组中去返回

            Stream流:方便操作集合/数组的手段;  集合/数组:才是开发中的目的

    Stream提供的常用终结方法说明
    R collect(Collector collector)把流处理后的结果收集到一个指定的集合中去
    Object[] toArray()把流处理后的结果收集到一个数组中去
    Collectors工具类提供的具体的收集方法说明
    public static Collector toList()把元素收集到List集合中
    public static Collector toSet()把元素收集到Set集合中
    public static Collector toMap(Function keyMapper , Function valueMapper)把元素收集到Map集合中
    1. //demo
    2. public class demo{
    3. public static void main(String[] args){
    4. List students = new ArrayList<>();
    5. Student s1 = new Student("张三","男",79,22);
    6. Student s2 = new Student("张三","男",79,22);
    7. Student s3 = new Student("李四","男",89.5,21);
    8. Student s4 = new Student("王五","男",98,21);
    9. Student s5 = new Student("小美","女",57.5,21);
    10. Student s6 = new Student("小新","女",100,20);
    11. Student s7 = new Student("小海","男",88,19);
    12. Collections.addAll(students,s1,s2,s3,s4,s5,s6,s7);
    13. //需求:计算出成绩>=90的学生人数
    14. //long count() 统计此流运算后的元素个数
    15. long sum = students.stream().filter(s -> s.getScore()>=90).count();
    16. System.out.println(sum); //2
    17. //需求:找出成绩最高的学生对象并输出
    18. //Optional max(Comparator comparator) 获取此流运算后的最大值元素
    19. Optional o_max = students.stream().max((o1, o2) -> Double.compare(o1.getScore(),o2.getScore()));
    20. System.out.println(o_max); //Optional[Student{name='小新', sex='女', score=100.0, age=20}]
    21. System.out.println(o_max.get()); //Student{name='小新', sex='女', score=100.0, age=20}
    22. //需求:找出成绩最低的学生对象并输出
    23. //Optional min(Comparator comparator) 获取此流运算后的最小值元素
    24. Optional o_min = students.stream().min((o1, o2) -> Double.compare(o1.getScore(),o2.getScore()));
    25. System.out.println(o_min.get()); //Student{name='小美', sex='女', score=57.5, age=21}
    26. //收集Stream流
    27. //需求:找出成绩在75-90之间的学生对象,并放到一个新集合中去返回
    28. //流只能收集一次
    29. //放到List集合中
    30. List list = students.stream().filter(s -> s.getScore()>75 && s.getScore()<90).collect(Collectors.toList());
    31. System.out.println(list);
    32. //[Student{name='张三', sex='男', score=79.0, age=22}, Student{name='张三', sex='男', score=79.0, age=22}, Student{name='李四', sex='男', score=89.5, age=21}, Student{name='小海', sex='男', score=88.0, age=19}]
    33. //放到Set集合中
    34. Set set = students.stream().filter(s -> s.getScore()>75 && s.getScore()<90).collect(Collectors.toSet());
    35. System.out.println(set);
    36. //[Student{name='李四', sex='男', score=89.5, age=21}, Student{name='张三', sex='男', score=79.0, age=22}, Student{name='小海', sex='男', score=88.0, age=19}]
    37. //Set中去把两个张三去重了(因为重写了HashCode和equals方法,不重写则不去重)
    38. //需求:找出成绩在75-90之间的学生对象,并把学生对象的名字和成绩,存放到一个Map集合中返回
    39. Map map = students.stream().filter(s -> s.getScore() > 75 && s.getScore() < 90)
    40. .distinct().collect(Collectors.toMap(k -> k.getName(), v -> v.getScore()));
    41. System.out.println(map); //{李四=89.5, 张三=79.0, 小海=88.0}
    42. Object[] objects = students.stream().filter(s -> s.getScore() > 75 && s.getScore() < 90).toArray();
    43. System.out.println(Arrays.toString(objects));
    44. Student[] stu = students.stream().filter(s -> s.getScore() > 75 && s.getScore() < 90).toArray(len -> new Student[len]);
    45. System.out.println(Arrays.toString(stu));
    46. }
    47. }
    48. //Student
    49. public class Student {
    50. private String name; //姓名
    51. private String sex; //性别
    52. private double score; //成绩
    53. private int age; //年龄
    54. public Student() {
    55. }
    56. public Student(String name, String sex, double score, int age) {
    57. this.name = name;
    58. this.sex = sex;
    59. this.score = score;
    60. this.age = age;
    61. }
    62. @Override
    63. public boolean equals(Object o) {
    64. if (this == o) return true;
    65. if (o == null || getClass() != o.getClass()) return false;
    66. Student student = (Student) o;
    67. return Double.compare(student.score, score) == 0 &&
    68. age == student.age &&
    69. Objects.equals(name, student.name) &&
    70. Objects.equals(sex, student.sex);
    71. }
    72. @Override
    73. public int hashCode() {
    74. return Objects.hash(name, sex, score, age);
    75. }
    76. public String getName() {
    77. return name;
    78. }
    79. public void setName(String name) {
    80. this.name = name;
    81. }
    82. public String getSex() {
    83. return sex;
    84. }
    85. public void setSex(String sex) {
    86. this.sex = sex;
    87. }
    88. public double getScore() {
    89. return score;
    90. }
    91. public void setScore(double score) {
    92. this.score = score;
    93. }
    94. public int getAge() {
    95. return age;
    96. }
    97. public void setAge(int age) {
    98. this.age = age;
    99. }
    100. @Override
    101. public String toString() {
    102. return "Student{" +
    103. "name='" + name + '\'' +
    104. ", sex='" + sex + '\'' +
    105. ", score=" + score +
    106. ", age=" + age +
    107. '}';
    108. }
    109. }
  • 相关阅读:
    Android 查看当前手机、APP的ABI架构信息
    Python实现PPT演示文稿中视频的添加、替换及提取
    Java String.format()方法具有什么功能呢?
    【Matlab】欧拉公式、梯形公式和改进欧拉公式求解常微分方程
    Android11 桌面默认横屏导致任务键近期任务布局UI显示错误!
    rabbitMQ:绑定Exchange发送和接收消息(direct)
    Apache Dubbo的@SPI接口应用
    【python学习】-列表的使用(添加/移除元素、寻找指定元素索引、列表复制等)
    深入理解python虚拟机:程序执行的载体——栈帧
    leetCode 72. 编辑距离 动态规划 + 滚动数组 + 优化空间
  • 原文地址:https://blog.csdn.net/qq_50755868/article/details/136718071