理解Java集合的基本用法—Collection:List、Set 和 Queue,Map

news2025/2/11 9:15:51

本博文部分参考 博客 ,强烈推荐这篇博客,写得超级全面!!!


图片来源

Java 集合框架

主要包括两种类型的容器,一种是集合(Collection),存储一个元素集合(单列集合);另一种是 Map ,存储键/值对映射。
Collection 接口又有 3 种子类型,List、Set 和 Queue,再下面是一些抽象类,最后是具体实现类。

  • Collection:所有单列集合的根接口。

    • List:有序、允许重复元素的集合。

    • Set:无序、不允许重复元素的集合。

    • Queue:用于存储按特定顺序处理的元素(如先进先出 FIFO)。

  • Map:映射接口(双列接口),用于存储键值对(Key-Value),提供对键值的快速查找。

在这里插入图片描述
图片来源

由于Java的集合设计非常久远,中间经历过大规模改进,我们要注意到有一小部分集合类是遗留类,不应该继续使用:

  • Hashtable:一种线程安全的Map实现;
  • Vector:一种线程安全的List实现;
  • Stack:基于Vector实现的LIFO的栈。

还有一小部分接口是遗留接口,也不应该继续使用:

  • Enumeration:已被Iterator取代。

List(有序集合,允许重复元素)

List 是一个有序的集合,元素按插入顺序排列,允许重复元素。
实现类:

  • ArrayList 基于动态数组实现,支持随机访问和快速查找,但插入和删除操作的性能较差,尤其是在中间位置操作时。
  • LinkedList 基于双向链表实现,插入和删除操作效率较高,适合频繁的插入和删除,但随机访问的性能差。
  • Vector(ArrayList是非线程安全的,效率高;Vector是基于线程安全的 List 实现,效率低 ,遗留类,通常不推荐使用) 。

ArrayList 是最常用的 List 实现类。

List<String> list = new ArrayList<>();  // 初始化空列表
List<Integer> list = new ArrayList<>(10);  //初始化容量为 10 的列表
List<Integer> list = new ArrayList<>(Arrays.asList(3, 4, 5));  //初始化带有元素 3, 4, 5 的列表
List<Integer> list = new ArrayList<>(other_list);  //用其他列表 list 初始化

常用方法:

  • boolean add(E element):在末尾添加一个元素。
  • boolean add(int index, E element):在指定索引添加一个元素。
  • E get(int index):获取指定索引的元素。
  • E set(int index, E element):设置指定位置的元素,返回先前在 index 处出现的元素。
  • boolean remove(Object o):删除指定元素。
  • E remove(int index):删除指定索引的元素。
  • int size():获取集合大小。
  • boolean contains(Object o):判断是否包含某元素。
  • int indexOf(Object o):可以返回某个元素的索引,如果元素不存在,就返回-1。

我们来比较一下 ArrayListLinkedList

ArrayListLinkedList
获取指定元素速度很快需要从头开始查找元素
添加元素到末尾速度很快速度很快
在指定位置添加/删除需要移动元素不需要移动元素
内存占用较大

通常情况下,我们总是优先使用 ArrayList

另外,我们要始终坚持使用迭代器 Iterator 来访问 List ,因为总是具有最高的访问效率。

public class Main {
    public static void main(String[] args) {
        List<String> list = List.of("apple", "pear", "banana");
        for (Iterator<String> it = list.iterator(); it.hasNext(); ) {
            String s = it.next();
            System.out.println(s);
        }
    }
}

Java 的 for each 循环本身可以帮我们使用 Iterator 遍历。可以把上面的代码改写成:

ublic class Main {
    public static void main(String[] args) {
        List<String> list = List.of("apple", "pear", "banana");
        for (String s : list) {
            System.out.println(s);
        }
    }
}

List 可以和 Array 相互转换:

把 List 变为 Array 有三种方法

  1. 调用toArray()方法直接返回一个Object[]数组,这种方法会丢失类型信息,所以实际应用很少。
