news 2026/9/7 9:42:12

Java开发必备工具库:字符串、集合、加密、JDBC一站式封装

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java开发必备工具库:字符串、集合、加密、JDBC一站式封装

简介:这是一套面向Java中高级开发者的轻量级通用工具库,聚焦日常开发高频场景,显著降低字符串处理、日期计算、集合操作、文件IO、JDBC封装、JSON解析及HTTP调用等重复编码成本。资源共2000个文件,主体为1920个精心组织的Java工具类(如CharSequenceUtil、FileUtil、CollUtil、DateUtil等),辅以24个XML配置、17个Shell部署脚本、10个Properties参数文件及8份Markdown使用说明,整体压缩包仅3.27MB,结构清晰、即引即用。已有11人学习下载,适合快速集成到Spring Boot或传统Java项目中,无需依赖复杂框架即可获得生产级稳定性与可读性;所有工具类均经过实际项目验证,覆盖边界处理、空值安全、线程友好等细节,附带完整注释与典型用例,大幅缩短开发调试周期。 做了这么多年Java开发,我发现一个很普遍的现象:大部分项目的代码库里,都有大量重复的、自己封装的基础工具类。字符串判空、日期格式化、集合转Map、文件读写……每个项目都要写一遍,换个人风格还不一样,代码质量全靠自觉。后来我开始重度使用功能比较全的Java工具库,这个习惯直接改变了我写业务代码的方式。

今天想聊的这个工具库,核心就一句话:把开发者日常开发中高频使用的操作——字符串、数字、集合、编码、日期、文件、IO、加密、数据库JDBC——全部封装成简单易用的静态方法,让你从重复造轮子中解脱出来。它适合所有Java开发者,不管你是写后端接口、跑批任务,还是做桌面工具,都能用得上。接下来我会从设计思路、核心功能、实操案例和踩坑经验几个角度,把这个工具库讲透。

1. 工具库的整体设计与核心价值

1.1 为什么你需要一个通用工具库

这个问题的答案,要从一个具体场景说起。之前我接手过一个老项目,代码里光是字符串判空的工具类就有三份,分别在不同的包里,命名分别是StringUtil、StringUtils、StrUtils,里面的实现还不完全一样。有的用str == null || "".equals(str),有的用str == null || str.trim().isEmpty(),有的甚至直接str.isEmpty(),连空指针都没处理。业务代码里调用起来五花八门,排查问题的时候非常痛苦。

工具库解决的就是这种问题。它把这些基础能力收敛到一个统一的地方,提供标准、稳定、经过充分测试的实现。你不需要关心isEmpty底层是怎么判断的,只需要知道传入字符串,返回布尔值。更重要的是,工具库的API设计一般都很人性化,方法名直白,参数少,返回值清晰,几乎没有学习成本。

从团队协作的角度看,工具库也是一个很好的规范约束。当大家都在同一个工具库里取用方法时,代码风格会自然趋同,review成本降低,新人上手也更快。我经常跟团队里的小伙伴说,能用工具库解决的,绝对不要自己写,这不是懒,是把精力留给真正有业务价值的部分。

1.2 模块化设计背后的思考

好的工具库一定不是把所有类堆在一个包里的,而是按照职责拆分模块。字符串有字符串的类,日期有日期的类,加密有加密的类,每个模块之间耦合度尽量降低。这种设计的好处非常明显:你只需要引入你用的那个模块,而不是为了一个日期格式化方法把整个库都引进来。

拿依赖体积来说,我之前用过某个大而全的工具库,一个jar包几十兆,里面有很多用不到的功能,白白增加了应用启动时间和打包体积。而这个工具库的设计思路更务实,它支持按需引入,你把工具库-core工具库-crypto工具库-db分开依赖,用哪个引哪个,编译产物干净很多。

模块化还带来一个附加价值:维护成本下降。当某个模块出现bug或需要升级时,影响范围是可控的。实际上在做技术选型时,模块边界是否清晰,也是我判断一个工具库成熟度的重要指标。如果所有功能都塞在一个类里,那这个库用起来也一定会很别扭。

1.3 工具库的适用场景

