首页 > 编程语言 >Java 集合 Collection、List、Set

Java 集合 Collection、List、Set

时间:2025-01-03 22:00:36浏览次数:3  
标签:Set Java list List System add 泰坦 println out

一. Collection 单列集合

       1.  Collection代表单列集合,每个元素(数据)只包含一个值

       2. Collection集合特点

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

                        ArrayList、LinekdList:有序、可重复,有索引

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

                        HashSet:无序、不重复、无索引

                        LinkedHashSet:有序、不重复、无索引

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

      3. Collection 集合的常用方法

                Collection 是所有单列集合的父类,他规定的方法是全部单列集合都会继承(包括List<E>集合 和 Set<E> 集合)

常用方法说明
boolean add(E e)添加元素,成功返回true

addAll()

把集合的全部元素移动到另一个集合中

void clear()清空集合中的元素
boolean isEmpty()判断集合是否为空 是则返回true
int size()获取集合的大小
boolean contains(Object o)判断集合是否包含某个元素
boolean remove(Object o)删除某个元素,如果有多个默认删除第一个
Object[] toArray()将集合转换成数组
public static void main(String[] args) {
        Collection<String> c = new ArrayList<String>();

        //boolean add(E e)	添加元素,成功返回true  因为可重复 所以一定会返回true
        c.add("卡莎");
        c.add("泰坦");
        c.add("洛");
        System.out.println(c);//[卡莎, 泰坦, 洛]

        //void clear()	清空集合中的元素
        c.clear();
        System.out.println(c);//[卡莎, 泰坦, 洛]

        //boolean isEmpty()	判断集合是否为空 是则返回true
        System.out.println(c.isEmpty());//true
        c.add("卡莎");
        c.add("泰坦");
        c.add("洛");
        c.add("A");
        c.add("洛");
        System.out.println(c.isEmpty());//false

        //int size()	获取集合的大小
        System.out.println(c.size());//5

        //boolean contains(Object o)	判断集合是否包含某个元素
        System.out.println(c);//[卡莎, 泰坦, 洛, A, 洛]
        System.out.println(c.contains("a"));//false
        System.out.println(c.contains("A"));//true

        //boolean remove(Object o)	删除某个元素,如果有多个默认删除第一个
        c.remove("洛");
        System.out.println(c);//[卡莎, 泰坦, A, 洛]


        //Object[] toArray()	将集合转换成数组
        Object[] object = c.toArray();
        System.out.println(Arrays.toString(object));//[卡莎, 泰坦, A, 洛]

        String[] strings = c.toArray(new String[c.size()]);
        System.out.println(Arrays.toString(strings));//[卡莎, 泰坦, A, 洛]

        //把集合的全部元素移动到另一个集合中
        Collection<String> c2 = new ArrayList<String>();
        c2.addAll(c);
        System.out.println(c2);//[卡莎, 泰坦, A, 洛]
    }

        4. Collection 集合的遍历方式

                (1) 迭代器:迭代器是用来遍历集合的专用方式(数组没有迭代器),Java中最常用的迭代器是Iterator

方法名说明
Iterator<E> iterator()返回集合中的迭代器对象,该迭代器对象默认指向当前集合的第一个元素
Boolean hasNext()询问当前位置是否有元素存在,存在返回true 不存在返回false
E next()获取当前位置的元素,并同时将迭代器对象指向下一个元素
public static void main(String[] args) {
        //iterator
        Collection<String> c = new ArrayList();
        c.add("卡莎");
        c.add("泰坦");
        c.add("洛");

        //Iterator<E> iterator()返回集合中的迭代器对象,该迭代器对象默认指向当前集合的第一个元素
        Iterator<String> iterator = c.iterator();

        //Boolean hasNext()	询问当前位置是否有元素存在,存在返回true 不存在返回false
        //E next()	获取当前位置的元素,并同时将迭代器对象指向下一个元素

        /*System.out.println(iterator.next());//卡莎
        System.out.println(iterator.next());//泰坦
        System.out.println(iterator.next());//洛
        System.out.println(iterator.next());//NoSuchElementException 异常*/
        while (iterator.hasNext()) {
            String ele = iterator.next();
            System.out.println(ele);//卡莎 泰坦 洛
        }

}

               (2) 增强for:既可以用来遍历集合,也可以用来遍历数组

                        格式:for(元素的数据类型 变量名 : 数组或集合){  }

                        本质上就是迭代器遍历集合的简化写法

