首页 > 其他分享 >05List、Set、Collections类工具

05List、Set、Collections类工具

时间:2022-12-30 14:56:02浏览次数:46  
标签:Set String 05List System add Collections println public out

01 Collection集合的遍历方式

Collection集合的遍历方式有三种:
(1)迭代器。
(2)foreach(增强for循环)。
(3)JDK 1.8开始之后的新技术Lambda表达式(了解)

1. 迭代器

public class CollectionDemo01 {
    public static void main(String[] args) {
        Collection<String> lists = new ArrayList<>();
        lists.add("赵敏");
        lists.add("小昭");
        lists.add("殷素素");
        lists.add("周芷若");
        System.out.println(lists);
        // lists = [赵敏, 小昭, 殷素素, 周芷若]

        // 1.得到集合的迭代器对象。
        Iterator<String> it = lists.iterator();
        //System.out.println(it.next());
        //System.out.println(it.next());
        //System.out.println(it.next());
        //System.out.println(it.next());
        //System.out.println(it.next()); // 出现异常NoSuchElementException,出现没有此元素异常!

        // 2.使用while循环遍历。
        while(it.hasNext()){
            String ele = it.next();
            System.out.println(ele);
        }
    }
}

2. foreach

for (String ele : lists) {
            System.out.println(ele);
        }

3. Lambda

        lists.forEach(s -> {
            System.out.println(s);
        });

02 List集合

Collection集合的体系:
                            Collection<E>(接口)
              /                                                \
           Set<E>(接口)                                         List<E>(接口)
            /                  \                               /                     \                  \
          HashSet<E>(实现类)    TreeSet<E>(实现类)          LinkedList<E>(实现类) Vector(线程安全)     ArrayList<E>(实现类)
          /
         LinkedHashSet<E>(实现类)

List系列集合:添加的元素,是有序,可重复,有索引的。

  • LinkedList: 添加的元素,是有序,可重复,有索引的。

  • ArrayList: 添加的元素,是有序,可重复,有索引的。

  • Vector: 是线程安全的,速度慢,工作中很少使用。

ArrayList实现类集合底层基于数组存储数据的,查询快,增删慢!

  • public void add(int index, E element): 将指定的元素,添加到该集合中的指定位置上。

  • public E get(int index):返回集合中指定位置的元素。

  • public E remove(int index): 移除列表中指定位置的元素, 返回的是被移除的元素。

  • public E set(int index, E element):用指定元素替换集合中指定位置的元素,返回更新前的元素值。

public class ListDemo01 {
    public static void main(String[] args) {
        // 1.创建一个ArrayList集合对象:这是一行经典代码!
        // List:有序,可重复,有索引的。
        List<String> lists = new ArrayList<>();
        lists.add("java1");
        lists.add("java1");
        lists.add("java2");
        lists.add("java2");
        System.out.println(lists);

        // 2.在某个索引位置插入元素。
        lists.add(2,"MySQL");
        System.out.println(lists);

        // 3.根据索引删除元素,返回被删除元素
        System.out.println(lists.remove(2));
        System.out.println(lists);

        // 4.根据索引获取元素
        System.out.println(lists.get(2)); // java2

        // 5.修改索引位置处的元素
        lists.set(3,"Mybatis");
        System.out.println(lists);
    }
}

List遍历方式:
(1)for循环。
(2)迭代器。
(3)foreach。
(4)JDK 1.8新技术。

public class ListDemo02 {
    public static void main(String[] args) {
        List<String> lists = new ArrayList<>();
        lists.add("java1");
        lists.add("java2");
        lists.add("java3");

        /** (1)for循环。 */
        for(int i = 0 ; i < lists.size() ; i++ ) {
            String ele = lists.get(i);
            System.out.println(ele);
        }
        System.out.println("-----------------------");

        /** (2)迭代器。 */
        Iterator<String> it = lists.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }
        System.out.println("-----------------------");

        /** (3)foreach。 */
        for(String ele : lists){
            System.out.println(ele);
        }
        System.out.println("-----------------------");

        /** (4)JDK 1.8开始之后的Lambda表达式*/
        lists.forEach(s -> {
            System.out.println(s);
        });
    }
}

小结:

  • List系列集合有序,可重复,有索引的。

  • ArrayList实现类集合底层基于数组存储数据的,查询快,增删慢!!

  • 开发中ArrayList集合用的最多!!

LinkedList集合

LinkedList也是List的实现类:底层是基于链表的,增删比较快,查询慢!!

LinkedList是支持双链表,定位前后的元素是非常快的,增删首尾的元素也是最快的