工具库不是万能的,它适用于很多场景,但也有它不该碰的领域。按照我的经验,下面这些场景它非常能打:

  • Web后端开发:Controller层接收参数、Service层处理业务逻辑,大量的参数校验、数据转换、日期处理、字符串拼接,工具类能帮上大忙。
  • 批处理和定时任务:读写文件、解析日志、数据库批量操作,IO和JDBC模块能省下不少代码量。
  • 单元测试:造测试数据时经常需要随机字符串、随机数字、临时文件,工具库的很多方法用起来非常顺手。
  • 工具类和中间件开发:比如你自己写一个Spring Boot Starter,里面需要加解密、JSON处理、HTTP客户端,工具库可以直接作为基础依赖。

但有一点要提醒:工具库解决的是通用基础操作,不适合封装复杂的业务逻辑。比如订单状态流转、复杂的权限判断,这些应该放在业务层自己实现,硬塞进工具类里反而会让代码变得混乱。

2. 基础工具类:字符串、数字、集合、日期

2.1 字符串处理:不只是判空判非空

字符串操作是日常开发中频率最高的基础操作之一。这个工具库的字符串工具类,我用的最多的就是判空、去空、截断、格式化这几个能力。

先说判空。工具库里的方法通常会区分两种情况:一个是isEmpty,判断字符串是否为null或空字符串;另一个是isBlank,判断字符串是否为null、空字符串或纯空白字符(空格、制表符、换行)。这两个方法的使用场景完全不同,比如做参数校验的时候,用户传了个全角空格,你以为他传了内容,实际上他什么都没填,这时候用isBlank更合适。我之前就因为判空逻辑写得粗,线上出现了不少诡异问题,后来统一改用工具库的isBlank之后,这类问题基本绝迹了。

截断操作也是高频需求。我之前做过一个消息推送的功能,短信内容超过字数限制就要截断,之前自己写的时候要考虑中文字节数、末尾标点、截断后加省略号,逻辑写了一大堆。工具库直接提供了sub方法,支持按长度截取,如果截断位置刚好落在中文中间还会自动处理,避免出现乱码。它内部考虑了很多边界情况,这是自己临时写的代码很难比的。

字符串格式化和拼接也值得一提。以前Java字符串拼接喜欢用+号,后来用StringBuilder,再后来用String.format,但都不够优雅。工具库提供的字符串模板功能,类似于StrUtil.format("你好,{}!欢迎回来", name),花括号占位符直观易懂,性能也做了优化。实际在写日志、拼SQL、生成短信模板的时候非常好用。

还有一个很实用的小功能,字符串去重、驼峰转下划线、下划线转驼峰。特别是在写Java项目对接数据库字段、前端传参的时候,动不动就要做这种命名风格转换。工具库一行代码搞定,不需要自己写正则。

2.2 数字与集合操作:数据处理的效率利器

数字工具类最实用的场景是什么?我觉得是各种类型转换和精度计算。

类型转换在开发中太常见了,比如把字符串转成Integer、Long、BigDecimal,还要处理转换失败的情况。工具库提供了NumberUtil.parseInt这类方法,支持传入默认值,NumberUtil.parseInt("abc", 0),转换失败就返回默认值,不会抛异常。这在处理外部接口返回的数据时特别有用,比如对接第三方API,对方的返回字段可能五花八门,用安全转换能避免很多潜在的运行时异常。

集合操作是另一个重头戏。Java原生的Collections工具类提供了排序、查找等方法,但功能偏基础。工具库的集合工具类做得更贴近业务场景。比如你把一个User对象的List,按userId转成Map,这个操作原生Java写起来要写好几行循环,工具库提供了CollUtil.toMap,一行搞定。

还有一个很常用的能力:集合判空。我见过太多list != null && list.size() > 0这种写法了,工具库直接CollUtil.isEmpty(list),语义清晰,不容易出错。

分组操作在统计报表场景下非常有用。比如把一批订单按状态分组,原生Java要写Map<String, List<Order>>然后循环往里塞,用工具库的方法可以更简洁。虽然Java 8之后Stream API也能做,但Stream的用法本身就有一定的理解门槛,工具库的API更接近普通开发者的思维习惯,用起来上手更快。

列表去重、取交集差集、随机抽取,这些也都有现成方法。我写抽奖活动功能时,用CollUtil.getRandomItems直接就实现了随机抽取若干人的逻辑,避免了手写随机数算法的麻烦。

