当前位置: 首页 > news >正文

开发场景中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. 存储值:把数据放到计算出的柜子里。

相关文章:

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

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

golangci-lint安装与Goland集成

golangci-lint安装与Goland集成 1.golangci-lint概述2.golangci-lint安装3.Goland 中集成 golangci-lint4.golangci-lint 的使用5.排除代码检查 1.golangci-lint概述 golangci-lint是用于go语言的代码静态检查工具集 官网地址&#xff1a;golangci-lint 特性&#xff1a; 快…...

金仓数据库安装-Kingbase v9-centos

在很多年前有个项目用的金仓数据库&#xff0c;上线稳定后就没在这个项目了&#xff0c;只有公司的开发环境还在维护&#xff0c;已经好多年没有安装过了&#xff0c;重温一下金仓数据库安装&#xff0c;体验一下最新版本&#xff0c;也做一个新版本的试验环境&#xff1b; 一、…...

条款6:auto推导若非己愿,使用显式类型初始化惯用法

一、代理类 所谓的代理类就是以模仿和增强一些类型的行为为目的存在的类 class MyArray { public:class MyArraySize{public:MyArraySize(int size) : theSize(size) {}int size() const { return theSize; }operator int() const { return theSize; }private:int theSize;};…...

蓝桥杯物联网开发板硬件组成

第一节 开发板简介 物联网设计与开发竞赛实训平台由蓝桥杯大赛技术支持单位北京四梯科技有限公司设计和生产&#xff0c;该产品可用于参加蓝桥杯物联网设计与开发赛道的竞赛实训或院校相关课程的 实践教学环节。 开发板基于STM32WLE5无线微控制器设计&#xff0c;芯片提供了25…...

视频汇聚融合云平台Liveweb一站式解决视频资源管理痛点

随着5G技术的广泛应用&#xff0c;各领域都在通信技术加持下通过海量终端设备收集了大量视频、图像等物联网数据&#xff0c;并通过人工智能、大数据、视频监控等技术方式来让我们的世界更安全、更高效。然而&#xff0c;随着数字化建设和生产经营管理活动的长期开展&#xff0…...

(aaai2025) FD2-Net: Frequency-Driven Feature Decomposition Network

论文&#xff1a;FD2-Net: Frequency-Driven Feature Decomposition Network for Infrared-Visible Object Detection 代码&#xff1a;https://github.com/like413/FD2-Net 这个论文核心思想认为&#xff1a;多源融合目标检测方法忽略了频率上的互补特征&#xff0c;如可见光图…...

深度学习之目标检测——RCNN

Selective Search 背景:事先不知道需要检测哪个类别,且候选目标存在层级关系与尺度关系 常规解决方法&#xff1a;穷举法&#xff0c;在原始图片上进行不同尺度不同大小的滑窗&#xff0c;获取每个可能的位置 弊端&#xff1a;计算量大&#xff0c;且尺度不能兼顾 Selective …...

2014年IMO第3题

在凸四边形 A B C D ABCD ABCD 中, ∠ A B C = ∠ A D C = π 2 \angle ABC=\angle ADC=\frac{\pi}{2} ∠ABC=∠ADC=2π​, H H H 为 A A A 在 B D BD BD 上的投影, 在边 A B AB AB 上有一点 S S S, ∠ C H S − ∠ C S B = π 2 \angle CHS-\angle CSB=\frac{\pi}{2} …...

国高材服务 | 高分子结晶动力学表征——高低温热台偏光显微镜

众所周知&#xff0c;聚合物制品的实际使用性能&#xff08;如光学透明性、硬度、模量等&#xff09;与材料内部的结晶形态、晶粒大小及完善程度有着密切的联系&#xff0c;因此&#xff0c;对聚合物结晶形态等的研究具有重要的理论和实际意义。 随着结晶条件的不用&#xff0c…...

跨站请求伪造之基本介绍

一.基本概念 1.定义 跨站请求伪造&#xff08;Cross - Site Request Forgery&#xff0c;缩写为 CSRF&#xff09;漏洞是一种网络安全漏洞。它是指攻击者通过诱导用户访问一个恶意网站&#xff0c;利用用户在被信任网站&#xff08;如银行网站、社交网站等&#xff09;的登录状…...

Hadoop集群(HDFS集群、YARN集群、MapReduce​计算框架)

一、 简介 Hadoop主要在分布式环境下集群机器&#xff0c;获取海量数据的处理能力&#xff0c;实现分布式集群下的大数据存储和计算。 其中三大核心组件: HDFS存储分布式文件存储、YARN分布式资源管理、MapReduce分布式计算。 二、工作原理 2.1 HDFS集群 Web访问地址&…...

单元测试(UT,C++版)经验总结(gtest+gmock)

最近做了一段测试工作&#xff0c;其中包括单元测试&#xff0c;编程语言是C。这里提供一些基本知识总结&#xff0c;方便入门单元测试。 1.单元测试介绍 单元测试&#xff08;Unit Testing, 简称UT&#xff09;是软件测试的一种方法&#xff0c;目的是通过对单个软件组件&am…...

Mysql高级部分总结(二)

MySQL的内部日志 binlog记载的是update/delete/insert这样的SQL语句,而redo log记载的是物理修改的内容(xxxx页修改了xxx)。 binlog无论MySQL用什么引擎,都会有,而redo log是MySQL的InnoDB引擎所产生的。 redo log事务开始的时候,就开始记录每次的变更信息,而binlog是在…...

纠正一下网络管理

先找到那个hrStorageType 这里我的值是 后面的值.1.3.6.1.2.1.25.2.1.4代表磁盘 我只有2个盘 C盘和D盘 所以这里只有2个 你们有E盘F盘的话 这里会多 .1.3.6.1.2.1.25.2.1.2 代表内存 .1.3.6.1.2.1.25.2.1.2 前面是 hrStorageType.4 所以 这里面.4后缀是表示内存的 之前…...

homebrew,gem,cocoapod 换源,以及安装依赖

安装homebrew /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)" 再按照成功提示配置环境变量 ruby 更新ruby到最新 brew install ruby 如果安装了会自动升级 安装完成后根据提示配置环境变量 再执行命令使其生效 s…...