所以LinkedList除了拥有List集合的全部功能还多了很多操作首尾元素的特殊功能:

  1. public void addFirst(E e):将指定元素插入此列表的开头。

  2. public void addLast(E e):将指定元素添加到此列表的结尾。

  3. public E getFirst():返回此列表的第一个元素。

  4. public E getLast():返回此列表的最后一个元素。

  5. public E removeFirst():移除并返回此列表的第一个元素。

  6. public E removeLast():移除并返回此列表的最后一个元素。

  7. public E pop():从此列表所表示的堆栈处弹出一个元素。

  8. public void push(E e):将元素推入此列表所表示的堆栈。

public class ListDemo03 {
    public static void main(String[] args) {
        // 1.用LinkedList做一个队列:先进先出,后进后出。
        LinkedList<String> queue = new LinkedList<>();
        // 入队
        queue.addLast("1号");
        queue.addLast("2号");
        queue.addLast("3号");
        queue.addLast("4号");
        System.out.println(queue); // [1号, 2号, 3号, 4号]
        // 出队
        System.out.println(queue.removeFirst());
        System.out.println(queue.removeFirst());
        System.out.println(queue);

        // 做一个栈
        LinkedList<String> stack = new LinkedList<>();
        // 压栈
        stack.push("第1颗子弹");
        stack.push("第2颗子弹");
        stack.push("第3颗子弹");
        stack.push("第4颗子弹");
        System.out.println(stack); // [第4颗子弹, 第3颗子弹, 第2颗子弹, 第1颗子弹]
        // 弹栈
        System.out.println(stack.pop());
        System.out.println(stack.pop());
        System.out.println(stack);


    }
}

小结:

  • LinkedList是支持双链表,定位前后的元素是非常快的,增删首尾的元素也是最快的。

  • 所以提供了很多操作首尾元素的特殊API可以做栈和队列的实现。

  • 如果查询多而增删少用ArrayList集合。(用的最多的)

  • 如果查询少而增删首尾较多用LinkedList集合。

03 Set集合

Set系列集合: 添加的元素,是无序,不重复,无索引的。

  • HashSet:添加的元素,是无序,不重复,无索引的。

  • LinkedHashSet:添加的元素,是有序,不重复,无索引的。

  • TreeSet: 不重复,无索引,按照大小默认升序排序!! ( 可排序集合 )

public class HashSetDemo01 {
    public static void main(String[] args) {
        // 无序,不重复,无索引的。
        Set<String> sets = new HashSet<>(); // 一行经典代码!!
        sets.add("Mybatis");
        sets.add("Java");
        sets.add("Java");
        sets.add("MySQL");
        sets.add("MySQL");
        sets.add("Spring");
        // [Java, MySQL, Spring, Mybatis]
        System.out.println(sets);
    }
}

研究两个问题(面试热点):

  • 1)Set集合添加的元素是不重复的,是如何去重复的?

  • 2)Set集合元素无序的原因是什么?

1) Set集合去重

1.对于有值特性的,Set集合可以直接判断进行去重复。
2.对于引用数据类型的类对象,Set集合是按照如下流程进行是否重复的判断。
        Set集合会让两两对象,先调用自己的hashCode()方法得到彼此的哈希值(所谓的内存地址)
        然后比较两个对象的哈希值是否相同,如果不相同则直接认为两个对象不重复。
        如果哈希值相同,会继续让两个对象进行equals比较内容是否相同,如果相同认为真的重复了
        如果不相同认为不重复。

                Set集合会先让对象调用hashCode()方法获取两个对象的哈希值比较
                   /                     \
                false                    true
                /                          \
            不重复                        继续让两个对象进行equals比较
                                           /          \
                                         false        true
                                          /             \
                                        不重复          重复了

需求:
  只要对象内容一样,就希望集合认为它们重复了。重写hashCode和equals方法。

小结:
  如果希望Set集合认为两个对象只要内容一样就重复了,必须重写对象的hashCode和equals方法。

Apple类

public class Apple {
    private String name;
    private double price ;
    private String color ;

    public Apple() {
    }

    public Apple(String name, double price, String color) {
        this.name = name;
        this.price = price;
        this.color = color;
    }