List<String> list = List.of("apple", "pear", "banana"); // 如果我们调用List.of(),它返回的是一个只读List
Object[] array = list.toArray();
  1. 给 toArray(T[]) 传入一个类型相同的 Array,List 内部自动把元素复制到传入的 Array 中。
List<Integer> list = List.of(12, 34, 56); //如果我们调用List.of(),它返回的是一个只读List
Integer[] array = list.toArray(new Integer[list.size()]);
  1. 通过List接口定义的T[] toArray(IntFunction<T[]> generator)方法。
Integer[] array = list.toArray(Integer[]::new);

把 Array 变为 List,通过 List.of(T…) 方法最简单

Integer[] array = { 1, 2, 3 };
List<Integer> list = List.of(array);

总结

  • List 是按索引顺序访问的长度可变的有序表,优先使用 ArrayList 而不是 LinkedList;

  • 可以直接使用 for each 遍历 List;

  • List 可以和 Array 相互转换。


Set(无序集合,不允许重复元素)

Set 是一个不允许重复元素的集合,它不保证元素的顺序。Set 实际上相当于只存储 key、不存储 value 的 Map。我们经常用 Set 用于去除重复元素。

Set 接口并不保证有序,而 SortedSet 接口则保证元素是有序的。PS:注意输出的顺序既不是添加的顺序,也不是 String 或 Integer 排序的顺序,在不同版本的JDK中,这个顺序也可能是不同的。
实现类:

  • HashSet 基于哈希表实现,元素无序,性能较好,适合用于查找。它实现了Set接口,并没有实现SortedSet接口;
  • LinkedHashSet 基于哈希表和链表实现,元素有序(按插入顺序)。
  • TreeSet 基于红黑树实现,元素按自然顺序(或提供的 Comparator)排序。它实现了SortedSet接口。

HashSet 是 Set 接口最常用的实现

Set<String> set = new HashSet<>();

常用方法:

  • boolean add(E e):添加元素。
  • boolean remove(Object o):删除指定元素。
  • boolean contains(Object o):判断是否包含某元素。
  • int size():获取集合大小。
  • clear():清空集合。

Queue / Deque

Queue 是一个先进先出(FIFO:First In First Out)的集合,只能一头进,另一头出。

实现类:

  • PriorityQueue:基于优先级堆实现,支持优先级排序的队列。PriorityQueue 并不是一个比较标准的队列实现,PriorityQueue 保存队列元素的顺序并不是按照加入队列的顺序,而是按照队列元素的大小进行重新排序。

  • Deque:Queue 是队列,只能一头进,另一头出。双端队列 Deque(Double Ended Queue)允许两头都进,两头都出。

    • ArrayDeque:基于数组实现,作为栈或队列使用,效率较高。

    • LinkedList:实现了 Queue 接口,适合用于队列操作。

Queue<String> queue = new LinkedList<>();

Queue

常用方法

  • boolean add(E) / boolean offer(E):添加元素到队尾;
  • E remove() / E poll():获取队首元素并从队列中删除;
  • E element() / E peek():获取队首元素但并不从队列中删除。
  • int size():获取队列大小。

对于具体的实现类,有的Queue有最大队列长度限制,有的Queue没有。注意到添加、删除和获取队列元素总是有两个方法,这是因为在添加或获取元素失败时,这两个方法的行为是不同的:

throw Exception返回false或null
添加元素到队尾add(E e)boolean offer(E e)
取队首元素并删除E remove()E poll()
取队首元素但不删除E element()E peek()

注意:不要把 null 添加到队列中,否则 poll() 方法返回 null 时,很难确定是取到了 null 元素还是队列为空。

Deque

Deque 接口继承自 Queue 接口

Queue 和 Deque 出队和入队的方法比较:

QueueDeque
添加元素到队尾add(E e) / offer(E e)addLast(E e) / offerLast(E e)
取队首元素并删除E remove() / E poll()E removeFirst() / E pollFirst()
取队首元素但不删除E element() / E peek()E getFirst() / E peekFirst()
添加元素到队首addFirst(E e) / offerFirst(E e)
取队尾元素并删除E removeLast() / E pollLast()
取队尾元素但不删除E getLast() / E peekLast()

Deque 接口实际上扩展自 Queue,因此,Queue 提供的 add()/offer() 方法在 Deque 中也可以使用,但是,使用 Deque,最好不要调用offer(),而是调用 offerLast()。即使用 Deque,推荐总是明确调用 offerLast() / offerFirst() 或者 pollFirst() / pollLast() 方法。

Deque 是一个接口,它的实现类有 ArrayDeque 和 LinkedList。

LinkedList,它即是List,又是Queue,还是Deque。但是我们在使用的时候,总是用特定的接口来引用它,这是因为持有接口说明代码的抽象层次更高,而且接口本身定义的方法代表了特定的用途。

// 不推荐的写法:
LinkedList<String> d1 = new LinkedList<>();

// 推荐的写法:
Deque<String> d2 = new LinkedList<>();

可见面向抽象编程的一个原则就是:尽量持有接口,而不是具体的实现类。

总结

Deque实现了一个双端队列(Double Ended Queue),它可以:

  • 将元素添加到队尾或队首:addLast()/offerLast()/addFirst()/offerFirst();

  • 从队首/队尾获取元素并删除:removeFirst()/pollFirst()/removeLast()/pollLast();

  • 从队首/队尾获取元素但不删除:getFirst()/peekFirst()/getLast()/peekLast();

  • 总是调用xxxFirst()/xxxLast()以便与Queue的方法区分开;

  • 避免把null添加到队列。


Stack

栈(Stack)是一种后进先出(LIFO:Last In First Out)的数据结构,元素的插入和删除操作都发生在栈的顶端。虽然 Stack 类是 Java 提供的传统类,但它已被 Deque 接口的 ArrayDeque 替代,ArrayDeque 提供了更高效的栈操作。常见实现:Stack(遗留类,较旧,不推荐使用)、ArrayDeque推荐使用)。

Deque<String> stack = new ArrayDeque<>();

在Java中,我们用 Deque 可以实现 Stack 的功能:

  • 把元素压栈:push(E) / addFirst(E);

  • 把栈顶的元素“弹出”:pop() / removeFirst();

  • 取栈顶元素但不弹出:peek() / peekFirst()。

为什么 Java 的集合类没有单独的 Stack 接口呢?因为有个遗留类名字就叫 Stack,出于兼容性考虑,所以没办法创建 Stack 接口,只能用Deque 接口来“模拟”一个 Stack 了。

当我们把 Deque 作为 Stack 使用时,注意只调用 push() / pop() / peek() 方法,不要调用 addFirst() / removeFirst() / peekFirst() 方法,这样代码更加清晰。


Map(映射,存储键值对)

Map 是一个存储键值对(key-value)的集合,Map 中的键是唯一的,值可以重复。

实现类:

  • HashMap:基于哈希表实现,查找和插入的性能较高,元素无序。(HashMap 非线程安全,高效,支持null)

  • LinkedHashMap:保持插入顺序的 HashMap 实现。

  • TreeMap:基于红黑树实现,元素按键的自然顺序或指定的 Comparator 排序。

  • Hashtable:遗留类,过时的线程安全版本,不推荐使用。(HashTable 线程安全,低效,不支持null )

HashMap 是 Map 接口最常用的实现,基于哈希表实现。它在内部会对 Key 进行排序,这种 Map 就是 SortedMap。注意到 SortedMap 是接口,它的实现类是 TreeMap。

Map<String, String> map = new HashMap<>();

常用方法:

  • put(K key, V value):添加键值对。

  • get(Object key):根据键获取对应的值。

  • remove(Object key):删除指定键的键值对。

  • boolean containsKey(Object key):判断是否包含指定键。

  • containsValue(Object value):判断是否包含指定值。

  • keySet():获取所有键。

  • values():获取所有值。

