开发场景中Java 集合的最佳选择

在 Java 开发中,集合类是处理数据的核心工具。合理选择集合,不仅可以提高代码效率,还能让代码更简洁。本篇文章将重点探讨 List、SetMap 的适用场景及优缺点,帮助你在实际开发中找到最佳解决方案。

一、List:有序存储的/最佳选择

1. ArrayList:快速查询与动态数组

应用场景:当你需要频繁查询元素,或者存储的元素数目动态变化时,ArrayList 是首选。例如:分页展示用户数据。

代码示例:

List<String> users = new ArrayList<>();
users.add("Alice");
users.add("Bob");
System.out.println(users.get(1)); // 输出 Bob

底层结构ArrayList 使用一个 动态数组 来存储元素。初始时,数组的大小是固定的,当元素超过数组的容量时,会自动扩展数组的大小。

优点

  • 查询效率高:数组支持按索引快速访问元素,时间复杂度为 O(1),因此 get() 操作非常高效。

  • 内存局部性:数组存储在连续的内存空间中,CPU 缓存友好,可以利用 CPU 的缓存机制提高访问效率。

缺点

  • 插入和删除效率低:当插入或删除元素时,尤其是在中间位置时,必须移动数组中的大量元素,时间复杂度为 O(n)

  • 扩容操作代价高:数组扩容时需要分配新的数组并将旧数组元素复制到新数组,操作的时间复杂度为 O(n)


2. LinkedList:高效增删的双向链表

应用场景:需要频繁在列表中间或首尾插入、删除数据时,例如实现任务队列。

代码示例:

LinkedList<String> tasks = new LinkedList<>();
tasks.addFirst("Task1");
tasks.addLast("Task2");
tasks.removeFirst();

底层结构LinkedList 使用 双向链表,每个元素都有两个指针:一个指向前一个元素,一个指向下一个元素。这样可以在常数时间内插入或删除元素。

优点

  • 插入和删除高效:无论是在链表的头部、中部还是尾部,插入和删除元素的时间复杂度都为 O(1),因为只需要改变相关节点的指针。

  • 内存使用灵活:每个元素的内存可以分散存储,不需要连续的内存块。

【比如在中间插入

假设需要在链表中的某个位置 node 前插入新节点 newNode

  1. newNodenext 指向 node,将 newNodeprev 指向 node.prev

  2. 更新 node.prev.nextnewNode,更新 node.prevnewNode

这只涉及 4 次指针操作,与链表的长度无关,因此在已定位到目标节点后,插入操作的时间复杂度为 O(1)

缺点

  • 查询效率低:为了查找元素,必须从头节点或尾节点开始遍历链表,时间复杂度为 O(n)

  • 内存开销大:每个元素都需要额外存储指向前后元素的指针,相较于数组,占用更多的内存。


二、Set:无重复集合的首选

1. HashSet:高效去重

应用场景:当需要存储一组不允许重复的元素,且对顺序没有要求时,例如用户注册时验证用户名的唯一性。

代码示例

Set<String> usernames = new HashSet<>();
usernames.add("Alice");
usernames.add("Bob");
usernames.add("Alice"); // 重复的元素会被忽略
System.out.println(usernames.size()); // 输出 2

底层结构HashSet 使用 哈希表HashMap)【哈希表在文末有补充讲解】来存储元素。哈希表通过将元素的哈希码映射到表中的桶来进行存储,确保元素是唯一的。

优点

  • 去重高效:哈希表能够快速判断元素是否已存在,因为它通过哈希值进行查找,时间复杂度为 O(1)

  • 查询效率高:哈希表的查找时间复杂度为 O(1),因此 contains()add() 操作非常高效。

缺点

  • 无序存储:哈希表并不维护元素的顺序,因此 HashSet 中的元素是无序的。

  • 哈希冲突:不同的元素可能具有相同的哈希值,哈希冲突会影响性能,但通常情况下,哈希表的设计会尽量减少冲突的概率。


2. LinkedHashSet:有序去重

应用场景:当需要去重的同时保留插入顺序,例如记录用户最近浏览的商品。

代码示例:

Set<String> products = new LinkedHashSet<>();
products.add("Laptop");
products.add("Phone");
products.add("Laptop"); // 再次添加无效
System.out.println(products); // 输出 [Laptop, Phone]