2.3 日期时间处理:兼容新旧API的桥接

日期处理这块,Java历来是个深坑。SimpleDateFormat线程不安全,CalendarAPI反人类,Java 8之后虽然有java.time包,但很多老项目还在用旧API,两边切换很痛苦。工具库的日期工具类解决了这个痛点,它兼容新旧两种日期体系,内部做了桥接。

我最常用的几个场景:获取当前时间直接格式化输出、日期字符串解析为Date对象、日期加减天数小时数、计算两个日期之间的间隔。

格式化这一块,工具库做得非常顺手。比如DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"),返回的字符串格式清爽。还有一个场景很常见,我想拿昨天的日期、下周的日期、上个月的第一天,原生写法要先用Calendar去set,工具库提供了DateUtil.offsetDay(date, -1)DateUtil.beginOfMonth(date)这类方法,语义化极强,看一眼就懂。

两个日期相差的天数是业务中特别常算的东西,比如判断用户是否在90天内登录过。手写的时候要考虑时间部分的影响,直接用DateUtil.between(date1, date2, DateUnit.DAY)算出差值,设置好单位就行,内部处理好了时区和夏令时问题。

我提醒一下大家,旧项目中使用旧API的时候,接工具库的时候要注意Date对象和LocalDateTime之间的转换。工具库一般会提供DateUtil.toLocalDateTime这类方法,方便你在新旧API之间无缝切换,不用自己写转换代码。

3. 进阶能力:编码、加密、文件与IO

3.1 加密工具类:对称加密和非对称加密的正确姿势

加密这块是工具库里面技术含量比较高的模块,也是我在项目里用得比较谨慎的模块。工具库的加密模块把Java原生加密API做了很友好的封装,同时提供了常见加密算法的统一入口。

先说对称加密。AES是最常用的对称加密算法,但直接用JDK原生API写AES加解密,代码量相当大。你要自己生成KeyGenerator、初始化Cipher、处理AlgorithmParameterSpec、处理Base64编解码。工具库把这一套流程封装好,你只需要提供密钥,调用encryptdecrypt方法。它还支持选择不同的加密模式和填充方式,比如ECB、CBC、PKCS5Padding、NoPadding。

实际使用的时候,我踩过一个坑:AES加密模式如果选择ECB,由于它不支持IV向量,同样的明文和密钥加密出来的密文永远一样,这在某些安全性要求高的场景下是不太合适的。工具库封装了CBC模式,你只需要在构造时提供一个IV参数,剩下的加解密细节都处理好。我自己在做接口签名、传输数据加密时,都推荐使用CBC模式。

非对称加密这块,RSA是标配。工具库支持生成密钥对、公钥加密私钥解密、私钥加密公钥解密。还有一个很好的能力,支持从PEM格式的字符串读取密钥,这样对接外部系统时,他们给你一个证书文件,你能很方便地加载进来。

摘要算法(消息摘要)也非常常用。MD5、SHA-1、SHA-256,工具库提供了统一调用方式,一行代码算出一个文件的哈希值。我用这个做过文件上传后校验完整性,接口返回的MD5值和实际文件算出来的一致,再确认上传没有损坏。

大家要注意,加密库的使用必须对密钥做好管理。密钥一旦泄露,加密就是形同虚设。实际项目中我用过从环境变量读取密钥的方式,避免把密钥硬编码在代码里。另外推荐使用工具库封装好的密钥生成方法,这样能避免因为用户提供的密钥格式不同导致加解密失败。

3.2 文件与IO操作:读写优雅且高效

文件操作是另一个让我感受深刻的模块。原生Java的文件读写,传统的用FileInputStream+BufferedReader,要写try-catch-finally,要记得关闭流,代码又长又容易出错。Java 7之后虽然有try-with-resources,但依然摆脱不了样板代码。

工具库的文件工具类FileUtil,把常用的文件操作都封装成了静态方法。最经典的就是读文件、写文件、复制文件、删除文件。一行FileUtil.readUtf8String(file)就能把整个文件读成字符串,一行FileUtil.writeString(content, file, "UTF-8")就能把字符串写进文件。