public static void main(String[] args) {
        Collection<String> c = new ArrayList();
        c.add("卡莎");
        c.add("泰坦");
        c.add("洛");

        for (String s : c){
            System.out.println(s);//卡莎 泰坦 洛
        }

        String[] ss = {"飞机","奥恩"};
        for (String s : ss){
            System.out.println(s);//飞机 奥恩
        }
}

                (3) lambda表达式:JDK8 开始的Lambda表达式,提供了一种更简单、更直接的方式来遍历集合

                        default void forEach(Consumer<? super T> action) 结合lambda遍历集合

public static void main(String[] args) {
        Collection<String> c = new ArrayList();
        c.add("卡莎");
        c.add("泰坦");
        c.add("洛");

        // default void forEach(Consumer<? super T> action) 结合lambda遍历集合
        c.forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);//卡莎 泰坦 洛
            }
        });

        c.forEach((String s) ->{
                System.out.println(s);//卡莎 泰坦 洛
            }
        );

        c.forEach((s) ->
                    System.out.println(s)//卡莎 泰坦 洛
        );

        c.forEach(s -> System.out.println(s));//卡莎 泰坦 洛
        
        c.forEach(System.out::println);

}

        5. List集合

                (1) List集合支持索引,除了Collection的方法,多了很多与索引相关的方法。包括ArrayList集合和LinkedList集合

方法名称说明
void add(int index, E element)在此集合中的指定位置插入指定的元素
E remove(int index)删除指定索引处的元素,返回被删除的元素
E set(int index, E element)修改指定索引出的元素,返回被修改的元素
E get(int index)返回指定索引出的元素
 public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("卡莎");
        list.add("泰坦");
        list.add("泰坦");
        list.add("洛");
        System.out.println(list);//[卡莎, 泰坦, 泰坦, 洛]

        //void add(int index, E element)	在此集合中的指定位置插入指定的元素
        list.add(3, "霞");
        System.out.println(list);//[卡莎, 泰坦, 泰坦, 霞, 洛]

        //E remove(int index)	删除指定索引处的元素,返回被删除的元素
        System.out.println(list.remove(2));//泰坦
        System.out.println(list);//[卡莎, 泰坦, 霞, 洛]

        //E set(int index, E element)	修改指定索引出的元素,返回被修改的元素
        System.out.println(list.set(2, "伊泽"));//霞

        //E get(int index)	返回指定索引出的元素
        System.out.println(list.get(2));//伊泽
}

                (2) List集合的遍历方式

                        ① for循环(因为List集合有索引)

                        ② 迭代器

                        ③ 增强for循环

                        ④ Lambda表达式

public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("卡莎");
        list.add("泰坦");
        list.add("泰坦");
        list.add("洛");
        //① for循环(因为List集合有索引)
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }

        //② 迭代器
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }

        //③ 增强for循环
        for (String string : list) {
            System.out.println(string);
        }

        //④ Lambda表达式
        list.forEach(System.out::println);
}

        6. ArrayList集合的底层原理

                (1) ArrayList与LinekdList都是 有序、可重复、 有索引,但底层采用的数据结构不同,应用场景也不同。

                (2) ArrayList的底层原理:基于数组实现的。利用无参构造器创建的集合,会在底层创建一个默认长度为0的数组;添加第一个元素时,底层会创建一个新的长度为10的数组;存满时,会扩容1.5倍;如果一次添加多个元素,1.5倍还放不下,则新创建数组的长度以实际为准;

                        ① 查询速度快(根据索引查询数据快):查询数据通过地址值和索引定位,查询任意数据耗时相同

                        ② 删除效率低:可能需要把后面很多的数据进行前移

                        ③ 添加效率低:可能需要把后面很多的数据后移,再添加元素;或者可能需要进行数组的扩容

        7. LinekdList集合的底层原理

                (1) ArrayList的底层原理:基于双链表实现的;链表中的节点都是独立的对象,在内存中时不连续的,每一个节点包含数据值和下一个节点的地址。

                (2) 特点:

                        ① 查询慢,无论查询哪个数据都要从头开始找。

                        ② 增删相对快,对首尾元素进行增删改查的速度是极快的。

                (3) LinekdList新增了很多首尾操作的特有方法