Java字符串的|分隔符转List实现方案

字符串处理 问题背景代码实现代码优化原因分析实现方案 注意事项异常处理Maven未识别异常 问题背景 在项目组对账流程中&#xff0c;接收对方系统的对账文件&#xff0c;数据以|为分隔符&#xff0c;读取文件内容&#xff0c;分条入库。 代码实现 Java中将字符串转给list&am…...

Kafka可视化工具 Offset Explorer (以前叫Kafka Tool)

数据的存储是基于 主题&#xff08;Topic&#xff09; 和 分区&#xff08;Partition&#xff09; 的 Kafka是一个高可靠性的分布式消息系统&#xff0c;广泛应用于大规模数据处理和实时, 为了更方便地管理和监控Kafka集群&#xff0c;开发人员和运维人员经常需要使用可视化工具…...

DeepWalk 原理详解

概述&#xff1a; DeepWalk 是一种流行的图嵌入方法&#xff0c;用于学习图结构数据中节点的低维表示。它通过将图的节点视作序列数据&#xff0c;利用自然语言处理中的技术&#xff08;类似于word2vec算法&#xff09;来捕捉节点间的关系&#xff0c;可以帮助我们理解和利用图…...

GitLab安装|备份数据|迁移数据及使用教程

作者&#xff1a; 宋发元 最后更新时间&#xff1a;2024-12-24 GitLab安装及使用教程 官方教程 https://docs.gitlab.com/ee/install/docker.html Docker安装GitLab 宿主机创建容器持久化目录卷 mkdir -p /docker/gitlab/{config,data,logs}拉取GitLab镜像 docker pull gi…...

后进先出(LIFO)详解

LIFO 是 Last In, First Out 的缩写&#xff0c;中文译为后进先出。这是一种数据结构的工作原则&#xff0c;类似于一摞盘子或一叠书本&#xff1a; 最后放进去的元素最先出来 -想象往筒状容器里放盘子&#xff1a; &#xff08;1&#xff09;你放进的最后一个盘子&#xff08…...

C++_核心编程_多态案例二-制作饮品

#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为&#xff1a;煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例&#xff0c;提供抽象制作饮品基类&#xff0c;提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

全球首个30米分辨率湿地数据集(2000—2022)

数据简介 今天我们分享的数据是全球30米分辨率湿地数据集&#xff0c;包含8种湿地亚类&#xff0c;该数据以0.5X0.5的瓦片存储&#xff0c;我们整理了所有属于中国的瓦片名称与其对应省份&#xff0c;方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放

简介 前面两期文章我们介绍了I2S的读取和写入&#xff0c;一个是通过INMP441麦克风模块采集音频&#xff0c;一个是通过PCM5102A模块播放音频&#xff0c;那如果我们将两者结合起来&#xff0c;将麦克风采集到的音频通过PCM5102A播放&#xff0c;是不是就可以做一个扩音器了呢…...

【算法训练营Day07】字符串part1

文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接&#xff1a;344. 反转字符串 双指针法&#xff0c;两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

自然语言处理——Transformer

自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效&#xff0c;它能挖掘数据中的时序信息以及语义信息&#xff0c;但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN&#xff0c;但是…...

(转)什么是DockerCompose?它有什么作用?

一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用&#xff0c;而无需手动一个个创建和运行容器。 Compose文件是一个文本文件&#xff0c;通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...

CMake控制VS2022项目文件分组

我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

IP如何挑?2025年海外专线IP如何购买?

你花了时间和预算买了IP&#xff0c;结果IP质量不佳&#xff0c;项目效率低下不说&#xff0c;还可能带来莫名的网络问题&#xff0c;是不是太闹心了&#xff1f;尤其是在面对海外专线IP时&#xff0c;到底怎么才能买到适合自己的呢&#xff1f;所以&#xff0c;挑IP绝对是个技…...

云原生安全实战:API网关Kong的鉴权与限流详解

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关&#xff08;API Gateway&#xff09; API网关是微服务架构中的核心组件&#xff0c;负责统一管理所有API的流量入口。它像一座…...