我在做一个日志分析工具的时候,需要遍历某个目录下所有日志文件,按行解析。工具库提供了FileUtil.loopFiles,传入目录路径,自动递归获取所有子文件,配合FileUtil.readUtf8Lines将文件的每一行读入List,整个过程代码量很少,而且内存使用也很可控。

IO工具类在Stream层面对字节流和字符流做了强化。比如IoUtil.copy(in, out),一行完成流拷贝。以前自己写流拷贝,要定义一个缓冲区数组,写一个while循环,还要考虑缓冲区大小怎么设置。工具库内部设置了合理缓冲区,性能也很好。

关于大文件处理,我有一个心得。别看工具库提供了FileUtil.readString这种一次性读入的方法,如果文件特别大,比如几个G的日志,直接读会OutOfMemoryError。这种情况下还是要用流式的方式,一行一行读取。工具库同样提供流式读取的方法,只需要传一个Consumer<String>回调,让每行内容通过回调处理,不会把所有行都加载到内存里。

3.3 编码转换:别让乱码问题折磨你

编码问题在国内开发的Java项目里相当突出,因为你经常会遇到不同来源的数据,有的是UTF-8,有的是GBK,有的是GB2312,处理不好就是一片乱码。工具库的编码工具类在这方面帮了大忙。

URLEncoderURLDecoder在Java里对URL编解码支持不够方便,工具库提供URLUtil.encodeURLUtil.decode方法,默认UTF-8编码,还能处理特殊字符。这在写HTTP客户端、构造请求参数时,特别常用。

Base64编码也是一个高频场景。密文传输、图片转码、token生成,都会用到Base64。工具库的Base64类提供了编解码方法,也支持URL安全模式,生成的字符不包含+/,可以用在URL参数里。

还有一个实用的十六进制转换工具。比如做加密算法调试时,工具库提供了字节数组和十六进制字符串互转的方法,在查看加密内容时非常有用。

编码问题排查有个经验要分享:不要在现象层去猜编码方式,要看数据的来源。比如一个字符串是乱码,先确认它原始编码是什么,再确认当前解码用了什么编码,两边一致才不会有乱码。工具库不能帮你自动识别编码,但它可以提供更多便捷的转换方法,帮你快速排查定位。

4. JDBC与数据库操作的封装

4.1 传统JDBC的痛点与工具库的解法

JDBC是Java连接数据库的基础技术,但是直接用原生JDBC写数据库操作,体验非常糟。你要手动注册驱动、获取连接、创建Statement、执行SQL、处理ResultSet、关闭连接,每一步都有可能出错,而且大量样板代码。

在Spring项目里,大部分人会直接用JdbcTemplate或MyBatis框架,但在非Spring的纯Java项目里,或者一些小的工具集项目里,封装好的JDBC工具类就很香。工具库的JDBC模块把核心的数据库操作封装成了简洁的方法,你只需要传SQL语句和参数,就能完成查询、更新、插入、删除操作。

通过Db.use()获取一个数据库操作入口,然后db.query("select * from user where id = ?", 1)返回的是一个Entity对象(类似一个Map),db.execute("update user set name = ? where id = ?", "张三", 1)执行更新操作。

这种设计天然适合数据量不大、SQL逻辑不复杂的场景,你在测试工具、运维脚本、轻量级后台服务里会很顺手。

4.2 我常用的JDBC工具场景

让我举几个实际使用场景。第一个是做数据迁移脚本。有一次我需要把旧系统的用户数据导入新系统的数据库,字段名、表结构都不太一样。直接用工具库的JDBC模块,从旧库查出来一个List ,然后遍历,把字段名映射成新库的字段,再插入新库,整个过程代码非常精炼。

第二个场景是动态查询。某些后台管理系统的搜索条件非常灵活,需要根据用户输入动态拼SQL。因为SQL是按条件拼接的,参数也要动态传递。工具库的Db支持传参数数组,拼SQL时把参数收集到一个List里再转成数组传入,实现非常方便。

第三个场景是批量操作。工具库也提供了批量执行能力,对大批量数据插入效率有提升。不过我做批量插入更推荐使用数据库原生的批处理特性,工具库底层实现的批处理还是通过循环执行,如果数据量特别大,还是建议考虑专门的批处理手段。

4.3 数据库连接池的搭配建议