    // 只要两个对象的内容一样,equals比较的结果一定为true
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Apple apple = (Apple) o;
        return Double.compare(apple.price, price) == 0 &&
                Objects.equals(name, apple.name) &&
                Objects.equals(color, apple.color);
    }

    // 只要两个对象的内容一样返回的哈希值也要一样!true
    @Override
    public int hashCode() {
        // Apple a2 = new Apple("阿克苏",39.9 ,"青红色");
        // Apple a3 = new Apple("阿克苏",39.9 ,"青红色");
        //  a2.hashCode() == Objects.hash(阿克苏, 39.9, 青红色)
        //  a3.hashCode() == Objects.hash(阿克苏, 39.9, 青红色)
        return Objects.hash(name, price, color);
    }

    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取
     * @return price
     */
    public double getPrice() {
        return price;
    }

    /**
     * 设置
     * @param price
     */
    public void setPrice(double price) {
        this.price = price;
    }

    /**
     * 获取
     * @return color
     */
    public String getColor() {
        return color;
    }

    /**
     * 设置
     * @param color
     */
    public void setColor(String color) {
        this.color = color;
    }

    public String toString() {
        return "Apple{name = " + name + ", price = " + price + ", color = " + color + "}";
    }
}

演示代码

public class HashSetDemo02 {
    public static void main(String[] args) {
        Set<Integer> sets = new HashSet<>(); // 一行经典代码!!
        sets.add(1);
        sets.add(1);
        sets.add(2);
        sets.add(2);
        System.out.println(sets);

        // 存储一些自定义类型数据:无序不重复
        Set<Apple> apples = new HashSet<>();
        Apple a1 = new Apple("红富士",59.9 ,"红色");
        Apple a2 = new Apple("阿克苏",39.9 ,"青红色");
        Apple a3 = new Apple("阿克苏",39.9 ,"青红色");
        System.out.println(a1.hashCode()); // 哈希值,相当于是内存地址
        System.out.println(a2.hashCode()); // 哈希值,相当于是内存地址
        System.out.println(a3.hashCode()); // 哈希值,相当于是内存地址
        apples.add(a1);
        apples.add(a2);
        apples.add(a3);
        System.out.println(apples);

    }
}

2)Set集合无序原因

Set系列集合添加元素无序的根本原因是因为底层采用了哈希表存储元素。

  • JDK 1.8之前:哈希表 = 数组 + 链表 + (哈希算法)

  • JDK 1.8之后:哈希表 = 数组 + 链表 + 红黑树 + (哈希算法)
    当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。

LinkedHashSet
LinkedHashSet底层依然是使用哈希表存储元素的,但是每个元素都额外带一个链来维护添加顺序!!

不光增删查快,还有序。缺点是多了一个存储顺序的链会占内存空间!!而且不允许重复,无索引。

public class HashSetDemo04 {
    public static void main(String[] args) {
        // 有序不重复无索引
        Set<String> sets = new LinkedHashSet<>();
        sets.add("Mybatis");
        sets.add("Java");
        sets.add("Java");
        sets.add("MySQL");
        sets.add("MySQL");
        sets.add("Spring");
        // [Java, MySQL, Spring, Mybatis]
        System.out.println(sets);
    }
}

总结:

  • 如果希望元素可以重复,又有索引,查询要快用ArrayList集合。(用的最多)

  • 如果希望元素可以重复,又有索引,增删要快要用LinkedList集合。(适合查询元素比较少的情况,经常要首尾操作元素的情况)

  • 如果希望增删改查都很快,但是元素不重复以及无序无索引,那么用HashSet集合。

  • 如果希望增删改查都很快且有序,但是元素不重复以及无索引,那么用LinkedHashSet集合。

TreeSet集合

TreeSet: 不重复,无索引,按照大小默认升序排序!!

TreeSet集合自自排序的方式:

  • 有值特性的元素直接可以升序排序。(浮点型,整型)

  • 字符串类型的元素会按照首字符的编号排序。

  • 对于自定义的引用数据类型,TreeSet默认无法排序,执行的时候直接报错,因为人家不知道排序规则。

自定义的引用数据类型的排序实现:

对于自定义的引用数据类型,TreeSet默认无法排序
        所以我们需要定制排序的大小规则,程序员定义大小规则的方案有2种:
        a.直接为对象的类实现比较器规则接口Comparable,重写比较方法(拓展方式)
             // 如果程序员认为比较者大于被比较者 返回正数!
             // 如果程序员认为比较者小于被比较者 返回负数!
             // 如果程序员认为比较者等于被比较者 返回0!

        b.直接为集合设置比较器Comparator对象,重写比较方法
             // 如果程序员认为比较者大于被比较者 返回正数!
             // 如果程序员认为比较者小于被比较者 返回负数!
             // 如果程序员认为比较者等于被比较者 返回0!
        注意:如果类和集合都带有比较规则,优先使用集合自带的比较规则。

Employee类

public class Employee implements Comparable<Employee>{
    private String name;
    private double salary;
    private int age;

