美文网首页一些收藏
[Java]重学Java-集合

[Java]重学Java-集合

作者: AbstractCulture | 来源:发表于2021-09-18 17:29 被阅读0次

容器

很多时候,我们写程序需要进行批量的操作,比如说,新增一批学生列表.那么就需要有容器来装下这10个对象。
Java提供了许多容器来装对象,在JDK的java.util包下,编程中最常用的有:

  1. List: 有序列表,有序地存储元素
  2. Set: 集合,存储的元素不可重复
  3. Map: 映射,建立key->value关系
  4. Quene: 队列,先进先出
  5. Stack: 栈,先进后出

泛型

使用Java的集合类最好配合泛型进行使用,以免发生以下的错误:

package com.tea.modules.java8.generic;

import java.util.ArrayList;
import java.util.List;

/**
 * com.tea.modules.java8.generic <br>
 * 不要使用原始类型
 * @author jaymin
 * @since 2021/6/4
 */
@SuppressWarnings("all")
public class DoNotUseRawType {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add(1);
        list.add("2");
    }
}

例子中,我们对list没做任何类型限制,添加了数字1和字符串2,那么在遍历取值使用的时候,我们可能会将字符相关的操作用在数字上,从而引发了异常。

equals 和 hashcode

如果存储的是对象,那么需要重写equals和hashcode,否则你的集合操作会产生意外的异常.

package com.tea.modules.java8.collection.prevent;

import lombok.extern.slf4j.Slf4j;

import java.util.*;

/**
 * com.xjm.collection.prevent<br>
 * 对集合对象进行操作,最好重写equals和hashcode,避免带来不好的影响<br>
 *
 * @author xiejiemin
 * @create 2020/12/25
 */
@Slf4j
public class EqualsAndHashCode {

    public static class Student implements Comparable<Student>{
        /**
         * 姓名
         */
        private String name;
        /**
         * 性别:0-man|1-women
         */
        private Integer gender;

        public Student(String name, Integer gender) {
            this.name = name;
            this.gender = gender;
        }

        public Student() {
        }

        public String getName() {
            return name;
        }

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

        public Integer getGender() {
            return gender;
        }

        public void setGender(Integer gender) {
            this.gender = gender;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj instanceof Student) {
                Student student = (Student) obj;
                return Objects.equals(this.name, student.name);
            }
            return false;
        }

        @Override
        public int hashCode() {
            int result = name.hashCode();
            result = 31 * result + gender;
            return result;
        }

        @Override
        public int compareTo(Student student) {
            return this.gender - student.gender;
        }
    }

    /**
     * <h2>实现/不实现equals和hashcode对于判等的影响</h2>
     */
    private static void beforeOverrideEqualsAndHashCode() {
        Student jackA = new Student("Jack", 20);
        Student jackB = new Student("Jack", 20);
        log.info("Before override equals and hashcode->{}", Objects.equals(jackA,jackB));
        Set<Student> studentSet = new HashSet<>();
        studentSet.add(jackA);
        studentSet.add(jackB);
        studentSet.forEach(System.out::println);
        Map<Student,Integer> studentMap = new HashMap<>();
        studentMap.put(jackA,20);
        studentMap.put(jackB,20);
        System.out.println(studentMap.size());
    }

    /**
     * <h3>类实现了compareTo方法,就需要实现equals方法</h3>
     * <h3>compareTo与equals的实现过程需要同步</h3>
     */
    private static void compareToWithEquals(){
        ArrayList<Student> students = new ArrayList<>();
        students.add(new Student("Jack",10));
        students.add(new Student("Jack",20));

        Student jack = new Student("Jack", 20);
        // equals
        int studentIndex = students.indexOf(jack);
        // compareTo
        int index = Collections.binarySearch(students, jack);

        System.out.println(studentIndex+"   "+index);
    }
    public static void main(String[] args) {
        beforeOverrideEqualsAndHashCode();
        compareToWithEquals();
    }
}

接口与实现

以列表为例子,我们通常这样使用:

List<String> strings = new ArrayList<>();

List是列表这个数据结构的顶层接口,ArrayList是具体的实现,ArrayList底层基于数组实现,可以动态扩容。
如果此时,我们需要更换队列的实现类,那么直接更换即可,依然返回List接口类型的结果.

List<String> strings = new LinkedList<>();

Collection

java中的绝大多数集合类都实现了Collection接口:

collection

来看看这些接口分别代表的含义:

method description
size 返回集合中元素的个数
isEmpty 判断当前集合中是否存储了元素
contains 集合中是否包含某个对象
iterator 获取迭代器
toArray 将集合转换成Object数组
toArray(T[]) 将集合转换成对象数组
add 往集合中添加元素
remove 从集合中移除元素
containsAll 集合中是否有子集
addAll 将两个集合合并
removeAll 求集合的差集
removeIf 如果符合Predicate的条件,将元素从集合中删除
retainAll 从该集合中移除所有未包含在指定集合中的元素
clear 移除集合中所有元素
stream 将集合转为流
parallerStream 将集合转为并行流

Iterator-迭代器

关于迭代器,可以看看我之前的文章,这里不重复描述
点我前往

  • 关于为什么要设计迭代器的解释