这里有一个非常关键的坑要跟大家提:工具库JDBC模块本身不管理连接池,它默认每次操作都新建连接。在低并发的工具类场景下没问题,但如果在Web应用里,频繁创建销毁连接会导致数据库连接数暴涨。所以正式环境一定要搭配连接池使用。

我自己搭配过的方案是使用HikariCP,这是目前Java生态里比较快的连接池。配置好HikariDataSource,然后把这个DataSource传给工具库的Db.use(),后续所有操作都会复用连接池的连接,不用每次新建。这样既保留了工具库API的简洁性,又解决了连接管理的问题。

配置连接池的时候,有几个参数值得注意:maximumPoolSize(最大连接数)、minimumIdle(最小空闲连接数)、connectionTimeout(获取连接超时时间)、maxLifetime(连接最大生命周期)。这些参数要根据你的并发量和数据库实际承受能力来调,不能盲目设置。之前我有个项目并发量并不高,但连接池最大连接数设置得太大,导致数据库接近崩溃,后来调整之后问题解决。

5. 常见问题与排查技巧实录

5.1 工具库使用中的典型问题

第一个问题,版本冲突。工具库的低版本和高版本之间API可能有变化,如果你的项目里间接依赖了不同版本,Maven依赖解析可能会导致运行时方法找不到。排查方法是运行mvn dependency:tree查看依赖树,找到冲突的版本,然后统一指定版本号。我之前就被这个问题坑过一次,本地编译没问题,部署到服务器上运行就报NoSuchMethodError,最后发现是依赖了老版本。

第二个问题,加密模块的密钥长度限制。AES算法对密钥长度有要求,一般是128位、192位、256位,如果你传入的密钥字符串长度不对,工具库会抛异常。这个在处理不同合作方的需求时特别容易踩坑。解决办法是统一约定密钥的编码方式,比如约定密钥是Base64编码后的字节数组,在代码里先解码再使用。

第三个问题,IO操作中的资源释放。虽然工具库封装了流操作,但如果你用的是一些底层方法,还是要自己负责关闭流。有的方法接收外部传入的InputStream,你不确定它是否会自动关闭,这一点最好查阅文档确认。我在写文件上传接口时,一开始以为工具库会帮我关闭输入流,结果导致文件句柄泄漏,最后手动关闭之后才稳定。

第四个问题,日期格式的线程安全性。如果使用工具库的静态方法处理日期,内部的设计一般都是线程安全的。但如果你在代码里用了SimpleDateFormat作为成员变量,还是会出现线程安全问题。建议统一使用工具库的方法,不要自己持有SimpleDateFormat实例。

5.2 避坑技巧分享:如何让工具库用得更顺

这里分享几个我实践下来非常有用的技巧。

第一,善用内省提示和IDE的自动补全。工具库类的命名都很直白,比如StrUtilNumberUtilCollUtilDateUtilFileUtilIoUtilSecureUtil。你只要记住这几个类名,剩下的方法都可以通过IDE自动补全来查找,不需要死记硬背。这极大降低了工具库的入门成本。

第二,封装一层你自己的工具入口。如果项目里用到工具库的地方非常多,可以考虑在自己的项目里再包一层XxxUtils,内部调用工具库方法,未来如果要换工具库或者改变实现,只需要改这个入口类。这个设计我觉得对长期维护特别有价值,也是我做过的最正确的封装决策之一。

第三,避免滥用反射和方法句柄。工具库在处理某些通用功能时可能会使用反射,比如Bean拷贝、实体转换。如果你的项目性能敏感,建议在关键路径上避免使用这类通用方法,而是手写字段赋值。我自己在写核心交易链路时,就严格控制了反射的使用。

第四,做好工具库版本的定期升级。工具库也在不断迭代,修复bug、增加新功能,建议关注其版本发布日志,定期升级到较新的稳定版本。升级前先在本地分支跑全量测试,避免新版本的影响。

第五,阅读源码了解实现细节。遇到奇怪问题的时候,直接去看工具库的源码。工具库本身的代码质量一般不错,源码注释也比较清晰,读源码不仅能解决问题,还能学到很多编程技巧。我靠这个方式解决了不止一个疑难杂症。

5.3 关于工具库的误用场景,我要多说几句

工具库是个好帮手,但它不是银弹。我最想提醒的是,不要在业务代码里过度依赖工具库,导致业务逻辑变成一堆工具类调用,失去了可读性。