    // 重写了比较方法。
    // e1.compareTo(o)
    // 比较者:this
    // 被比较者:o
    // 需求:按照年龄比较
    @Override
    public int compareTo(Employee o) {
        // 规则:Java规则
        // 如果程序员认为比较者大于被比较者 返回正数!
        // 如果程序员认为比较者小于被比较者 返回负数!
        // 如果程序员认为比较者等于被比较者 返回0!
//        if(this.age > o.age){
//            return 1;
//        }else if(this.age < o.age){
//            return -1;
//        }
//        return 0;
        return this.age - o.age;
    }

    public Employee() {
    }

    public Employee(String name, double salary, int age) {
        this.name = name;
        this.salary = salary;
        this.age = age;
    }

    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取
     * @return salary
     */
    public double getSalary() {
        return salary;
    }

    /**
     * 设置
     * @param salary
     */
    public void setSalary(double salary) {
        this.salary = salary;
    }

    /**
     * 获取
     * @return age
     */
    public int getAge() {
        return age;
    }

    /**
     * 设置
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }

    public String toString() {
        return "Employee{name = " + name + ", salary = " + salary + ", age = " + age + "}";
    }


}

演示代码

public class TreeSetDemo05 {
    public static void main(String[] args) {
        // TreeSet : 排序不重复集合。
        Set<Double> scores = new TreeSet<>();
        scores.add(100.0);
        scores.add(99.9);
        scores.add(69.5);
        scores.add(0.1);
        scores.add(89.3);
        System.out.println(scores);

        // 字符串按照首字符的编号进行排序。
        Set<String> names = new TreeSet<>();
        names.add("Jack");
        names.add("rose");
        names.add("Dlei");
        names.add("about");
        names.add("曹雪芹");
        names.add("bozai");
        names.add("caocao");
        names.add("angel");
        System.out.println(names);

        // 引用数据类型定义TreeSet集合。
        Set<Employee> employees = new TreeSet<>();
        employees.add(new Employee("播仔",6500.0,21));
        employees.add(new Employee("播妞",7500.0,19));
        employees.add(new Employee("乔治",4500.0,23));
        System.out.println(employees);


        // public TreeSet(Comparator<? super E> comparator)
        // 集合自带比较器对象
        // 如果类和集合都存在大小规则,默认使用集合自带的规则进行大小排序!!
        Set<Employee> employees1 = new TreeSet<>(new Comparator<Employee>() {
            @Override
            public int compare(Employee o1, Employee o2) {
                // o1比较者   o2被比较者
                // 如果程序员认为比较者大于被比较者 返回正数!
                // 如果程序员认为比较者小于被比较者 返回负数!
                // 如果程序员认为比较者等于被比较者 返回0!
                return o1.getAge() - o2.getAge();
            }
        });
        employees1.add(new Employee("播仔",6500.0,21));
        employees1.add(new Employee("播妞",7500.0,19));
        employees1.add(new Employee("乔治",4500.0,23));
        System.out.println(employees1);
    }
}

小结:
TreeSet集合对自定义引用数据类型排序,默认无法进行。

但是有两种方式可以让程序员定义大小规则:

  • a.直接为对象的类实现比较器规则接口Comparable,重写比较方法(拓展方式)

  • b.直接为集合设置比较器Comparator对象,重写比较方法

注意:如果类和集合都带有比较规则,优先使用集合自带的比较规则。

04 Collections工具类

Collections有几个常用的API:

  • public static boolean addAll(Collection<? super T> c, T... elements)
    给集合对象批量添加元素!

  • public static void shuffle(List<?> list) :打乱集合顺序。

  • public static void sort(List list):将集合中元素按照默认规则排序。

  • public static void sort(List list,Comparator<? super T> ):将集合中元素按照指定规则排序。

public class CollectionsDemo01 {
    public static void main(String[] args) {
        // 1.给集合批量添加元素
        Collection<String> names = new ArrayList<>();
        /**
         * 参数一:被添加元素的集合
         * 参数二:可变参数,一批元素
         */
        Collections.addAll(names,"曹操","贾乃亮","王宝强","陈羽凡");
        System.out.println(names);

        // 2.打乱集合的顺序:public static void shuffle(List<?> list)
        // 注意:只能打乱有序的List集合。
        List<String> newnames = new ArrayList<>();
        Collections.addAll(newnames,"曹操","贾乃亮","王宝强","陈羽凡");
        Collections.shuffle(newnames); // 打乱顺序
        System.out.println(newnames);

        // 3.public static <T> void sort(List<T> list):给List集合升序排序。
        List<Double> scores = new ArrayList<>();
        Collections.addAll(scores, 98.5, 66.5 , 59.5 , 66.5 , 99.5 );
        Collections.sort(scores); // 默认升序排序!
        System.out.println(scores);
    }
}