方法名称说明
public void addFirst(E e)将指定的元素追加到列表的开头
public void addLast(E e)将指定的元素追加到列表的末尾
public E getFirst()返回第一个元素
public E getLast()返回最后一个元素
public E removeFirst()删除并返回第一个元素
public E removeLast()删除并返回最后一个元素
public static void main(String[] args) {
        LinkedList<String> list = new LinkedList<>();
        list.add("卡莎");
        list.add("泰坦");
        list.add("泰坦");
        list.add("洛");
        System.out.println(list);//[卡莎, 泰坦, 泰坦, 洛]

        //public void addFirst(E e)	将指定的元素追加到列表的开头
        list.addFirst("张飞");
        System.out.println(list);//[张飞, 卡莎, 泰坦, 泰坦, 洛]

        //public void addLast(E e)	将指定的元素追加到列表的末尾
        list.addLast("豆芽");
        System.out.println(list);//[张飞, 卡莎, 泰坦, 泰坦, 洛, 豆芽]

        //public E getFirst()	返回第一个元素
        System.out.println(list.getFirst());//张飞

        //public E getLast()	返回最后一个元素
        System.out.println(list.getLast());//豆芽

        //public E removeFirst()	删除并返回第一个元素
        System.out.println(list.removeFirst());//张飞
        
        //public E removeLast()	删除并返回最后一个元素
        System.out.println(list.removeLast());//豆芽
}

        8. Set集合

                (1) 特点:添加的元素是无序(添加数据的顺序和获取数据出的数据顺序不一样)、不重复、无索引

                (2) Set 要用到的常用方法,基本上就是Collection提供的,自己几乎没有新增的方法

        9. HashSet集合

                (1) 无序、不重复、无索引

                底层原理:

                (2) 哈希值:就是一个int类型的数值,Java中每一个对象都有一个哈希值。都可以通过Objectl类提供的hashCode方法获取对象的哈希值。public int hashCode()

                        ① 同一个对象多次调用hashCode()方法返回的哈希值是相同的

                        ② 不同的对象,他们的哈希值一般不相同,但也有可能会相同(哈希碰撞)

                (3) HashSet 是基于哈希表实现的。哈希表是一种增删改查数据性能都较好的数据结构。JDK8之前哈希表=数组+链表;JDK8之后:数组+链表+红黑树

                (4) DK8开始,当链表的长度超过8,且数组长度>=64时,自动将链表转成红黑树

                (5) 如果希望Set集合认为2个内容一样的对象是重复的,必须重写对象的hashCode()和equals()方法

public class Student {
    private int id;
    private String name;
    private Double[] grades;

    public Student() {
    }

    public Student(int id, String name, Double[] grades) {
        this.id = id;
        this.name = name;
        this.grades = grades;
    }


    // idea快捷键生成,类中右键选择Generate->equals() and hashCode()

    @Override
    public int hashCode() {
        return Objects.hash(id, name, Arrays.hashCode(grades));
    }


    @Override
    public boolean equals(Object o) {
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return id == student.id && Objects.equals(name, student.name) && Objects.equals(grades, student.grades);
    }


}

        10. LinkedHashSet集合

                (1) 有序(添加元素的顺序和获取元素的顺序一样)、不重复、无索引

                底层原理:

                (2) 基于哈希表(数组、链表、红黑树)实现的;但是,他的每个元素都额外多了一个双链表的机制记录它前后元素的位置(更占内存)

        11. TreeSet集合

                (1) 按照大小默认升序排序、不重复、无索引

                底层原理:        

                (2) 基于红黑树实现的排序

                (3) 注意:

                        ① 对于数值类型:Integer、Double,默认按照数值大小进行排序

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

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

                        ④ 自定义排序规则:TreeSet集合存储自定义类型的对象时,必须指定排序规则(有两种):

                        规则1:让自定义类实现Comparable接口,重写里面的CompareTo()方法

                        规则2:通过调用TreeSet集合有参构造器,可以设置Comparator对象(比较器对象)--public TreeSet(Comparator<? Super E> comparator)

                        如果规则1和规则2同时使用,默认就近原则(规则2)

//方式1. Comparable:让该类对象实现Comparable(比较规则)接口,然后重写compareTo方法,自己制定比较规则
public class Student implements Comparable<Student>{
    private String name;
    private int age;
    private double score;

    public Student() {
    }