比如有一段代码,判断一个订单是否满足发货条件,如果整段逻辑全部用工具类的各种方法串联起来,可能在代码review时你根本看不明白它到底在做什么。遇到这种情况,还是应该把业务判断抽成有语义的私有方法,内部再调用工具类辅助实现。

另外,有些工具库方法看起来很强大,但背后可能会做一些很重的操作。比如某个链式API,看似一行代码搞定,但内部可能创建了很多临时对象、做了多次遍历。在性能敏感的场景,建议及时通过压测发现问题。

工具库的选择和使用最终要服务于代码的可维护性和业务的高效交付。合理使用工具库,能让你的代码更简洁、稳定,减少自己造轮子带来的隐患;但如果用得不恰当,反而会增加理解和维护的成本。这个平衡,需要在实践中慢慢体会。

我在实际项目里已经积累了很长时间的使用经验,最大的体会是:工具库不是银弹,但它确实能让你从重复、琐碎的基础代码里解放出来,让你有更多精力关注业务本身。对Java开发者来说,掌握一款顺手的工具库,就像手里多了一把好用的瑞士军刀,应对日常开发的各种小问题都能游刃有余。希望这篇文章能帮你更好地理解它、使用它,少踩一些我踩过的坑。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/6 13:02:09

合同管理系统开发等保 2.0 三级技术落地:加密、RBAC、审计与密钥管理的工程实现

等保 2.0 三级是金融、政务类合同系统的准入门槛。密评不是"上云 开 HTTPS"就完事&#xff0c;它会逐条核对口令复杂度、双因素认证、日志留存时长、密钥管理归属。本文给出一套可落地、且天然契合信创语境的数据安全架构。 一、三级到底卡什么三级核心要求可浓缩为…

作者头像 李华
网站建设 2026/9/6 11:27:54

蚁小二的视频和图文分发有什么区别,支持哪些内容类型

很多新手在使用蚁小二的时候&#xff0c;分不清平台视频分发和图文分发的具体区别&#xff0c;也不清楚工具具体支持哪些内容类型&#xff0c;很容易出现发文格式错误、发布失败、内容不匹配平台规则的问题。本文所有功能介绍均严格参照蚁小二官方公开功能与规则撰写&#xff0…

作者头像 李华
网站建设 2026/9/4 8:35:12

C语言字符串数组详解:二维数组与指针数组的核心区别

字符串数组是 C 语言里最容易让人绕晕的知识点之一。很多初学者学到数组时觉得没问题&#xff0c;学到指针时也勉强能跟上&#xff0c;但一碰到“字符串数组”这个概念&#xff0c;就开始分不清char name[3][20]和char *name[3]到底有什么区别&#xff0c;更不用说在写用户名单…

作者头像 李华
网站建设 2026/9/4 7:36:46

C语言字符串数组:二维数组与指针数组的本质区别与工程选择

字符串数组在C语言里看起来很简单&#xff1a;不就是一堆字符串装进一个数组吗&#xff1f;但真上手写几行代码&#xff0c;很多人会发现不对劲——为什么有时候能改字符串里的字符&#xff0c;有时候一改就崩溃&#xff1f;为什么char *names[]和char names[][20]看着差不多&a…

作者头像 李华
网站建设 2026/9/6 5:26:01

P4角色桌Replay完结篇:雪山密室的终局推理与叙事复盘

这个标题信息量其实很大&#xff1a;P4、角色桌、Replay、完结篇、雪山密室、第九话、灯推理。它既是一个创作项目的收尾&#xff0c;也是一个非常典型的“叙事型角色桌Replay”作品。这篇博客不写代码&#xff0c;但要把它当成一个完整的“创作项目”来拆解&#xff1a;这个系…

作者头像 李华
网站建设 2026/9/4 11:52:32

【图论】最短路径-----Dijkstra篇

文章目录【图论】最短路径Dijkstra算法朴素版代码实现堆优化图的存储实现代码结构体形式pair形式例题【图论】最短路径 算法单源 / 多源支持负权边检测负权环时间复杂度适合场景Dijkstra&#xff08;堆优化&#xff09;单源不支持❌O(mlogn)无负权&#xff0c;稀疏图&#xff…

作者头像 李华