底层结构LinkedHashSet 使用一个 哈希表 来存储元素,并通过一个 双向链表 来维护元素的插入顺序。

优点

  • 有序存储:由于链表的存在,LinkedHashSet 能够保持元素的插入顺序,访问时能够按照插入的顺序遍历元素。

  • 去重高效:与 HashSet 一样,哈希表提供了快速的查找和去重机制。

缺点性能略低于 HashSet,由于还需要维护链表,LinkedHashSet 的操作稍微比 HashSet 慢,但差距通常不大。


3. TreeSet:排序与去重兼备

应用场景:当需要去重的同时对元素进行排序,例如实现排行榜或数据字典。

代码示例:

TreeSet<Integer> scores = new TreeSet<>();
scores.add(50);
scores.add(80);
scores.add(70);
System.out.println(scores); // 输出 [50, 70, 80]

底层结构TreeSet 使用 红黑树 来存储元素。红黑树是一种自平衡的二叉搜索树,能够确保树的深度保持在对数级别。

优点

  • 有序存储TreeSet 会自动对元素进行排序,默认按自然顺序排序compareTo(Object obj))或者通过传入 Comparator 自定义排序)。

  • 查找、插入和删除的时间复杂度为 O(log n):由于红黑树的结构特性,所有操作的时间复杂度为对数级别。

缺点性能较低,相比哈希表,红黑树的插入、删除和查找操作的时间复杂度为 O(log n),因此在大量数据操作时,性能略逊色于 HashSetLinkedHashSet

三、Map:键值对存储的首选

Map 是存储键值对的集合类,每个键唯一对应一个值。常用于快速查找和关联关系的存储。

1. HashMap:高效的键值映射

应用场景:需要高效查找时,例如存储用户 ID 和用户信息的映射。

代码示例:

Map<Integer, String> userMap = new HashMap<>();
userMap.put(1, "Alice");
userMap.put(2, "Bob");
System.out.println(userMap.get(1)); // 输出 Alice

底层结构HashMap 使用 哈希表 来存储键值对,通过键的哈希码来确定存储位置。

优点

  • 查找和插入高效:查找、插入和删除操作的时间复杂度为 O(1),通过哈希值直接定位位置。

  • 支持键值对的存储:每个键对应唯一的值,适合各种映射操作。

缺点

  • 无序存储:哈希表中的元素是无序的,因此遍历时无法保证顺序。


2. LinkedHashMap:有序的键值映射

应用场景:需要既保持插入顺序,又能高效查找,例如实现最近访问页面的缓存。

代码示例:

Map<Integer, String> accessLog = new LinkedHashMap<>();
accessLog.put(1, "HomePage");
accessLog.put(2, "ProfilePage");
accessLog.put(3, "SettingsPage");
System.out.println(accessLog); // 输出 {1=HomePage, 2=ProfilePage, 3=SettingsPage}

底层结构LinkedHashMap 使用 哈希表 存储元素,并通过 双向链表 维护元素的插入顺序。

优点

  • 有序存储:保持了元素的插入顺序,遍历时能够按照插入顺序输出。

  • 高效查找:与 HashMap 一样,查询和插入操作的时间复杂度为 O(1)

缺点内存开销较大,需要额外的内存来存储链表指针。


3. TreeMap:有序的键值存储

应用场景:需要按键排序存储键值对,例如实现字典或排行榜。

代码示例:

Map<Integer, String> sortedMap = new TreeMap<>();
sortedMap.put(3, "C");
sortedMap.put(1, "A");
sortedMap.put(2, "B");
System.out.println(sortedMap); // 输出 {1=A, 2=B, 3=C}
  • 底层结构TreeMap 使用 红黑树 来存储键值对,按照键的自然顺序(或通过指定的 Comparator)进行排序。

  • 优点

    • 有序存储:自动对键进行排序,适用于需要顺序访问键值对的场景。

    • 高效的查找、插入和删除:操作时间复杂度为 O(log n)

  • 缺点性能略低于 HashMapLinkedHashMap,由于红黑树需要维护平衡,操作的时间复杂度为对数级别,性能不如哈希表