PS: Map 中不存在重复的 key,因为放入相同的 key ,只会把原有的 key-value 对应的 value 给替换掉。

遍历 Map (无序,既不是插入顺序,也不是某个逻辑下的排序顺序)

for (String key : map.keySet()) {  // keySet()方法返回的Set集合,它包含不重复的key的集合
	Integer value = map.get(key);
	System.out.println(key + " = " + value);
 }
 

 for (Map.Entry<String, Integer> entry : map.entrySet()) {  // entrySet()集合,它包含每一个key-value映射
    String key = entry.getKey();
    Integer value = entry.getValue();
    System.out.println(key + " = " + value);
}
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2251124.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

搭建深度学习框架+nn.Module

一、搭建项目框架&#xff08;YOLO框架的简约版本&#xff09; 最终成品的项目框架如下图&#xff0c;最终实现的效果&#xff0c;通过自己配置的框架函数&#xff0c;对模型进行定义与参数调配。同时在参数配置的过程中可选择是否进行模型初始化参数的使用。适用于YOLO框架的…

FFmpeg 简介与编译

1. ffmpeg 简介&#xff1a; FFmpeg是一套可以用来记录、转换数字音频、视频&#xff0c;并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库libavcodec&#xff0c;为了保证高可移…

打latex公式可以练到像手写一样快吗?

这里分享两个Python Latex工具latexify和handcalcs。 latexify生成LaTeX 数学公式 import math import latexify @latexify.with_latex #调用latexify的装饰器 def solve(a, b, c):return (-b + math.sqrt(b**2 - 4*a*c)) / (2*a)solve 更多例子.......

【Linux】磁盘 | 文件系统 | inode

&#x1fa90;&#x1fa90;&#x1fa90;欢迎来到程序员餐厅&#x1f4ab;&#x1f4ab;&#x1f4ab; 主厨&#xff1a;邪王真眼 主厨的主页&#xff1a;Chef‘s blog 所属专栏&#xff1a;青果大战linux 总有光环在陨落&#xff0c;总有新星在闪烁 模电好难啊&#xff…

AntFlow 0.20.0版发布,增加多数据源多租户支持,进一步助力企业信息化,SAAS化

传统老牌工作流引擎比如activiti,flowable或者camunda等虽然功能强大&#xff0c;也被企业广泛采用&#xff0c;然后也存着在诸如学习曲线陡峭&#xff0c;上手难度大&#xff0c;流程设计操作需要专业人员&#xff0c;普通人无从下手等问题。。。引入工作流引擎往往需要企业储…

Scrapy管道设置和数据保存

1.1 介绍部分&#xff1a; 文字提到常用的Web框架有Django和Flask&#xff0c;接下来将学习一个全球范围内流行的爬虫框架Scrapy。 1.2 内容部分&#xff1a; Scrapy的概念、作用和工作流程 Scrapy的入门使用 Scrapy构造并发送请求 Scrapy模拟登陆 Scrapy管道的使用 Scrapy中…

洛谷 B3626 跳跃机器人 C语言 记忆化搜索

题目&#xff1a; https://www.luogu.com.cn/problem/B3626 题目描述 地上有一排格子&#xff0c;共 n 个位置。机器猫站在第一个格子上&#xff0c;需要取第 n 个格子里的东西。 机器猫当然不愿意自己跑过去&#xff0c;所以机器猫从口袋里掏出了一个机器人&#xff01;这…

docker快速部署gitlab

文章目录 场景部署步骤默认账号密码效果 场景 新增了一台机器, 在初始化本地开发环境&#xff0c;docker快速部署gitlab 部署步骤 编写dockerfile version: 3.7services:gitlab:image: gitlab/gitlab-ce:latestcontainer_name: gitlabrestart: alwayshostname: gitlabenviron…

计算机视觉工程师紧张学习中!

