[Java]重学Java-集合

容器

很多时候,我们写程序需要进行批量的操作,比如说,新增一批学生列表.那么就需要有容器来装下这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();
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345

推荐阅读更多精彩内容

  • Collection: 在Java类库中,集合类的基本接口是Collection接口,这个接口有两个基本方法: 迭...
    PC_Repair阅读 297评论 0 0
  • Java集合框架 Java中封装了许多常用的数据结构,称为集合框架,可以有效组织数据,提高程序性能。最初Java只...
    Steven1997阅读 919评论 0 2
  • 映射表集合关系图 引言:list是一个集合,它可以快速的查找现有的元素。但是要查看一个元素,我们需要有想要查找元素...
    cp_insist阅读 228评论 0 0
  • 一、Java 集合简介 (一) Java集合简介 1、Java 集合定义:(1)一个 Java 对象可以在内部持有...
    瀑月流光阅读 250评论 0 1
  • 概述 Java集合框架由Java类库的一系列接口、抽象类以及具体实现类组成。我们这里所说的集合就是把一组对象组织到...
    absfree阅读 1,246评论 0 10