4. Properties

应用场景

  • Properties 常用于管理应用程序的配置信息,如数据库连接信息、语言国际化资源等。

  • 它可以方便地加载和存储键值对到 .properties 文件中,支持流式操作。

代码示例:

import java.io.*;
import java.util.Properties;
​
public class PropertiesExample {public static void main(String[] args) throws IOException {Properties properties = new Properties();// 设置键值对properties.setProperty("database.url", "jdbc:mysql://localhost:3306/mydb");properties.setProperty("database.user", "root");properties.setProperty("database.password", "password");
​// 保存到文件try (FileOutputStream output = new FileOutputStream("config.properties")) {properties.store(output, "Database Configuration");}
​// 从文件加载try (FileInputStream input = new FileInputStream("config.properties")) {properties.load(input);}
​// 打印所有属性properties.forEach((key, value) -> System.out.println(key + ": " + value));}
}

底层结构

  • Properties 的基础是 Hashtable

    • 底层采用线程安全的哈希表结构。

    • 键和值均为字符串类型(String),以适应配置文件的存储和解析需求。

    • 提供了 load()store() 方法,用于流式操作,方便配置文件的读写。

优点

  1. 简单直观:内置方法支持直接操作配置文件,减少手动解析的复杂性;适合存储和管理小规模配置。

  2. 线程安全:继承自 Hashtable,所有操作均是同步的,适合简单的多线程环境。

  3. 与文件系统集成良好:提供了流式操作接口,方便将键值对直接保存为 .properties 文件或从文件中加载。

缺点

  1. 性能较低:由于继承自同步的 Hashtable,在现代高并发场景下不推荐使用,性能落后于 HashMap

  2. 局限性:仅支持 String 类型的键值对,若需要存储复杂对象,需额外序列化。