    public Student(String name, int age, double score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public double getScore() {
        return score;
    }

    public void setScore(double score) {
        this.score = score;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", score=" + score +
                '}';
    }

    @Override
    public int compareTo(Student o) {
        //左边对象 大于 右边对象 返回正整数
        //左边对象 小于 右边对象 返回负整数
        //左边对象 等于 右边对象 返回0
        //如按照成绩排序 默认升序

        /*if (this.score > o.score) {
            return 1;
        }else if (this.score < o.score) {
            return -1;
        }else {
            return 0;
        }*/
        return Double.compare(this.getScore(), o.getScore());//升序

        //降序的话:
        //左边对象 大于 右边对象 返回负整数
        //左边对象 小于 右边对象 返回正整数
        //左边对象 等于 右边对象 返回0
       /* if (this.score > o.score) {
            return -1;
        }else if (this.score < o.score) {
            return 0;
        }else {
            return 0;
        }
        return Double.compare(o.getScore(), this.getScore());//降序
        */
    }
}
public static void main(String[] args) {

        //HashSet
        Set<String> set = new HashSet();//无序 不重复 无索引
        set.add("1");
        set.add("2");
        set.add("3");
        set.add("4");
        set.add("1");
        set.add("5");
        set.add("2");
        System.out.println(set);//

        //LinkedHashSet
        Set<String> set1 = new LinkedHashSet();//有序 不重复 无索引
        set1.add("3");
        set1.add("2");
        set1.add("1");
        set1.add("4");
        set1.add("5");
        System.out.println(set1);

        //TreeSet
        Set<String> set3 = new TreeSet();
        set3.add("3");
        set3.add("1");
        set3.add("2");
        set3.add("6");
        set3.add("5");
        System.out.println(set3);

        Set<Integer> set4 = new TreeSet();
        set4.add(1);
        set4.add(7);
        set4.add(5);
        set4.add(6);
        set4.add(2);
        set4.add(5);
        System.out.println(set4);


        //自定义对象TreeSet
        Student student = new Student("卡莎", 18, 99);
        Student student1 = new Student("泰坦", 19, 93);
        Student student2 = new Student("伊泽", 16, 98);
        Student student3 = new Student("璐璐", 16, 98);

        Set<Student> set5 = new TreeSet();
        set5.add(student);
        set5.add(student1);
        set5.add(student2);
        set5.add(student3);
        //[Student{name='泰坦', age=19, score=93.0}, Student{name='伊泽', age=16, score=98.0}, Student{name='卡莎', age=18, score=99.0}]
        System.out.println(set5);//由于伊泽和璐璐 分数98相同 后一个不存了

        Set<Student> set6 = new TreeSet(new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return o1.getAge()- o2.getAge();
            }
        });
        set6.add(student);
        set6.add(student1);
        set6.add(student2);
        set6.add(student3);
        //[Student{name='伊泽', age=16, score=98.0}, Student{name='卡莎', age=18, score=99.0}, Student{name='泰坦', age=19, score=93.0}]
        System.out.println(set6);

}

二. 集合的并发修改异常问题

        1. 集合的并发修改异常:使用迭代器遍历集合时,又同时在删除集合中的数据,程序就会出现并发修改异常

        2. 由于增强for循环遍历集合就是迭代器遍历集合的简化写法,因此,使用增强for循环遍历集合,又在同时删除集合中的数据时,程序也会出现并发修改异常

        3. 解决方法:

                ① 如果使用迭代器遍历集合,用迭代器自己的删除方法删除数据即可

                ② 如果能用for循环遍历时,可以倒着遍历并删除;或者从前往后遍历,删除元素后进行i--;

public static void main(String[] args) {
        //集合的并发修改异常问题
        ArrayList<String> list = new ArrayList<String>();
        list.add("泰坦");
        list.add("卡莎");
        list.add("王莎");
        list.add("洛");
        list.add("伊泽");
        list.add("赵莎");
        list.add("璐璐");
        list.add("孙莎");
        System.out.println(list);

        //迭代器 ConcurrentModificationException异常
       Iterator<String> iterator = list.iterator();
       /*while (iterator.hasNext()) {
           String s = iterator.next();
           if (s.contains("莎")){
               list.remove(s);//ConcurrentModificationException
           }
       }*/

       //解决方法iterator.remove();
        while (iterator.hasNext()) {
            String s = iterator.next();
            if (s.contains("莎")){
                iterator.remove();//删除迭代器当前遍历到的数据,每删除一个数据后,相当于i--
            }
        }
        System.out.println(list);


        ArrayList<String> list2 = new ArrayList<String>();
        list2.add("泰坦");
        list2.add("卡莎");
        list2.add("王莎");
        list2.add("洛");
        list2.add("伊泽");
        list2.add("赵莎");
        list2.add("璐璐");
        list2.add("孙莎");
        //for循环
        for (int i = 0; i < list2.size(); i++) {
            String s = list2.get(i);
            if (s.contains("莎")){
                list2.remove(i);
            }
        }
        //出现bug 没有删除完
        System.out.println(list2);//[泰坦, 王莎, 洛, 伊泽, 璐璐]

        //解决方法1 i--
        for (int i = 0; i < list2.size(); i++) {
            String s = list2.get(i);
            if (s.contains("莎")){
                list2.remove(i);
                i--;
            }
        }

        //解决方法2 倒着删
        for (int i = list2.size() - 1; i > 0; i--) {
            String s = list2.get(i);
            if (s.contains("莎")){
                list2.remove(i);
            }
        }

        ArrayList<String> list3 = new ArrayList<String>();
        list3.add("泰坦");
        list3.add("卡莎");
        list3.add("王莎");
        list3.add("洛");
        list3.add("伊泽");
        list3.add("赵莎");
        list3.add("璐璐");
        list3.add("孙莎");
        //使用正确for循环遍历集合并删除数据,没有办法解决ConcurrentModificationException异常
        //ConcurrentModificationException异常
        for (String s : list3) {
            if (s.contains("莎")){
                list3.remove(s);
            }
        }

        //使用正确forEach循环遍历集合并删除数据 没有办法解决ConcurrentModificationException异常
        //ConcurrentModificationException异常
       list.forEach(name -> {
           if (name.contains("莎")){
               list3.remove(name);
           }
       });

    }