在当今这个日新月异的科技时代&#xff0c;计算机视觉作为人工智能的重要分支&#xff0c;正以前所未有的速度改变着我们的生活和工作方式。为了紧跟时代步伐&#xff0c;提升自我技能&#xff0c;一群怀揣梦想与热情的计算机视觉设计开发工程师们聚集在了本次线下培训活动中。…

RabbitMq死信队列(详解)

死信队列的概念 死信(dead message)简单理解就是因为种种原因&#xff0c;无法被消费的信息&#xff0c;就是死信。 有死信&#xff0c;自然就有死信队列。当消息在⼀个队列中变成死信之后&#xff0c;它能被重新被发送到另⼀个交换器中&#xff0c;这个交换器就是DLX( Dead L…

30分钟学会正则表达式

正则表达式是对字符串操作的一种逻辑公式&#xff0c;就是用事先定义好的一些特定字符、及这些特定字符的组合&#xff0c;组成一个“规则字符串”&#xff0c;这个“规则字符串”用来表达对字符串的一种过滤逻辑。 作用 匹配 查看一个字符串是否符合正则表达式的语法 搜索 正…

IDEA无法创建java8、11项目创建出的pom.xml为空

主要是由于Spring3.X版本不支持JDK8&#xff0c;JDK11&#xff0c;最低支持JDK17 解决的话要不就换成JDK17以上的版本&#xff0c;但是不太现实 另外可以参考以下方式解决 修改spring初始化服务器地址为阿里云的 https://start.aliyun.com/

Unity类银河战士恶魔城学习总结(P149 Screen Fade淡入淡出菜单)

【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili 教程源地址&#xff1a;https://www.udemy.com/course/2d-rpg-alexdev/ 本章节实现了进入游戏和死亡之后的淡入淡出动画效果 UI_FadeScreen.cs 1. Animator 组件的引用 (anim) 该脚本通过 Animator 控制 UI 元…

IDEA 解决Python项目import导入报错、引用不到的问题

使用Idea 23.1 专业版编写Python项目时&#xff0c;import 导入爆红&#xff0c;无法引入其他package的代码&#xff0c;现象如&#xff1a; 解决方案&#xff1a;Idea表头打开 File -> Project Settring 解决效果&#xff1a;

[NSSRound#12 Basic]ordinary forensics

解压出来两个文件&#xff0c;一个是镜像文件另一个不知道 先查看镜像文件 vol.py -f /home/kali/Desktop/forensics.raw imageinfo再查看进程&#xff0c;发现有个cmd的程序 vol.py -f /home/kali/Desktop/forensics.raw --profileWin7SP1x64 pslist进行查看&#xff0c;有…

uniapp中父组件数组更新后与页面渲染数组不一致实战记录

简单描述一下业务场景方便理解: 商品设置功能,支持添加多组商品(点击添加按钮进行增加).可以对任意商品进行删除(点击减少按钮对选中的商品设置进行删除). 问题: 正常添加操作后,对已添加的任意商品删除后,控制台打印数组正常.但是与页面显示不一致.已上图为例,选中尾…

【Git系列】利用 Bash 脚本获取 Git 最后一次非合并提交的提交人

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

hadoop环境配置-vm安装+麒麟ubantu

一.VM版本 选择16版本&#xff0c;15版本存在windows蓝屏的情况&#xff0c;也不用设置HV等相关设置 激活下载参考下述博客&#xff1a;https://blog.csdn.net/matrixlzp/article/details/140674802 提前在bois打开SVM设置&#xff0c;不设置无法打开新建的虚拟机 ubantu下载…

基于SpringBoot的电脑配件销售系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

【linux学习指南】详解Linux进程信号保存

文章目录 &#x1f4dd;保存信号&#x1f320; 信号其他相关常⻅概念&#x1f309;在内核中的表⽰ &#x1f320; sigset_t&#x1f320;信号集操作函数&#x1f309;sigprocmask&#x1f309;sigpending &#x1f6a9;总结 &#x1f4dd;保存信号 &#x1f320; 信号其他相关常…