自定义数据类型的排序
Oringe类

public class Orange implements Comparable {
    private String name;
    private double weight;
    private String price;

    public Orange() {
    }

    public Orange(String name, double weight, String price) {
        this.name = name;
        this.weight = weight;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getWeight() {
        return weight;
    }

    public void setWeight(double weight) {
        this.weight = weight;
    }

    public String getPrice() {
        return price;
    }

    public void setPrice(String price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "Orange{" +
                "name='" + name + '\'' +
                ", weight=" + weight +
                ", price='" + price + '\'' +
                '}'+"\n";
    }

    @Override
    public int compareTo(Object o) {
        Orange o2 = (Orange) o;
        // 集合会自动送入两个句子对象来比较!!
        // 认为o1 > o2返回正整数。
        // 认为o1 = o2返回0。
        // 认为o1 < o2返回负整数。
        if(this.weight > o2.weight) return 1;
        if(this.weight < o2.weight) return -1;
        return 0;
    }
}

演示代码

public class CollectionsDemo02 {
    public static void main(String[] args) {
        // 自定义类型如何排序!
        List<Orange> oranges = new ArrayList<>();
        Orange o1 = new Orange("红橘子",654.0 ,"贼便宜~");
        Orange o2 = new Orange("黄橘子",454.0 ,"贼便宜~");
        Orange o3 = new Orange("黄橘子",454.0 ,"贼便宜~");
        Orange o4 = new Orange("青橘子",456.0 ,"贼便宜~");
        Collections.addAll(oranges,o1,o2,o3,o4);
        Collections.sort(oranges); // 排序,按照类实现的比较规则进行排序!!
        System.out.println(oranges);


        List<Orange> oranges1 = new ArrayList<>();
        Orange o11 = new Orange("红橘子",654.0 ,"贼便宜~");
        Orange o22 = new Orange("黄橘子",454.0 ,"贼便宜~");
        Orange o33 = new Orange("黄橘子",454.0 ,"贼便宜~");
        Orange o44 = new Orange("青橘子",456.0 ,"贼便宜~");
        Collections.addAll(oranges1,o11,o22,o33,o44);
        // 优先用方法自带的比较器对象Comparator而不会用类的比较规则!!
        Collections.sort(oranges1, new Comparator<Orange>() {
            @Override
            public int compare(Orange o1, Orange o2) {
                if(o1.getWeight() > o2.getWeight()) return -1;
                if(o1.getWeight() < o2.getWeight()) return 1;
                return 0;
            }
        });
        System.out.println(oranges1);
    }
}

05 可变参数

可变参数的作用:

  • 传输参数非常灵活,方便。

  • 可以不传输参数。

  • 可以传输一个参数。

  • 可以传输多个参数。

  • 可以传输一个数组。

可变参数的注意事项:

  • 一个形参列表中可变参数只能有一个!!

  • 可变参数必须放在形参列表的最后面!!

public class MethodDemo {
    public static void main(String[] args) {
        sum(); // 可以不传输参数。
        sum(10); // 可以传输一个参数。
        sum(10,20,30); // 可以传输多个参数。
        sum(new int[]{10,30,50,70,90}); // 可以传输一个数组。
    }

    public static void sum(int...nums){
        // 可变参数在方法内部本质上就是一个数组。
        System.out.println("元素个数:"+nums.length);
        System.out.println("元素内容:"+ Arrays.toString(nums));
        System.out.println("--------------------------");
    }
}


06 斗地主做牌洗牌看牌

Card类

public class Card {
    String number;
    String color;
    int index;

    public Card() {
    }

    public Card(String color, String number, int index) {
        this.number = number;
        this.color = color;
        this.index = index;
    }

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public int getIndex() {
        return index;
    }

    public void setIndex(int index) {
        this.index = index;
    }

    @Override
    public String toString() {
        return color+number;
    }
}

主代码

public class GameDemo {
    public static final List<Card> ALL_CARDS = new ArrayList<>();
    //1.做牌
    static {
        String[] numbers = {"3","4","5","6","7","8","9","10","J","Q","K","A","2"};
        String[] colors = {"♦" ,"♣" ,"♥" ,"♠"};
        int index = 1;
        for (String number : numbers) {
            for (String color : colors) {
                Card card = new Card(color,number,index++);
                ALL_CARDS.add(card);
            }
        }
        //<<额外加入大小王>>
        Collections.addAll(ALL_CARDS,new Card("

标签:Set,String,05List,System,add,Collections,println,public,out
From: https://www.cnblogs.com/Gege-1/p/17014871.html

相关文章