  3. 不适合大规模配置:适合小型项目或简单模块的配置管理,大型系统建议采用更复杂的配置管理工具(如 Apache Commons Configuration 或 Spring)。

总结

集合类底层数据结构主要优点主要缺点
ArrayList动态数组查询效率高,支持随机访问插入删除效率低,扩容代价大
LinkedList双向链表插入删除效率高,内存灵活查询效率低,占用内存大
HashSet哈希表查询和去重效率高无序存储,受哈希冲突影响
LinkedHashSet哈希表 + 双向链表有序存储,去重效率高内存占用较高
TreeSet红黑树有序存储,按自然顺序或自定义顺序排序性能略低于哈希表,操作复杂度为 O(log n)
HashMap哈希表查找和插入效率高,支持键值对映射无序存储,受哈希冲突影响
LinkedHashMap哈希表 + 双向链表有序存储,按插入顺序遍历键值对内存开销较高
TreeMap红黑树有序存储,按键自然顺序或自定义顺序排序性能略低于哈希表,操作复杂度为 O(log n)
Properties哈希表(继承自 Hashtable专为存储键值对配置设计,支持读写 .properties 文件性能较低(继承自同步的 Hashtable),不适合高并发

知识点补充

1. 什么是哈希表?

哈希表是一种用来存储 键值对 的工具,它能非常快速地找到数据。你可以把它想象成一个 带编号的储物柜,每个柜子都有一个编号(索引),你把东西存进去时,会根据物品的特点计算出一个编号,然后直接放进对应的柜子里。取东西时也用相同的方法计算编号,直接找到对应的柜子打开拿走。

例子

  • 假如你有一本字典,查找某个单词(键)对应的解释(值)。

  • 传统查找方法:逐页翻阅,耗时长。

  • 使用哈希表:计算单词的编号,直接跳到对应的位置查看解释,速度非常快。

总结类比

  • 键是 “单词”,值是 “解释”。

  • 哈希表通过哈希函数快速找到这个单词在哪页。


2. 哈希表是如何存数据的?

哈希表的核心在于 哈希函数。这个函数就像一个计算器,可以把一个键(比如一个字符串)变成一个数字(哈希值)。哈希值用来确定数据存储的位置。

步骤:

  1. 计算位置:用哈希函数把键变成一个数字,然后对储物柜的总数取模(%),确定放在哪个柜子里。假如储物柜有 10 个,"Alice" 的哈希值是 42,42 % 10 = 2,所以数据放到第 2 个柜子。

  2. 存储值:把数据放到计算出的柜子里。

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

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

相关文章

Java包装类型的缓存

Java 基本数据类型的包装类型的大部分都用到了缓存机制来提升性能。 Byte,Short,Integer,Long 这 4 种包装类默认创建了数值 [-128&#xff0c;127] 的相应类型的缓存数据&#xff0c;Character 创建了数值在 [0,127] 范围的缓存数据&#xff0c;Boolean 直接返回 True or Fal…

工程师 - MinGW

MinGW Minimalist GNU for Windows&#xff0c;前身为mingw32&#xff0c;是一个免费开源的软件开发环境&#xff0c;从2010年开始项目停止并不再使用。后续提供MinGW-w64。 MinGW包括: - 移植到Windows上的GNU编译器集&#xff08;GCC&#xff09;&#xff0c;包括C、C、ADA和…

EasyExcel(读取操作和填充操作)

文章目录 1.准备Read.xlsx&#xff08;具有两个sheet&#xff09;2.读取第一个sheet中的数据1.模板2.方法3.结果 3.读取所有sheet中的数据1.模板2.方法3.结果 EasyExcel填充1.简单填充1.准备 Fill01.xlsx2.无模版3.方法4.结果 2.列表填充1.准备 Fill02.xlsx2.模板3.方法4.结果 …

CKA认证 | Day7 K8s存储

第七章 Kubernetes存储 1、数据卷与数据持久卷 为什么需要数据卷&#xff1f; 容器中的文件在磁盘上是临时存放的&#xff0c;这给容器中运行比较重要的应用程序带来一些问题。 问题1&#xff1a;当容器升级或者崩溃时&#xff0c;kubelet会重建容器&#xff0c;容器内文件会…

关于JAVA方法值传递问题

1.1 前言 之前在学习C语言的时候&#xff0c;将实参传递给方法&#xff08;或函数&#xff09;的方式分为两种&#xff1a;值传递和引用传递&#xff0c;但在JAVA中只有值传递&#xff08;颠覆认知&#xff0c;基础没学踏实&#xff09; 参考文章&#xff1a;https://blog.csd…

Excel基础知识

一&#xff1a;数组 一行或者一列数据称为一维数组&#xff0c;多行多列称为二维数组&#xff0c;数组支持算术运算&#xff08;如加减乘除等&#xff09;。 行&#xff1a;{1,2,3,4} 数组中的每个值用逗号分隔列&#xff1a;{1;2;3;4} 数组中的每个值用分号分隔行列&#xf…

基于DIODES AP43781+PI3USB31531+PI3DPX1207C的USB-C PD Video 之全功能显示器连接端口方案

随着USB-C连接器和PD功能的出现&#xff0c;新一代USB-C PD PC显示器可以用作个人和专业PC工作环境的电源和数据集线器。 虽然USB-C PD显示器是唯一插入墙壁插座的交流电源输入设备&#xff0c;但它可以作为数据UFP&#xff08;上游接口&#xff09;连接到连接到TCD&#xff0…

gazebo_world 基本围墙。

如何使用&#xff1f; 参考gazebo harmonic的官方教程。 本人使用harmonic的template&#xff0c;在里面进行修改就可以分流畅地使用下去。 以下是world 文件. <?xml version"1.0" ?> <!--Try sending commands:gz topic -t "/model/diff_drive/…

解决无法在 Ubuntu 24.04 上运行 AppImage 应用

在 Ubuntu 24.04 中运行 AppImage 应用的完整指南 在 Ubuntu 24.04 中&#xff0c;许多用户可能会遇到 AppImage 应用无法启动的问题。即使你已经设置了正确的文件权限&#xff0c;AppImage 仍然拒绝运行。这通常是由于缺少必要的库文件所致。 问题根源&#xff1a;缺少 FUSE…

springboot配置oracle+达梦数据库多数据源配置并动态切换

项目场景&#xff1a; 在工作中很多情况需要跨数据库进行数据操作,自己总结的经验希望对各位有所帮助 问题描述 总结了几个问题 1.识别不到mapper 2.识别不到xml 3.找不到数据源 原因分析&#xff1a; 1.配置文件编写导致识别mapper 2.配置类编写建的格式有问题 3.命名…

html+css+js网页设计 美食 家美食1个页面

htmlcssjs网页设计 美食 家美食1个页面 网页作品代码简单&#xff0c;可使用任意HTML辑软件&#xff08;如&#xff1a;Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及修改编辑等操作&#xff09;。 获取源码 1&#xf…

【机器学习】【朴素贝叶斯分类器】从理论到实践:朴素贝叶斯分类器在垃圾短信过滤中的应用

&#x1f31f; 关于我 &#x1f31f; 大家好呀&#xff01;&#x1f44b; 我是一名大三在读学生&#xff0c;目前对人工智能领域充满了浓厚的兴趣&#xff0c;尤其是机器学习、深度学习和自然语言处理这些酷炫的技术&#xff01;&#x1f916;&#x1f4bb; 平时我喜欢动手做实…

Vue使用Tinymce 编辑器

目录 一、下载并重新组织tinymce结构二、使用三、遇到的坑 一、下载并重新组织tinymce结构 下载 npm install tinymce^7 or yarn add tinymce^7重构目录 在node_moudles里找到tinymce文件夹&#xff0c;把里面文件拷贝一份放到public下&#xff0c;如下&#xff1a; -- pub…

EMNLP'24 最佳论文解读 | 大语言模型的预训练数据检测:基于散度的校准方法

点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入&#xff01; 点击 阅读原文 观看作者讲解回放&#xff01; 作者简介 张伟超&#xff0c;中国科学院计算所网络数据科学与技术重点实验室三年级直博生 内容简介 近年来&#xff0c;大语言模型&#xff08;LLMs&#xff09;的…

大数据技术-Hadoop(一)Hadoop集群的安装与配置

目录 一、准备工作 1、安装jdk&#xff08;每个节点都执行&#xff09; 2、修改主机配置 &#xff08;每个节点都执行&#xff09; 3、配置ssh无密登录 &#xff08;每个节点都执行&#xff09; 二、安装Hadoop&#xff08;每个节点都执行&#xff09; 三、集群启动配置&a…

折腾日记:如何让吃灰笔记本发挥余热——搭建一个相册服务

背景 之前写过&#xff0c;我在家里用了一台旧的工作站笔记本做了服务器&#xff0c;连上一个绿联的5位硬盘盒实现简单的网盘功能&#xff0c;然而&#xff0c;还是觉的不太理想&#xff0c;比如使用filebrowser虽然可以备份文件和图片&#xff0c;当使用手机使用网页&#xf…

使用seata实现分布式事务管理

配置 版本说明&#xff1a;springCloud Alibaba组件版本关系 我用的是spring cloud Alibaba 2.2.1.RELEASE 、springboot 2.2.1.RELEASE、nacos 2.0.1、seata1.2.0,jdk1.8 seata 主要用于在分布式系统中对数据库进行事务回滚&#xff0c;保证全局事务的一致性。 seata的使用…

RabbitMQ中的异步Confirm模式:提升消息可靠性的利器

在现代分布式系统中&#xff0c;消息队列&#xff08;Message Queue&#xff09;扮演着至关重要的角色&#xff0c;它能够解耦系统组件、提高系统的可扩展性和可靠性。RabbitMQ作为一款广泛使用的消息队列中间件&#xff0c;提供了多种机制来确保消息的可靠传递。其中&#xff…

linux安装nginxs报错:openssl not found

系统&#xff1a; linux 版本&#xff1a;centOS7 nginx版本&#xff1a;nginx-1.20.2 linux安装nginx时 执行下面命令时报错&#xff1a; ./configure --with-http_stub_status_module --with-http_ssl_module --prefix/usr/local/nginxchecking for OpenSSL library ... not …

【论文笔记】Contrastive Learning for Sign Language Recognition and Translation

&#x1f34e;个人主页&#xff1a;小嗷犬的个人主页 &#x1f34a;个人网站&#xff1a;小嗷犬的技术小站 &#x1f96d;个人信条&#xff1a;为天地立心&#xff0c;为生民立命&#xff0c;为往圣继绝学&#xff0c;为万世开太平。 基本信息 标题: Contrastive Learning for…