要使用集合,必须对集合的确切类型编程。这一开始可能看起来不是很糟糕,但是考虑下面的情况:如果原本是对 List 编码的,但是后来发现如果能够将相同的代码应用于 Set 会更方便,此时应该怎么做?或者假设想从一开始就编写一段通用代码,它不知道或不关心它正在使用什么类型的集合,因此它可以用于不同类型的集合,那么如何才能不重写代码就可以应用于不同类型的集合?
迭代器(也是一种设计模式)的概念实现了这种抽象。迭代器是一个对象,它在一个序列中移动并选择该序列中的每个对象,而客户端程序员不知道或不关心该序列的底层结构。

摘自《Java编程思想》

集合实现

  • 队列与集合

    abstractCollection
  • 映射

    map

说到映射,很多朋友可能觉得很迷糊,其实就是key->value的关系.

package com.tea.modules.java8.collection.maps;

import java.util.HashMap;
import java.util.Map;

/**
 * com.tea.modules.java8.collection.maps <br>
 * 用于测试Map的API
 * @author jaymin
 * @since 2021/9/18
 */
public class WhatIsMap {

    public static void main(String[] args) {
        Map<String,Object> hashMap = new HashMap<>();
        hashMap.put("男","man");
        hashMap.put("女","woman");
        System.out.println(hashMap.get("男"));
    }
}
collection description
ArrayList 可以动态扩容和缩减的有序列表
LinkedList 可以在任一位置进行插入和删除的有序列表,基于链表
HashSet 无重复元素的无序集合
HashMap 存储键值对的映射表,无序
EnumSet 枚举集合
LinkedHashSet 记录插入顺序的无重复元素集合
PriorityQueue 一种允许高效删除最小元素的集合
TreeMap Key根据自然排序的映射表
LinkedHashMap 记录插入顺序的映射表
WeakHashMap 对象引用为弱引用的映射表
IdentityHashMap 用==来对比键值的映射表

快速失败机制

package com.tea.modules.java8.collection.prevent;

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

/**
 * com.tea.modules.java8.collection.prevent <br>
 * 触发集合的ConcurrentModificationException <br>
 * 可以想象, 如果在某个迭代器修改集合时, 另一个迭代器对其进行遍历,一定会出现
 * 混乱的状况。例如,一个迭代器指向另一个迭代器刚刚删除的元素前面,现在这个迭代器
 * 就是无效的,并且不应该再使用。链表迭代器的设计使它能够检测到这种修改。如果迭代
 * 器发现它的集合被另一个迭代器修改了, 或是被该集合自身的方法修改了, 就会抛出一个
 * ConcurrentModificationException 异常 <br>
 * JDK文档:   <br>
 * 例如,通常不允许一个线程修改一个集合,而另一个线程正在对其进行迭代。  <br>
 * 通常,在这些情况下迭代的结果是不确定的。   <br>
 * 如果检测到此行为,某些迭代器实现(包括 JRE 提供的所有通用集合实现的实现)可能会选择抛出此异常。   <br>
 * 这样做的迭代器被称为快速失败迭代器,因为它们快速而干净地失败,  <br>
 * 而不是冒着在未来不确定的时间出现任意、非确定性行为的风险。<br>
 * @author jaymin
 * @since 2021/9/18
 */
public class ConcurrentModificationExceptionDemo {

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("A");
        list.add("B");
        ListIterator<String> stringListIteratorA = list.listIterator();
        ListIterator<String> stringListIteratorB = list.listIterator();
        stringListIteratorA.next();
        stringListIteratorA.remove();
        stringListIteratorB.next();
    }
}

相关文章

  • [Java]重学Java-集合

    容器 很多时候,我们写程序需要进行批量的操作,比如说,新增一批学生列表.那么就需要有容器来装下这10个对象。Jav...

  • [Java]重学Java-集合的视图

    聊聊一些常用的视图API asList 很多时候,我们希望快速得到一个List,我们可能会这样写: 直接报错: 出...

  • Hello Java

    目录 Java-基础(1/6) Java-对象(2/6) Java-核心库类 上(3/6) Java-核心库类下(...

  • [Java]重学Java-继承

    复用 随着码代码的时间增长,程序员会越发需要"复用"这个能力,比如最简单的对String类进行判空: 我们需要每次...

  • [Java]重学Java-接口

    接口是什么 首先接口不是类,它本身是无法被实例化的,只有实现类可以被实例化。它更像是一种功能的描述,程序输入什么值...

  • [Java]重学Java-多态

    从一个例子理解多态 对于一个不同特征的对象,使用接口可以隐藏子类的行为,对外暴露同一个接口,从而实现编程的解耦. ...

  • Java-集合

    Collection: 在Java类库中,集合类的基本接口是Collection接口,这个接口有两个基本方法: 迭...

  • JAVA-集合

    JAVA集合 Java集合是使程序能够存储和操纵元素不固定的一组数据。 JAVA中的集合是一个类似一个‘’容器‘’...

  • Java-集合

    List接口特点: 允许重复元素必须是有序的可以放入null元素 ArrayList特点 里面维护的是一个数组 默...

  • java-集合

    CollectionListSet泛型MapCollections Collecton1.1 集合知识回顾集合类的...

网友评论

    本文标题:[Java]重学Java-集合

    本文链接:https://www.haomeiwen.com/subject/sjrygltx.html