标签:Set,Java,list,List,System,add,泰坦,println,out
From: https://blog.csdn.net/zeijiershuai/article/details/144858299

相关文章

  • JavaScript 基础2
    js的运算符算数运算符+相加求和,如果用在字符串则是拼接-相减求差*相乘求积/相除求商%模除求余具体用法如下letnum=154letnum2=15document.write(num+num2)document.write(`<br>`)document.write(num-num2)document.write(`<br>`)document.write(num*num2)......
  • 高级java每日一道面试题-2025年01月03日-并发篇-什么是Callable和Future?
    如果有遗漏,评论区告诉我进行补充面试官:什么是Callable和Future?我回答:Callable定义与功能:Callable是Java5引入的一个接口,用于定义可并发执行的任务。它类似于Runnable接口,但提供了更多的功能。Callable可以在执行完成后返回结果,而Runnable无法返回任何结果。Call......
  • 高级java每日一道面试题-2025年01月03日-并发篇-索引是什么?
    如果有遗漏,评论区告诉我进行补充面试官:索引是什么?我回答:在Java高级面试中,“索引”这个概念可以涉及到多个方面,包括但不限于数据库中的索引、Java集合框架中的索引(如List接口)、以及某些数据结构或算法中的索引。为了提供一个详尽的解释,我们将从不同角度来探讨“......
  • JavaDay3
    JavaDay3面向对象把大象装进冰箱:​ 1、Java语言通过一个类来描述生活中的事物​ 2、有哪些类?​ 如上:大象类、冰箱类、冰箱装大象组合类。​ 3、类中有什么?​ 属性和行为​ 4、类与类的关系是什么?​ 继承关系面向对象开发:​ 创建对象、使用对象、指......
  • javaweb基于SSH开发车辆管理系统源码+论文+开题报告+任务书+PPT 课程设计 毕业设计
    ......
  • 24年javaWeb考试复习
    1、servlet1、servlet是运行在web服务器端的应用程序配置方式(两种):·web.xml<servlet> <servlet-name>小名</servlet-name> <servlet-class>包名</servlet-class></servlet><servlet-mapping> <servlet-name>小名</se......
  • 一文解秘Rust如何与Java互操作
    使用场景JAVA与Rust互操作让Rust可以背靠Java大生态来做更多事情,而Java也可以享受Rust语言特性的内存安全,所有权机制,无畏并发。互操作的典型场景包括:性能优化:利用Rust处理计算密集型任务,提高Java应用的整体性能。系统级编程:结合Rust的底层控制能力与......
  • java 使用HttpClient发送post请求,参数包括MultipartFile、Map以及File转MockMultipart
        遇到使用java调用其他系统的http接口时,发送的参数中有文件,不太好处理,如下总结了发送带文件的的http方法,发送的文件还需要先将File转成MockMultipartFile否则接收会报错。关键的代码和依赖如下所示。一、依赖<dependency><groupId>org.apache.httpcomponents</......
  • 【手把手-包教包会系列】java按模板多sheet导出Excel
    手把手带你java按模板多sheet导出Excel【包教包会系列】废话不多说直接撸代码1.引入依赖推荐使用3.2以上版本,原因是在性能上会有新的优化<!--easyExcel--><dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.......
  • 【Java 温故而知新系列】基础知识-04 重点关键字(面试经常遇到的)
    1、final 在Java中,final关键字可以用于变量、方法和类,分别赋予它们不同的语义和行为。以下是final关键字的主要作用修饰变量当final修饰一个变量时,表示该变量的值一旦初始化后就不能再被改变。这适用于基本类型和引用类型。基本类型:对于基本类型(如 int, double 等......