Compare commits

...

34 Commits

Author SHA1 Message Date
1509597032
Merge pull request 'dev' (#12) from dev into master
Reviewed-on: #12
2025-09-21 15:41:49 +08:00
ac92f62967
build(jdk8): 更新构建脚本中的 Kotlin 和 Dokka 插件版本- 在 jdk8/build.gradle.kts 中添加了 Kotlin JVM 插件和 Dokka 插件
- 更新 `build.gradle.kts` 中的 Dokka 版本从2.1.0-Beta 到2.0.0- 调整了 Gradle 任务依赖方式,使用字符串名称替代任务引用
- 升级项目版本号从 4.1.8 到 4.1.9
2025-09-21 15:39:14 +08:00
683aeb2c7f
```
feat(stream): 优化 SuperStream 的 toArray 方法实现- 调整 toArray 方法,支持传入 Class 参数以正确创建泛型数组
- 原无参 toArray 方法改为返回 Object[],避免类型转换异常
- 移除对 ForEach 工具类的依赖
- 提升流处理中数组转换的灵活性与安全性

```

```
feat(collection): 改进 toArray 工具方法支持泛型数组创建

- 新增基于 reified 泛型的 toArray 扩展方法,自动推断数组类型
- 添加带 Class 参数的 toArray 重载方法,用于明确指定元素类型
- 处理空列表时直接返回空数组,避免后续操作异常

```

```
build(gradle): 升级 dokka 插件版本并更新项目依赖- 将 org.jetbrains.dokka 插件升级至 2.1.0-Beta 版本
- 添加 jna5.17.0 依赖用于本地库调用支持
- 引入 mybatis-plus-core 3.0.1 编译依赖
- 更新项目版本号从 4.1.7 至 4.1.8

```
2025-09-21 14:37:22 +08:00
5eed682aa1
feat(utils): 添加 MyBatis-Plus 查询包装器支持
在 build.gradle.kts 中替换 JNA依赖为 mybatis-plus-core,并新增BaseMapperQuery 接口,提供通用的 QueryWrapper 实例创建方法,便于MyBatis-Plus 相关操作的统一封装与复用
2025-09-20 14:22:14 +08:00
578f0a3e89
fix(collection): 抑制类型转换警告并更新文件时间戳修复了 Collection.kt 文件中的类型转换警告问题,通过添加 @Suppress("UNCHECKED_CAST")
注解来抑制编译器警告。同时更新了文件的最后修改时
2025-09-20 14:05:41 +08:00
075dc2346a
feat(utils): 更新工具类并优化集合扩展函数
- 更新多个工具类的最后修改时间和用户信息
- 移除冗余的 main 函数测试代码
- 优化 ByteUtils 中流处理方法的引用- 为 Collection 扩展大量实用函数,包括转换、获取元素和创建集合实例等
- 引入 SuperStream 替代部分自定义流处理逻辑
- 调整 Spring Boot 自动配置包扫描路径- 修复资源读取时的空指针风险,使用 Kotlin 的 elvis 操作符简化代码
2025-09-20 14:01:36 +08:00
23548c0c3d
refactor(Base91): 更新Base91解码表并添加示例
更新了Base91解码表的初始化方式,并添加了一个示例方法来演示编码和解码功能。

feat(Base256): 添加Base256编解码器

新增了Base256类,实现了Base256编解码功能,并在BaseUtils中添加了相应的实例。

refactor(BaseCodec): 增加字符串编解码方法

在BaseCodec接口中增加了对字符串进行Base64编码和解码的方法。refactor(OsPath): 简化路径处理逻辑

移除了OsPath类中不必要的方法实现,简化了路径处理逻辑。

feat(UUID): 支持Base256短字符串

在UUID类中添加了对Base256短字符串的支持,包括编码和解码方法。
2025-09-18 14:43:01 +08:00
4b187f3774
添加 String.join 的文档
添加 List.join 的文档
添加 split 的文档
2025-09-18 09:28:06 +08:00
c90c1d590b
修改 List.join 为<T> 2025-09-18 09:24:43 +08:00
42a3302495
添加 String.join 方法 2025-09-18 09:23:19 +08:00
496c3e6248
更新List.join方法 2025-09-18 09:22:55 +08:00
9002f41c63
Merge pull request 'dev' (#11) from dev into master
Reviewed-on: #11
2025-09-17 21:20:20 +08:00
58806e85f1
refactor(bcrypt): 重构 BCrypt.kt 文件
- 将 BCrypt 对象中的函数转换为顶级函数
- 添加 @JvmName 注解以自定义 JVM 方法名
- 更新相关文件中的导入和引用
- 调整 DateTime 类的 parse 和 format 方法
- 优化 StringUtils 中的 isEmpty 方法
2025-09-17 21:15:39 +08:00
0f5748d55d
feat(utils): 添加 BCrypt 加密工具类
- 新增 BCrypt.kt 文件,提供 BCrypt 加密相关方法
- 更新 build.gradle.kts,调整依赖项和版本
- 更新 gradle.properties,升级版本号至 4.1.1
- 更新 HashUtils.kt,使用新的 BCrypt 工具类
- 添加 NOTICE 文件,记录第三方软件的版权声明
2025-09-17 12:10:53 +08:00
8f8ffc72db
Merge pull request 'feat(build): 重构项目并添加 Maven 发布支持' (#10) from dev into master
Some checks failed
Gitea Actions Build / Build (push) Failing after 2s
Reviewed-on: #10
2025-09-17 11:12:41 +08:00
fcd528a821
feat(build): 重构项目并添加 Maven 发布支持
- 更新 .gitignore 文件,添加 secret.gpg
- 移除 .prettierrc 文件
- 重构 AES 加密工具类,使用新的 Base64 实现
- 新增 Base16、Base64 和 Base91 编解码工具类
- 新增 BaseCodec接口和 BaseUtils 工具类
- 更新 build.gradle.kts 配置,添加 Maven 发布和签名
- 修复 ByteUtils 和 DateTime 工具类中的问题
- 重构 UUID 使用自己的实现 不依赖标准库以及其他的 UUID库
2025-09-17 11:12:10 +08:00
0450e87c13
Merge pull request 'dev' (#9) from dev into master
All checks were successful
Gitea Actions Build / Build (push) Successful in 3m11s
Reviewed-on: #9
2025-09-15 22:33:56 +08:00
541a8a82b4
feat(network): 添加网络地址和端口相关工具类
- 新增 NetworkAddress 类用于表示网络地址,支持 IPv4 和 IPv6
- 新增 NetworkPort 类用于表示端口号
- 新增 NetworkEndpoint 类用于封装网络地址和端口信息
- 优化 AutoConfiguration 类,添加更多系统信息
- 更新 AesUtils、Base64Utils等类的版本信息
- 删除 Minecraft SLF 相关无用代码
- 更新项目版本号至 4.0.7
2025-09-15 22:32:56 +08:00
7c3c13e28c
feat(utils): 更新版本号并优化 UUID 功能
- 将项目版本号从 4.0.5 升级到 4.0.6
- 更新 Main.kt 文件,使用 UUID 替代 DateTime
- 改进 UUID.kt 中的 equals 方法,支持与 JUUID 类型的比较
2025-09-15 18:03:35 +08:00
e4bb9884c1
Merge pull request 'refactor(stream): 重构流处理相关代码' (#8) from dev into master
All checks were successful
Gitea Actions Build / Build (push) Successful in 2m21s
Reviewed-on: #8
2025-09-15 17:27:10 +08:00
cc3156572f
refactor(stream): 重构流处理相关代码
- 移除 InOutSteam、InputStreanWrapper、OutputStreamWrapper 类
- 删除 Getable、GetIdable、GetKeyable、GetNameable 接口- 更新 ByteUtils 和 Collection.kt 中的流处理逻辑
- 新增 InputStreamUtils.kt 文件,提供输入流相关扩展函数
- 更新项目版本号至 4.0.5
2025-09-15 17:26:39 +08:00
0b1aac8ecc
Merge pull request 'refactor(mybatis): 更新类型处理器以支持 JDBC 类型参数为 null' (#7) from dev into master
All checks were successful
Gitea Actions Build / Build (push) Successful in 2m25s
Reviewed-on: #7
2025-09-15 13:55:22 +08:00
9a6c6cd662
refactor(mybatis): 更新类型处理器以支持 JDBC 类型参数为 null
- 修改 DateTimeTypeHandler、MysqlUUIDBinaryTypeHandler 和 UUIDTypeHandler
- 将 setNonNullParameter 方法的 jdbcType 参数变更为可空类型
- 更新方法实现以适应新的可空参数
- 提升代码的健壮性和灵活性,允许在某些情况下不指定 JDBC 类型
2025-09-15 13:55:01 +08:00
3d1f249970
Merge pull request 'dev' (#6) from dev into master
Some checks failed
Gitea Actions Build / Build (push) Failing after 2m14s
Reviewed-on: #6
2025-09-15 12:46:12 +08:00
b329953377
feat(foreach): 增加带有提前终止功能的遍历方法并优化代码结构
- 新增 forEachB 系列函数,支持在遍历过程中提前终止
- 为数组和集合添加专门的 forEach 和 forEachB 函数
- 优化现有 forEach 函数的实现,提高性能
- 添加针对 Map 类型的 forEachMap 和 forEachMapB 函数
- 更新函数注释,明确参数和返回值的含义
2025-09-15 12:45:59 +08:00
f9e96fccd3
feat(foreach): 增加带有提前终止功能的遍历方法并优化代码结构
- 新增 forEachB 系列函数,支持在遍历过程中提前终止
- 为数组和集合添加专门的 forEach 和 forEachB 函数
- 优化现有 forEach 函数的实现,提高性能
- 添加针对 Map 类型的 forEachMap 和 forEachMapB 函数
- 更新函数注释,明确参数和返回值的含义
2025-09-15 12:45:16 +08:00
d6517287d1
Merge pull request 'feat(utils): 添加 foreach 扩展函数并更新项目版本' (#5) from dev into master
All checks were successful
Gitea Actions Build / Build (push) Successful in 2m4s
Reviewed-on: #5
2025-09-15 12:01:58 +08:00
33999bf4c6
feat(utils): 添加 foreach 扩展函数并更新项目版本
- 新增 ForEach.kt 文件,提供多种 foreach 函数实现
- 更新项目版本至 4.0.2
- 修改 gradle-wrapper.properties 和 gradlew 文件,更新 Gradle 分发 URL
2025-09-15 12:01:38 +08:00
533ba9bed7
Merge pull request 'refactor(time): 重构 DateTime 类并添加新功能' (#4) from dev into master
Some checks failed
Gitea Actions Build / Build (push) Failing after 1m54s
Reviewed-on: #4
2025-09-15 11:33:46 +08:00
b19fcba67b
refactor(time): 重构 DateTime 类并添加新功能
- 从 Java 文件中删除了旧的 DateTime 类
- 新增 Kotlin 版本的 DateTime 类,具有以下改进:
  - 添加了时间格式化枚举类 Formatter
  - 新增时间位移类 DateTimeOffset - 重构了 parse 和 format 方法,支持新的 Formatter 枚举  - 优化了文件时间转换方法,使用纳秒精度
- 删除了旧的 DateTimeJsonConverter 类
2025-09-15 11:33:09 +08:00
092947d81a
Merge pull request 'refactor(time): 重构 DateTime 类并添加新功能' (#3) from dev into master
Some checks failed
Gitea Actions Build / Build (push) Failing after 2m30s
Reviewed-on: #3
2025-09-15 11:20:38 +08:00
7526b2e787
refactor(time): 重构 DateTime 类并添加新功能
- 从 Java 文件中删除了旧的 DateTime 类
- 新增 Kotlin 版本的 DateTime 类,具有以下改进:
  - 添加了时间格式化枚举类 Formatter
  - 新增时间位移类 DateTimeOffset - 重构了 parse 和 format 方法,支持新的 Formatter 枚举  - 优化了文件时间转换方法,使用纳秒精度
- 删除了旧的 DateTimeJsonConverter 类
2025-09-15 11:20:08 +08:00
6a7d73091e
Merge pull request 'refactor(mingli-utils):重构集合工具类并添加新功能' (#2) from dev into master
All checks were successful
Gitea Actions Build / Build (push) Successful in 2m4s
Reviewed-on: #2
2025-09-15 09:32:42 +08:00
dc129c016f
refactor(mingli-utils):重构集合工具类并添加新功能
- 重写 Collection 类,使用 Kotlin 语法和特性优化代码结构
- 添加新方法以支持数组和集合之间的转换
- 新增 CopyOnWriteArrayList、Stack 和 TreeSet 相关方法
-优化现有方法,提高代码可读性和性能
- 删除未使用的 ForEach 导入
-调整 build.gradle.kts 中的依赖项
2025-09-15 09:30:41 +08:00
146 changed files with 9627 additions and 26726 deletions

1
.gitignore vendored
View File

@ -45,3 +45,4 @@ log
node_modules
*lock*
.kotlin
secret.gpg

View File

@ -1,8 +0,0 @@
{
"$schema": "https://json.schemastore.org/prettierrc",
"plugins": [
"prettier-plugin-java"
],
"tabWidth": 4,
"useTabs": true
}

25
NOTICE Normal file
View File

@ -0,0 +1,25 @@
mingli-utils
Copyright 2025 mingliqiye
This product includes software developed by third parties.
The original copyright notices and licenses are reproduced below.
------------------------------------------------------------
https://github.com/jeremyh/jBCrypt (org.mindrot:jbcrypt@0.4)
Copyright (c) 2006 Damien Miller <djm@mindrot.org>
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
------------------------------------------------------------

167
README.md
View File

@ -1,167 +0,0 @@
# mingli-utils
一个功能丰富的Java工具类库提供字符串处理、时间处理、文件操作、网络工具、哈希计算等常用工具方法。
## 项目概述
mingli-utils 是一个 Java 工具类库,提供各种常用的工具方法,旨在简化开发流程,减少重复代码。
## 技术栈
- JDK 版本: Java 8
- 构建工具: Gradle (Kotlin DSL)
- 依赖库:
- Lombok 1.18.38: 用于简化 Java Bean 代码
- Jackson Databind 2.19.2: 用于 JSON 序列化
- MyBatis 3.5.19: 持久层框架
- Spring Boot Starter 2.7.14: Spring Boot基础依赖
- Bouncy Castle 1.81: 加密算法库
- UUID Creator 6.1.0: UUID生成工具
- jBCrypt 0.4: BCrypt加密实现
- JetBrains Annotations 24.0.0: 注解库
## 主要功能模块
### 字符串处理 (StringUtil)
提供常用的字符串操作方法:
- `toString()`: 对象转字符串
- `format()`: 格式化字符串
- `isEmpty()`: 判断字符串是否为空
- `join()`: 连接字符串
- `split()`: 分割字符串
### 集合工具 (Lists)
提供创建各种List实现的便捷方法
- `newArrayList()`: 创建ArrayList实例
- `newLinkedList()`: 创建LinkedList实例
- `newVector()`: 创建Vector实例
### 时间处理 (time)
提供时间相关功能:
- `DateTime`: 时间处理类封装了LocalDateTime的操作
- `DateTimeOffset`: 时间偏移量处理
- `Formatter`: 常用时间格式枚举
- `DateTimeUnit`: 时间单位常量定义
### 文件操作 (FileUtil)
提供文件读写等操作:
- `readFileToString()`: 读取文件内容为字符串
- `writeStringToFile()`: 将字符串写入文件
- `readLines()`: 读取文件内容为字符串列表(按行分割)
- `writeLines()`: 将字符串列表写入文件(每行一个元素)
- `copyFile()`: 复制文件
- `deleteFile()`: 删除文件
- `exists()`: 检查文件是否存在
- `getFileSize()`: 获取文件大小
### 网络工具 (network)
提供网络地址处理功能:
- `NetworkEndpoint`: 网络端点IP+端口)封装
- `NetworkAddress`: 网络地址处理支持IPv4/IPv6
- `NetworkPort`: 网络端口处理
### 哈希工具 (HashUtils)
提供哈希计算功能:
- `calculateFileHash()`: 计算文件哈希值
- `bcrypt()`: BCrypt加密
- `checkBcrypt()`: 验证BCrypt哈希
### 系统工具 (SystemUtil)
提供系统相关工具方法:
- `isWindows()/isMac()/isUnix()`: 操作系统类型判断
- `getJdkVersion()`: 获取JDK版本
- `getLocalIps()`: 获取本地IP地址
### UUID工具 (uuid)
提供UUID处理功能
- `UUID`: UUID封装类支持时间戳型UUID
### 并发工具 (concurrent)
提供线程安全的数据结构:
- `IsChanged`: 基于CAS操作的线程安全包装类
### 函数式工具 (functions)
提供函数式编程支持:
- `Debouncer`: 防抖器实现
## 使用示例
```java
// 字符串格式化
String message =
StringUtil.format("Hello {}, you are {} years old", "张三", 25);
// 创建列表
List<String> fruits = Lists.newArrayList("苹果", "香蕉", "橙子");
// 连接字符串
String result = StringUtil.join(", ", fruits);
// 时间处理
DateTime now = DateTime.now();
String formatted = now.format(Formatter.STANDARD_DATETIME);
// 文件操作
FileUtil.
writeStringToFile("example.txt","Hello World");
String content = FileUtil.readFileToString("example.txt");
// 网络地址处理
NetworkEndpoint endpoint = NetworkEndpoint.of("127.0.0.1", 8080);
InetSocketAddress address = endpoint.toInetSocketAddress();
// 哈希计算
String hash = HashUtils.bcrypt("password");
boolean matches = HashUtils.checkBcrypt("password", hash);
```
## 构建和运行
使用以下命令构建项目:
```bash
./gradlew build
```
发布到本地Maven仓库
```bash
./gradlew publishToMavenLocal
```
## 项目配置
项目在 `gradle.properties` 中定义了以下配置:
```properties
JDKVERSIONS=1.8
GROUPSID=com.mingliqiye.utils
ARTIFACTID=mingli-utils
VERSIONS=1.0.4
```
## License
本项目采用Apache 2.0许可证,详细信息请查看 [LICENSE](LICENSE) 文件。

View File

@ -16,7 +16,7 @@
* ProjectName mingli-utils
* ModuleName mingli-utils
* CurrentFile build.gradle.kts
* LastUpdate 2025-09-13 10:11:22
* LastUpdate 2025-09-21 15:36:59
* UpdateUser MingLiPro
*/
@ -26,12 +26,12 @@ import java.time.format.DateTimeFormatter
plugins {
idea
java
id("java-library")
id("maven-publish")
signing
`java-library`
`maven-publish`
kotlin("jvm") version "2.2.20"
id("org.jetbrains.dokka") version "2.0.0"
}
val GROUPSID = project.properties["GROUPSID"] as String
val VERSIONS = project.properties["VERSIONS"] as String
val ARTIFACTID = project.properties["ARTIFACTID"] as String
@ -65,23 +65,21 @@ java {
}
dependencies {
annotationProcessor("org.jetbrains:annotations:24.0.0")
annotationProcessor("org.projectlombok:lombok:1.18.38")
implementation("org.slf4j:slf4j-api:2.0.17")
implementation("com.mingliqiye.utils.jna:WinKernel32Api:1.0.1")
// https://github.com/jeremyh/jBCrypt
implementation("org.mindrot:jbcrypt:0.4")
compileOnly("org.springframework.boot:spring-boot-starter:2.7.14")
compileOnly("com.fasterxml.jackson.core:jackson-databind:2.19.2")
compileOnly("com.google.code.gson:gson:2.13.1")
compileOnly("org.mybatis:mybatis:3.5.19")
compileOnly("com.alibaba.fastjson2:fastjson2:2.0.58")
compileOnly("org.projectlombok:lombok:1.18.38")
implementation("org.bouncycastle:bcprov-jdk18on:1.81")
implementation("com.github.f4b6a3:uuid-creator:6.1.0")
implementation("org.mindrot:jbcrypt:0.4")
implementation("org.jetbrains:annotations:24.0.0")
compileOnly("net.java.dev.jna:jna:5.17.0")
implementation("jakarta.annotation:jakarta.annotation-api:2.1.1")
implementation("org.slf4j:slf4j-api:2.0.17")
implementation("com.mingliqiye.utils.jna:WinKernel32Api:1.0.1")
compileOnly("com.baomidou:mybatis-plus-core:3.0.1")
compileOnly("net.java.dev.jna:jna:5.17.0")
}
@ -96,13 +94,14 @@ tasks.withType<JavaExec>().configureEach {
)
}
tasks.withType<org.gradle.jvm.tasks.Jar> {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
from("LICENSE") { into("META-INF") }
from("NOTICE") { into("META-INF") }
manifest {
attributes(
mapOf(
"Main-Class" to "com.mingliqiye.utils.Main",
"Main-Class" to "com.mingliqiye.utils.main.Main",
"Specification-Title" to ARTIFACTID,
"Specification-Version" to VERSIONS,
"Specification-Vendor" to "minglipro",
@ -133,17 +132,16 @@ repositories {
}
mavenCentral()
}
tasks.register<Jar>("javaDocJar") {
group = "build"
archiveClassifier.set("javadoc")
dependsOn(tasks.dokkaJavadoc)
dependsOn("dokkaJavadoc")
from(buildDir.resolve("dokka/javadoc"))
}
tasks.register<Jar>("kotlinDocJar") {
group = "build"
archiveClassifier.set("kotlindoc")
dependsOn(tasks.dokkaHtml)
dependsOn("dokkaHtml")
from(buildDir.resolve("dokka/html"))
}
publishing {
@ -152,6 +150,10 @@ publishing {
name = "MavenRepositoryRaw"
url = uri("C:/data/git/maven-repository-raw")
}
maven {
name = "OSSRepository"
url = uri("C:/data/git/maven-repository-raw-utils")
}
}
publications {
create<MavenPublication>("mavenJava") {
@ -160,8 +162,34 @@ publishing {
artifact(tasks.named("kotlinDocJar"))
artifactId = ARTIFACTID
java.toolchain.languageVersion.set(JavaLanguageVersion.of(8))
pom {
name = "mingli-utils"
url = "https://mingli-utils.mingliqiye.com"
description = "A Java/kotlin Utils"
licenses {
license {
name = "The Apache License, Version 2.0"
url = "http://www.apache.org/licenses/LICENSE-2.0.txt"
}
}
developers {
developer {
id = "minglipro"
name = "mingli"
email = "minglipro@163.com"
}
}
scm {
connection = "scm:git:https://git.mingliqiye.com/minglipro/mingli-utils.git"
developerConnection = "scm:git:https://git.mingliqiye.com:minglipro/mingli-utils.git"
url = "https://git.mingliqiye.com/minglipro/mingli-utils"
}
}
}
}
signing {
sign(publishing.publications)
}
}
tasks.build {
@ -181,7 +209,6 @@ tasks.processResources {
DateTimeFormatter.ofPattern(
"yyyy-MM-dd HH:mm:ss.SSSSSSS"
)
)
)
)

View File

@ -16,10 +16,13 @@
# ProjectName mingli-utils
# ModuleName mingli-utils
# CurrentFile gradle.properties
# LastUpdate 2025-09-14 22:10:29
# LastUpdate 2025-09-21 15:38:52
# UpdateUser MingLiPro
#
JDKVERSIONS=1.8
GROUPSID=com.mingliqiye.utils
ARTIFACTID=mingli-utils
VERSIONS=3.3.2
VERSIONS=4.1.9
signing.keyId=B22AA93B
signing.password=
signing.secretKeyRingFile=secret.gpg

Binary file not shown.

View File

@ -16,12 +16,12 @@
# ProjectName mingli-utils
# ModuleName mingli-utils
# CurrentFile gradle-wrapper.properties
# LastUpdate 2025-09-09 08:37:34
# LastUpdate 2025-09-15 22:32:50
# UpdateUser MingLiPro
#
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://mirrors.aliyun.com/macports/distfiles/gradle/gradle-8.14-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

2
gradlew vendored
View File

@ -18,7 +18,7 @@
# ProjectName mingli-utils
# ModuleName mingli-utils
# CurrentFile gradlew
# LastUpdate 2025-09-09 08:37:33
# LastUpdate 2025-09-15 22:32:50
# UpdateUser MingLiPro
#

View File

@ -16,12 +16,16 @@
* ProjectName mingli-utils
* ModuleName mingli-utils.jdk8
* CurrentFile build.gradle.kts
* LastUpdate 2025-09-14 18:19:04
* LastUpdate 2025-09-21 15:39:12
* UpdateUser MingLiPro
*/
plugins {
id("java-library")
id("maven-publish")
signing
kotlin("jvm") version "2.2.20"
id("org.jetbrains.dokka") version "2.0.0"
}
val GROUPSID = project.properties["GROUPSID"] as String
val VERSIONS = project.properties["VERSIONS"] as String
@ -39,15 +43,44 @@ publishing {
name = "MavenRepositoryRaw"
url = uri("C:/data/git/maven-repository-raw")
}
maven {
name = "OSSRepository"
url = uri("C:/data/git/maven-repository-raw-utils")
}
}
publications {
create<MavenPublication>("mavenJava") {
from(components["java"])
artifactId = "$ARTIFACTID-win-jdk8"
groupId = GROUPSID
version = VERSIONS
java.toolchain.languageVersion.set(JavaLanguageVersion.of(8))
pom {
name = "mingli-utils-win-jdk8"
url = "https://mingli-utils.mingliqiye.com"
description = "A Java/kotlin Utils"
licenses {
license {
name = "The Apache License, Version 2.0"
url = "http://www.apache.org/licenses/LICENSE-2.0.txt"
}
}
developers {
developer {
id = "minglipro"
name = "mingli"
email = "minglipro@163.com"
}
}
scm {
connection = "scm:git:https://git.mingliqiye.com/minglipro/mingli-utils.git"
developerConnection = "scm:git:https://git.mingliqiye.com:minglipro/mingli-utils.git"
url = "https://git.mingliqiye.com/minglipro/mingli-utils"
}
}
}
}
signing {
sign(publishing.publications)
}
}
java.toolchain.languageVersion.set(JavaLanguageVersion.of(8))

23
jdk8/gradle.properties Normal file
View File

@ -0,0 +1,23 @@
#
# Copyright 2025 mingliqiye
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# ProjectName mingli-utils
# ModuleName mingli-utils.jdk8
# CurrentFile gradle.properties
# LastUpdate 2025-09-16 12:14:37
# UpdateUser MingLiPro
#
signing.secretKeyRingFile=../secret.gpg

View File

@ -1 +0,0 @@
lombok.addLombokGeneratedAnnotation = false

View File

@ -1,14 +0,0 @@
{
"name": "maven-repository",
"version": "1.0.0",
"scripts": {
"build": "gradle build-jar",
"buildw": "gradlew build-jar",
"format": "prettier --write \"**/*.{js,ts,jsx,tsx,cjs,cts,mjs,mts,vue,astro,json,java}\"",
"f": "prettier --write \"**/*.{js,ts,jsx,tsx,cjs,cts,mjs,mts,vue,astro,json,java}\""
},
"devDependencies": {
"prettier-plugin-java": "^2.7.1",
"prettier": "^3.6.2"
}
}

View File

@ -16,7 +16,7 @@
* ProjectName mingli-utils
* ModuleName mingli-utils
* CurrentFile settings.gradle.kts
* LastUpdate 2025-09-13 02:37:04
* LastUpdate 2025-09-16 12:32:52
* UpdateUser MingLiPro
*/

View File

@ -1,347 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile Collection.java
* LastUpdate 2025-09-14 22:12:16
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.collection;
import com.mingliqiye.utils.stream.SuperStream;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
/**
* 集合工具类提供对列表和数组的常用操作方法
*
* @author MingLiPro
*/
public class Collection {
/**
* 获取集合的第一个元素
*
* @param collection 集合
* @param <T> 元素类型
* @return 第一个元素如果集合为空或为null则返回 null
*/
@Nullable
public static <T> T getFirst(@Nullable java.util.Collection<T> collection) {
if (collection == null || collection.isEmpty()) {
return null;
}
// 对于List类型直接获取第一个元素
if (collection instanceof List) {
return ((List<T>) collection).get(0);
}
// 对于其他Collection类型使用迭代器获取第一个元素
return collection.iterator().next();
}
/**
* 获取数组的第一个元素
*
* @param list 数组不能为空
* @param <T> 元素类型
* @return 第一个元素如果数组为空则返回 null
*/
@Nullable
public static <T> T getFirst(@NotNull T[] list) {
if (list.length == 0) {
return null;
}
return list[0];
}
/**
* 获取集合的最后一个元素
*
* @param collection 集合
* @param <T> 元素类型
* @return 最后一个元素如果集合为空或为null则返回 null
*/
@Nullable
public static <T> T getLast(@Nullable java.util.Collection<T> collection) {
if (collection == null || collection.isEmpty()) {
return null;
}
// 对于List类型直接获取最后一个元素
if (collection instanceof List) {
List<T> list = (List<T>) collection;
return list.get(list.size() - 1);
}
// 对于其他Collection类型需要遍历到最后一个元素
T lastElement = null;
for (T element : collection) {
lastElement = element;
}
return lastElement;
}
/**
* 获取数组的最后一个元素
*
* @param list 数组不能为空
* @param <T> 元素类型
* @return 最后一个元素如果数组为空则返回 null
*/
@Nullable
public static <T> T getLast(@NotNull T[] list) {
if (list.length == 0) {
return null;
}
return list[list.length - 1];
}
/**
* 获取列表中指定索引的元素如果索引超出范围则返回默认值
*
* @param list 列表
* @param index 索引
* @param defaultValue 默认值
* @param <T> 元素类型
* @return 指定索引的元素或默认值
*/
@Nullable
public static <T> T getOrDefault(
@NotNull java.util.Collection<T> list,
int index,
@Nullable T defaultValue
) {
if (index < 0 || index >= list.size()) {
return defaultValue;
}
return SuperStream.of(list).get(index);
}
/**
* 获取集合中指定索引的元素
* 如果索引超出范围则返回null
*
* @param list 集合
* @param index 索引
* @param <T> 元素类型
* @return 指定索引的元素如果索引超出范围则返回null
*/
@Nullable
public static <T> T get(@NotNull java.util.Collection<T> list, int index) {
return getOrDefault(list, index, null);
}
/**
* 获取数组中指定索引的元素如果索引超出范围则返回默认值
*
* @param array 数组
* @param index 索引
* @param defaultValue 默认值
* @param <T> 元素类型
* @return 指定索引的元素或默认值
*/
@Nullable
public static <T> T getOrDefault(
@NotNull T[] array,
int index,
@Nullable T defaultValue
) {
if (index < 0 || index >= array.length) {
return defaultValue;
}
return array[index];
}
/**
* 获取列表的安全子列表自动处理边界情况
*
* @param list 原始列表
* @param fromIndex 起始索引包含
* @param toIndex 结束索引不包含
* @param <T> 元素类型
* @return 子列表
*/
@NotNull
public static <T> List<T> safeSubList(
@NotNull List<T> list,
int fromIndex,
int toIndex
) {
int size = list.size();
if (size == 0) {
return Collections.emptyList();
}
// 调整边界
fromIndex = Math.max(0, fromIndex);
toIndex = Math.min(size, toIndex);
if (fromIndex >= toIndex) {
return Collections.emptyList();
}
return list.subList(fromIndex, toIndex);
}
/**
* 判断列表是否为空或null
*
* @param list 待检查的列表
* @return 如果列表为null或空则返回true否则返回false
*/
public static boolean isEmpty(@Nullable List<?> list) {
return list == null || list.isEmpty();
}
/**
* 判断数组是否为空或null
*
* @param array 待检查的数组
* @return 如果数组为null或空则返回true否则返回false
*/
public static boolean isEmpty(@Nullable Object[] array) {
return array == null || array.length == 0;
}
/**
* 查找列表中第一个满足条件的元素
*
* @param list 列表
* @param predicate 条件谓词
* @param <T> 元素类型
* @return 第一个满足条件的元素如果没有则返回null
*/
@Nullable
public static <T> T findFirst(
@NotNull List<T> list,
@NotNull Predicate<T> predicate
) {
for (T item : list) {
if (predicate.test(item)) {
return item;
}
}
return null;
}
/**
* 查找数组中第一个满足条件的元素
*
* @param array 数组
* @param predicate 条件谓词
* @param <T> 元素类型
* @return 第一个满足条件的元素如果没有则返回null
*/
@Nullable
public static <T> T findFirst(
@NotNull T[] array,
@NotNull Predicate<T> predicate
) {
for (T item : array) {
if (predicate.test(item)) {
return item;
}
}
return null;
}
/**
* 过滤列表中满足条件的元素
*
* @param list 原始列表
* @param predicate 条件谓词
* @param <T> 元素类型
* @return 包含满足条件元素的新列表
*/
@NotNull
public static <T> List<T> filter(
@NotNull List<T> list,
@NotNull Predicate<T> predicate
) {
List<T> result = new ArrayList<>();
for (T item : list) {
if (predicate.test(item)) {
result.add(item);
}
}
return result;
}
/**
* 过滤数组中满足条件的元素
*
* @param array 原始数组
* @param predicate 条件谓词
* @param <T> 元素类型
* @return 包含满足条件元素的新列表
*/
@NotNull
public static <T> List<T> filter(
@NotNull T[] array,
@NotNull Predicate<T> predicate
) {
return filter(Arrays.asList(array), predicate);
}
/**
* 将列表转换为数组
*
* @param list 列表
* @param clazz 元素类型class
* @param <T> 元素类型
* @return 转换后的数组
*/
@SuppressWarnings("unchecked")
@NotNull
public static <T> T[] toArray(
@NotNull List<T> list,
@NotNull Class<T> clazz
) {
T[] array = (T[]) java.lang.reflect.Array.newInstance(
clazz,
list.size()
);
return list.toArray(array);
}
/**
* 将集合转换为列表
*
* @param collection 集合
* @param <T> 元素类型
* @return 转换后的列表
*/
@NotNull
public static <T> List<T> toList(
@NotNull java.util.Collection<T> collection
) {
return new ArrayList<>(collection);
}
public static <T> SuperStream<T> toSuperStream(
@NotNull java.util.Collection<T> list
) {
return SuperStream.of(list);
}
}

View File

@ -1,579 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile ForEach.java
* LastUpdate 2025-09-14 22:12:16
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.collection;
import com.mingliqiye.utils.functions.P1Function;
import com.mingliqiye.utils.functions.P2Function;
import com.mingliqiye.utils.functions.P3Function;
import java.util.*;
import java.util.concurrent.ConcurrentMap;
/**
* 集合和映射的增强遍历功能
* ListsAMaps 工具类提供对集合和映射的增强遍历功能
* 包含多个重载的 forEach 方法支持带索引的遍历操作<br>
*
* 不可终止的遍历 可以使用 ForEachBreaked
*
* @since 3.0.4
*
* @see com.mingliqiye.utils.collection.ForEachBreaked
* @author MingLiPro
*/
public class ForEach {
/**
* 对给定的可迭代对象执行指定的操作操作包含元素值和索引
* 根据可迭代对象类型选择最优的遍历方式以提高性能
*
* @param iterable 要遍历的可迭代对象
* @param action 要对每个元素执行的操作接收元素值和索引作为参数
* @param <T> 可迭代对象中元素的类型
*/
public static <T> void forEach(
Iterable<T> iterable,
P2Function<? super T, Integer> action
) {
// 参数校验如果集合或操作为空则直接返回
if (iterable == null || action == null) {
return;
}
// 如果集合实现了 RandomAccess 接口 ArrayList使用索引访问优化性能
if (iterable instanceof RandomAccess && iterable instanceof List) {
List<T> list = (List<T>) iterable;
for (int i = 0; i < list.size(); i++) {
action.call(list.get(i), i);
}
}
// 如果是普通 List使用迭代器遍历并手动维护索引
else if (iterable instanceof List) {
int index = 0;
Iterator<T> it = iterable.iterator();
while (it.hasNext()) {
action.call(it.next(), index);
index++;
}
}
// 其他类型的集合使用增强 for 循环并手动维护索引
else {
int index = 0;
for (T element : iterable) {
action.call(element, index);
index++;
}
}
}
/**
* 对给定的可迭代对象执行指定的操作仅处理元素值
* 根据可迭代对象是否实现 RandomAccess 接口选择最优的遍历方式
*
* @param iterable 要遍历的可迭代对象
* @param action 要对每个元素执行的操作只接收元素值作为参数
* @param <T> 可迭代对象中元素的类型
*/
public static <T> void forEach(
Iterable<T> iterable,
P1Function<? super T> action
) {
// 参数校验如果集合或操作为空则直接返回
if (iterable == null || action == null) {
return;
}
// 如果集合实现了 RandomAccess 接口使用索引访问提升性能
if (iterable instanceof RandomAccess) {
List<T> list = (List<T>) iterable;
for (int i = 0; i < list.size(); i++) {
action.call(list.get(i));
}
}
// 否则使用增强 for 循环进行遍历
else {
for (T element : iterable) {
action.call(element);
}
}
}
/**
* 对给定的迭代器执行指定的操作仅处理元素值
* @param iterator 要遍历的迭代器
* @param action 要对每个元素执行的操作只接收元素值作为参数
* @param <T> 迭代器中元素的类型
*/
public static <T> void forEach(
Iterator<T> iterator,
P2Function<? super T, Integer> action
) {
if (iterator == null || action == null) {
return;
}
int index = 0;
while (iterator.hasNext()) {
action.call(iterator.next(), index);
index++;
}
}
/**
* 对给定的迭代器执行指定的操作处理元素值和索引
* @param iterator 要遍历的迭代器
* @param action 要对每个元素执行的操作只接收元素值作为参数
* @param <T> 迭代器中元素的类型
*/
public static <T> void forEach(
Iterator<T> iterator,
P1Function<? super T> action
) {
if (iterator == null || action == null) {
return;
}
while (iterator.hasNext()) {
action.call(iterator.next());
}
}
/**
* 对给定的映射执行指定的操作操作包含键值和索引
* 根据映射类型选择不同的遍历策略
*
* @param map 要遍历的映射
* @param action 要对每个键值对执行的操作接收键值和索引作为参数
* @param <K> 映射中键的类型
* @param <V> 映射中值的类型
*/
public static <K, V> void forEach(
Map<K, V> map,
P3Function<? super K, ? super V, Integer> action
) {
// 参数校验如果映射或操作为空则直接返回
if (map == null || action == null) {
return;
}
// 遍历 TreeMap 的条目集合并传递索引
if (map instanceof TreeMap) {
int index = 0;
for (Map.Entry<K, V> entry : map.entrySet()) {
action.call(entry.getKey(), entry.getValue(), index);
index++;
}
}
// 遍历 ConcurrentMap LinkedHashMap 的条目集合并传递索引
else if (map instanceof ConcurrentMap || map instanceof LinkedHashMap) {
int index = 0;
for (Map.Entry<K, V> entry : map.entrySet()) {
action.call(entry.getKey(), entry.getValue(), index);
index++;
}
}
// 遍历其他类型映射的条目集合并传递索引
else {
int index = 0;
for (Map.Entry<K, V> entry : map.entrySet()) {
action.call(entry.getKey(), entry.getValue(), index);
index++;
}
}
}
/**
* 对给定的映射执行指定的操作仅处理键和值
* 根据映射类型选择不同的遍历策略
*
* @param map 要遍历的映射
* @param action 要对每个键值对执行的操作接收键和值作为参数
* @param <K> 映射中键的类型
* @param <V> 映射中值的类型
*/
public static <K, V> void forEach(
Map<K, V> map,
P2Function<? super K, ? super V> action
) {
// 参数校验如果映射或操作为空则直接返回
if (map == null || action == null) {
return;
}
// 遍历 TreeMap 的条目集合
if (map instanceof TreeMap) {
for (Map.Entry<K, V> entry : map.entrySet()) {
action.call(entry.getKey(), entry.getValue());
}
}
// 如果是 ConcurrentMap LinkedHashMap使用其内置的 forEach 方法
else if (map instanceof ConcurrentMap || map instanceof LinkedHashMap) {
forEach(map.entrySet(), i -> action.call(i.getKey(), i.getValue()));
}
// 遍历其他类型映射的条目集合
else {
for (Map.Entry<K, V> entry : map.entrySet()) {
action.call(entry.getKey(), entry.getValue());
}
}
}
/**
* 对可变参数数组执行指定的操作操作包含元素值和索引
*
* @param action 要对每个元素执行的操作接收元素值和索引作为参数
* @param objects 要遍历的可变参数数组
* @param <T> 数组中元素的类型
*/
public static <T> void forEach(
P2Function<? super T, Integer> action,
T... objects
) {
forEach(Lists.newArrayList(objects), action);
}
/**
* 对数组执行指定的操作操作包含元素值和索引
*
* @param objects 要遍历的数组
* @param action 要对每个元素执行的操作接收元素值和索引作为参数
* @param <T> 数组中元素的类型
*/
public static <T> void forEach(
T[] objects,
P2Function<? super T, Integer> action
) {
forEach(action, objects);
}
/**
* 对数组执行指定的操作仅处理元素值
*
* @param objects 要遍历的数组
* @param action 要对每个元素执行的操作只接收元素值作为参数
* @param <T> 数组中元素的类型
*/
public static <T> void forEach(T[] objects, P1Function<? super T> action) {
forEach(action, objects);
}
/**
* 对可变参数数组执行指定的操作仅处理元素值
*
* @param action 要对每个元素执行的操作只接收元素值作为参数
* @param objects 要遍历的可变参数数组
* @param <T> 数组中元素的类型
*/
public static <T> void forEach(P1Function<? super T> action, T... objects) {
forEach(Lists.toList(objects), (t, i) -> action.call(t));
}
/**
* 对整型数组执行指定的操作操作包含元素值和索引
*
* @param objects 要遍历的整型数组
* @param action 要对每个元素执行的操作接收元素值和索引作为参数
*/
public static void forEach(
int[] objects,
P2Function<Integer, Integer> action
) {
forEach(action, objects);
}
/**
* 对整型可变参数数组执行指定的操作操作包含元素值和索引
*
* @param action 要对每个元素执行的操作接收元素值和索引作为参数
* @param objects 要遍历的整型可变参数数组
*/
private static void forEach(
P2Function<Integer, Integer> action,
int... objects
) {
forEach(objects, action);
}
/**
* 对整型可变参数数组执行指定的操作仅处理元素值
*
* @param action 要对每个元素执行的操作只接收元素值作为参数
* @param objects 要遍历的整型可变参数数组
*/
private static void forEach(P1Function<Integer> action, int... objects) {
forEach(Lists.toList(objects), action);
}
/**
* 对字节数组执行指定的操作操作包含元素值和索引
*
* @param objects 要遍历的字节数组
* @param action 要对每个元素执行的操作接收元素值和索引作为参数
*/
public static void forEach(
byte[] objects,
P2Function<Byte, Integer> action
) {
forEach(Lists.toList(objects), action);
}
/**
* 对字节可变参数数组执行指定的操作操作包含元素值和索引
*
* @param action 要对每个元素执行的操作接收元素值和索引作为参数
* @param objects 要遍历的字节可变参数数组
*/
private static void forEach(
P2Function<Byte, Integer> action,
byte... objects
) {
forEach(objects, action);
}
/**
* 对字节可变参数数组执行指定的操作仅处理元素值
*
* @param action 要对每个元素执行的操作只接收元素值作为参数
* @param objects 要遍历的字节可变参数数组
*/
private static void forEach(P1Function<Byte> action, byte... objects) {
forEach(Lists.toList(objects), action);
}
/**
* 对短整型数组执行指定的操作操作包含元素值和索引
*
* @param objects 要遍历的短整型数组
* @param action 要对每个元素执行的操作接收元素值和索引作为参数
*/
public static void forEach(
short[] objects,
P2Function<Short, Integer> action
) {
forEach(Lists.toList(objects), action);
}
/**
* 对短整型可变参数数组执行指定的操作操作包含元素值和索引
*
* @param action 要对每个元素执行的操作接收元素值和索引作为参数
* @param objects 要遍历的短整型可变参数数组
*/
private static void forEach(
P2Function<Short, Integer> action,
short... objects
) {
forEach(objects, action);
}
/**
* 对短整型可变参数数组执行指定的操作仅处理元素值
*
* @param action 要对每个元素执行的操作只接收元素值作为参数
* @param objects 要遍历的短整型可变参数数组
*/
private static void forEach(P1Function<Short> action, short... objects) {
forEach(Lists.toList(objects), action);
}
/**
* 对长整型数组执行指定的操作操作包含元素值和索引
*
* @param objects 要遍历的长整型数组
* @param action 要对每个元素执行的操作接收元素值和索引作为参数
*/
public static void forEach(
long[] objects,
P2Function<Long, Integer> action
) {
forEach(action, objects);
}
/**
* 对长整型可变参数数组执行指定的操作操作包含元素值和索引
*
* @param action 要对每个元素执行的操作接收元素值和索引作为参数
* @param objects 要遍历的长整型可变参数数组
*/
private static void forEach(
P2Function<Long, Integer> action,
long... objects
) {
forEach(Lists.toList(objects), action);
}
/**
* 对长整型可变参数数组执行指定的操作仅处理元素值
*
* @param action 要对每个元素执行的操作只接收元素值作为参数
* @param objects 要遍历的长整型可变参数数组
*/
private static void forEach(P1Function<Long> action, long... objects) {
forEach(Lists.toList(objects), action);
}
/**
* 对浮点数组执行指定的操作操作包含元素值和索引
*
* @param objects 要遍历的浮点数组
* @param action 要对每个元素执行的操作接收元素值和索引作为参数
*/
public static void forEach(
float[] objects,
P2Function<Float, Integer> action
) {
forEach(action, objects);
}
/**
* 对浮点可变参数数组执行指定的操作操作包含元素值和索引
*
* @param action 要对每个元素执行的操作接收元素值和索引作为参数
* @param objects 要遍历的浮点可变参数数组
*/
private static void forEach(
P2Function<Float, Integer> action,
float... objects
) {
forEach(Lists.toList(objects), action);
}
/**
* 对浮点可变参数数组执行指定的操作仅处理元素值
*
* @param action 要对每个元素执行的操作只接收元素值作为参数
* @param objects 要遍历的浮点可变参数数组
*/
private static void forEach(P1Function<Float> action, float... objects) {
forEach(Lists.toList(objects), action);
}
/**
* 对双精度浮点数组执行指定的操作操作包含元素值和索引
*
* @param objects 要遍历的双精度浮点数组
* @param action 要对每个元素执行的操作接收元素值和索引作为参数
*/
public static void forEach(
double[] objects,
P2Function<Double, Integer> action
) {
forEach(action, objects);
}
/**
* 对双精度浮点可变参数数组执行指定的操作操作包含元素值和索引
*
* @param action 要对每个元素执行的操作接收元素值和索引作为参数
* @param objects 要遍历的双精度浮点可变参数数组
*/
private static void forEach(
P2Function<Double, Integer> action,
double... objects
) {
forEach(Lists.toList(objects), action);
}
/**
* 对双精度浮点可变参数数组执行指定的操作仅处理元素值
*
* @param action 要对每个元素执行的操作只接收元素值作为参数
* @param objects 要遍历的双精度浮点可变参数数组
*/
private static void forEach(P1Function<Double> action, double... objects) {
forEach(Lists.toList(objects), action);
}
/**
* 对字符数组执行指定的操作操作包含元素值和索引
*
* @param objects 要遍历的字符数组
* @param action 要对每个元素执行的操作接收元素值和索引作为参数
*/
public static void forEach(
char[] objects,
P2Function<Character, Integer> action
) {
forEach(action, objects);
}
/**
* 对字符可变参数数组执行指定的操作操作包含元素值和索引
*
* @param action 要对每个元素执行的操作接收元素值和索引作为参数
* @param objects 要遍历的字符可变参数数组
*/
private static void forEach(
P2Function<Character, Integer> action,
char... objects
) {
forEach(Lists.toList(objects), action);
}
/**
* 对字符可变参数数组执行指定的操作仅处理元素值
*
* @param action 要对每个元素执行的操作只接收元素值作为参数
* @param objects 要遍历的字符可变参数数组
*/
private static void forEach(P1Function<Character> action, char... objects) {
forEach(Lists.toList(objects), action);
}
/**
* 对布尔数组执行指定的操作操作包含元素值和索引
*
* @param objects 要遍历的布尔数组
* @param action 要对每个元素执行的操作接收元素值和索引作为参数
*/
public static void forEach(
boolean[] objects,
P2Function<Character, Integer> action
) {
forEach(objects, action);
}
/**
* 对布尔可变参数数组执行指定的操作操作包含元素值和索引
*
* @param action 要对每个元素执行的操作接收元素值和索引作为参数
* @param objects 要遍历的布尔可变参数数组
*/
private static void forEach(
P2Function<Boolean, Integer> action,
boolean... objects
) {
forEach(Lists.toList(objects), action);
}
/**
* 对布尔可变参数数组执行指定的操作仅处理元素值
*
* @param action 要对每个元素执行的操作只接收元素值作为参数
* @param objects 要遍历的布尔可变参数数组
*/
private static void forEach(
P1Function<Boolean> action,
boolean... objects
) {
forEach(Lists.toList(objects), action);
}
}

View File

@ -1,656 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile ForEachBreaked.java
* LastUpdate 2025-09-14 22:12:16
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.collection;
import com.mingliqiye.utils.functions.P1RFunction;
import com.mingliqiye.utils.functions.P2RFunction;
import com.mingliqiye.utils.functions.P3RFunction;
import java.util.*;
import java.util.Collection;
import java.util.concurrent.ConcurrentMap;
/**
* ForEachBreaked 工具类提供对集合和映射的增强遍历功能支持在遍历过程中中断操作
* 包含多个重载的 forEach 方法支持带索引的遍历操作并且可以在满足条件时提前终止遍历
* <br>
*
* <p>
* return null; // 提前下一次遍历 = continue;
* <p>
* return true; // 提前终止遍历 = break;
* <p>
* return false; // 继续下一次遍历
*
* @author MingLiPro
* @since 3.0.4
*/
public class ForEachBreaked {
/**
* 对给定的集合执行指定的操作操作包含元素值和索引
* 根据集合类型选择最优的遍历方式以提高性能
* 当操作返回 true 遍历将提前终止
*
* @param collection 要遍历的集合可以是 List 或其他 Collection 实现
* @param action 要对每个元素执行的操作接收元素值和索引作为参数返回 Boolean 值决定是否继续遍历
* @param <T> 集合中元素的类型
*/
public static <T> void forEach(
Collection<T> collection,
P2RFunction<? super T, Integer, Boolean> action
) {
// 参数校验如果集合或操作为空则直接返回
if (collection == null || action == null) {
return;
}
// 如果集合实现了 RandomAccess 接口 ArrayList使用索引访问优化性能
if (collection instanceof RandomAccess && collection instanceof List) {
List<T> list = (List<T>) collection;
for (int i = 0; i < list.size(); i++) {
if (action.call(list.get(i), i)) return;
}
}
// 如果是普通 List使用迭代器遍历并手动维护索引
else if (collection instanceof List) {
int index = 0;
Iterator<T> it = collection.iterator();
while (it.hasNext()) {
if (action.call(it.next(), index)) return;
index++;
}
}
// 其他类型的集合使用增强 for 循环并手动维护索引
else {
int index = 0;
for (T element : collection) {
if (action.call(element, index)) return;
index++;
}
}
}
/**
* 对给定的集合执行指定的操作仅处理元素值
* 根据集合是否实现 RandomAccess 接口选择最优的遍历方式
* 当操作返回 true 遍历将提前终止
*
* @param collection 要遍历的集合
* @param action 要对每个元素执行的操作只接收元素值作为参数返回 Boolean 值决定是否继续遍历
* @param <T> 集合中元素的类型
*/
public static <T> void forEach(
Collection<T> collection,
P1RFunction<? super T, Boolean> action
) {
// 参数校验如果集合或操作为空则直接返回
if (collection == null || action == null) {
return;
}
// 如果集合实现了 RandomAccess 接口使用索引访问提升性能
if (collection instanceof RandomAccess) {
List<T> list = (List<T>) collection;
for (int i = 0; i < list.size(); i++) {
if (action.call(list.get(i))) return;
}
}
// 否则使用增强 for 循环进行遍历
else {
for (T element : collection) {
if (action.call(element)) return;
}
}
}
/**
* 对给定的映射执行指定的操作操作包含键值和索引
* 根据映射类型选择不同的遍历策略
* 当操作返回 true 遍历将提前终止
*
* @param map 要遍历的映射
* @param action 要对每个键值对执行的操作接收键值和索引作为参数返回 Boolean 值决定是否继续遍历
* @param <K> 映射中键的类型
* @param <V> 映射中值的类型
*/
public static <K, V> void forEach(
Map<K, V> map,
P3RFunction<? super K, ? super V, Integer, Boolean> action
) {
// 参数校验如果映射或操作为空则直接返回
if (map == null || action == null) {
return;
}
// 遍历 TreeMap 的条目集合并传递索引
if (map instanceof TreeMap) {
int index = 0;
for (Map.Entry<K, V> entry : map.entrySet()) {
if (
action.call(entry.getKey(), entry.getValue(), index)
) return;
index++;
}
}
// 遍历 ConcurrentMap LinkedHashMap 的条目集合并传递索引
else if (map instanceof ConcurrentMap || map instanceof LinkedHashMap) {
int index = 0;
for (Map.Entry<K, V> entry : map.entrySet()) {
if (
action.call(entry.getKey(), entry.getValue(), index)
) return;
index++;
}
}
// 遍历其他类型映射的条目集合并传递索引
else {
int index = 0;
for (Map.Entry<K, V> entry : map.entrySet()) {
if (
action.call(entry.getKey(), entry.getValue(), index)
) return;
index++;
}
}
}
/**
* 对给定的映射执行指定的操作仅处理键和值
* 根据映射类型选择不同的遍历策略
* 当操作返回 true 遍历将提前终止
*
* @param map 要遍历的映射
* @param action 要对每个键值对执行的操作接收键和值作为参数返回 Boolean 值决定是否继续遍历
* @param <K> 映射中键的类型
* @param <V> 映射中值的类型
*/
public static <K, V> void forEach(
Map<K, V> map,
P2RFunction<? super K, ? super V, Boolean> action
) {
// 参数校验如果映射或操作为空则直接返回
if (map == null || action == null) {
return;
}
// 遍历 TreeMap 的条目集合
if (map instanceof TreeMap) {
for (Map.Entry<K, V> entry : map.entrySet()) {
if (action.call(entry.getKey(), entry.getValue())) return;
}
}
// 如果是 ConcurrentMap LinkedHashMap使用其内置的 forEach 方法
else if (map instanceof ConcurrentMap || map instanceof LinkedHashMap) {
forEach(map.entrySet(), i -> {
return action.call(i.getKey(), i.getValue());
});
}
// 遍历其他类型映射的条目集合
else {
for (Map.Entry<K, V> entry : map.entrySet()) {
if (action.call(entry.getKey(), entry.getValue())) return;
}
}
}
/**
* 对可变参数数组执行指定的操作操作包含元素值和索引
* 当操作返回 true 遍历将提前终止
*
* @param action 要对每个元素执行的操作接收元素值和索引作为参数返回 Boolean 值决定是否继续遍历
* @param objects 要遍历的可变参数数组
* @param <T> 数组中元素的类型
*/
public static <T> void forEach(
P2RFunction<? super T, Integer, Boolean> action,
T... objects
) {
forEach(Lists.newArrayList(objects), action);
}
/**
* 对数组执行指定的操作操作包含元素值和索引
* 当操作返回 true 遍历将提前终止
*
* @param objects 要遍历的数组
* @param action 要对每个元素执行的操作接收元素值和索引作为参数返回 Boolean 值决定是否继续遍历
* @param <T> 数组中元素的类型
*/
public static <T> void forEach(
T[] objects,
P2RFunction<? super T, Integer, Boolean> action
) {
forEach(action, objects);
}
/**
* 对迭代器执行指定的操作操作包含元素值和索引
* 当操作返回 true 遍历将提前终止
*
* @param iterator 要遍历的迭代器
* @param action 要对每个元素执行的操作接收元素值和索引作为参数返回 Boolean 值决定是否继续遍历
* @param <T> 数组中元素的类型
*/
public static <T> void forEach(
Iterator<T> iterator,
P2RFunction<? super T, Integer, Boolean> action
) {
if (iterator == null || action == null) {
return;
}
int index = 0;
while (iterator.hasNext()) {
if (action.call(iterator.next(), index)) return;
index++;
}
}
/**
* 对迭代器执行指定的操作操作包含元素值
* 当操作返回 true 遍历将提前终止
*
* @param iterator 要遍历的迭代器
* @param action 要对每个元素执行的操作接收元素值作为参数返回 Boolean 值决定是否继续遍历
* @param <T> 数组中元素的类型
*/
public static <T> void forEach(
Iterator<T> iterator,
P1RFunction<? super T, Boolean> action
) {
if (iterator == null || action == null) {
return;
}
while (iterator.hasNext()) {
if (action.call(iterator.next())) return;
}
}
/**
* 对数组执行指定的操作仅处理元素值
* 当操作返回 true 遍历将提前终止
*
* @param objects 要遍历的数组
* @param action 要对每个元素执行的操作只接收元素值作为参数返回 Boolean 值决定是否继续遍历
* @param <T> 数组中元素的类型
*/
public static <T> void forEach(
T[] objects,
P1RFunction<? super T, Boolean> action
) {
forEach(action, objects);
}
/**
* 对可变参数数组执行指定的操作仅处理元素值
* 当操作返回 true 遍历将提前终止
*
* @param action 要对每个元素执行的操作只接收元素值作为参数返回 Boolean 值决定是否继续遍历
* @param objects 要遍历的可变参数数组
* @param <T> 数组中元素的类型
*/
public static <T> void forEach(
P1RFunction<? super T, Boolean> action,
T... objects
) {
forEach(Lists.toList(objects), (t, i) -> {
return action.call(t);
});
}
/**
* 对整型数组执行指定的操作操作包含元素值和索引
* 当操作返回 true 遍历将提前终止
*
* @param objects 要遍历的整型数组
* @param action 要对每个元素执行的操作接收元素值和索引作为参数返回 Boolean 值决定是否继续遍历
*/
public static void forEach(
int[] objects,
P2RFunction<Integer, Integer, Boolean> action
) {
forEach(action, objects);
}
/**
* 对整型可变参数数组执行指定的操作操作包含元素值和索引
* 当操作返回 true 遍历将提前终止
*
* @param action 要对每个元素执行的操作接收元素值和索引作为参数返回 Boolean 值决定是否继续遍历
* @param objects 要遍历的整型可变参数数组
*/
private static void forEach(
P2RFunction<Integer, Integer, Boolean> action,
int... objects
) {
forEach(objects, action);
}
/**
* 对整型可变参数数组执行指定的操作仅处理元素值
* 当操作返回 true 遍历将提前终止
*
* @param action 要对每个元素执行的操作只接收元素值作为参数返回 Boolean 值决定是否继续遍历
* @param objects 要遍历的整型可变参数数组
*/
private static void forEach(
P1RFunction<Integer, Boolean> action,
int... objects
) {
forEach(Lists.toList(objects), action);
}
/**
* 对字节数组执行指定的操作操作包含元素值和索引
* 当操作返回 true 遍历将提前终止
*
* @param objects 要遍历的字节数组
* @param action 要对每个元素执行的操作接收元素值和索引作为参数返回 Boolean 值决定是否继续遍历
*/
public static void forEach(
byte[] objects,
P2RFunction<Byte, Integer, Boolean> action
) {
forEach(Lists.toList(objects), action);
}
/**
* 对字节可变参数数组执行指定的操作操作包含元素值和索引
* 当操作返回 true 遍历将提前终止
*
* @param action 要对每个元素执行的操作接收元素值和索引作为参数返回 Boolean 值决定是否继续遍历
* @param objects 要遍历的字节可变参数数组
*/
private static void forEach(
P2RFunction<Byte, Integer, Boolean> action,
byte... objects
) {
forEach(objects, action);
}
/**
* 对字节可变参数数组执行指定的操作仅处理元素值
* 当操作返回 true 遍历将提前终止
*
* @param action 要对每个元素执行的操作只接收元素值作为参数返回 Boolean 值决定是否继续遍历
* @param objects 要遍历的字节可变参数数组
*/
private static void forEach(
P1RFunction<Byte, Boolean> action,
byte... objects
) {
forEach(Lists.toList(objects), action);
}
/**
* 对短整型数组执行指定的操作操作包含元素值和索引
* 当操作返回 true 遍历将提前终止
*
* @param objects 要遍历的短整型数组
* @param action 要对每个元素执行的操作接收元素值和索引作为参数返回 Boolean 值决定是否继续遍历
*/
public static void forEach(
short[] objects,
P2RFunction<Short, Integer, Boolean> action
) {
forEach(Lists.toList(objects), action);
}
/**
* 对短整型可变参数数组执行指定的操作操作包含元素值和索引
* 当操作返回 true 遍历将提前终止
*
* @param action 要对每个元素执行的操作接收元素值和索引作为参数返回 Boolean 值决定是否继续遍历
* @param objects 要遍历的短整型可变参数数组
*/
private static void forEach(
P2RFunction<Short, Integer, Boolean> action,
short... objects
) {
forEach(objects, action);
}
/**
* 对短整型可变参数数组执行指定的操作仅处理元素值
* 当操作返回 true 遍历将提前终止
*
* @param action 要对每个元素执行的操作只接收元素值作为参数返回 Boolean 值决定是否继续遍历
* @param objects 要遍历的短整型可变参数数组
*/
private static void forEach(
P1RFunction<Short, Boolean> action,
short... objects
) {
forEach(Lists.toList(objects), action);
}
/**
* 对长整型数组执行指定的操作操作包含元素值和索引
* 当操作返回 true 遍历将提前终止
*
* @param objects 要遍历的长整型数组
* @param action 要对每个元素执行的操作接收元素值和索引作为参数返回 Boolean 值决定是否继续遍历
*/
public static void forEach(
long[] objects,
P2RFunction<Long, Integer, Boolean> action
) {
forEach(action, objects);
}
/**
* 对长整型可变参数数组执行指定的操作操作包含元素值和索引
* 当操作返回 true 遍历将提前终止
*
* @param action 要对每个元素执行的操作接收元素值和索引作为参数返回 Boolean 值决定是否继续遍历
* @param objects 要遍历的长整型可变参数数组
*/
private static void forEach(
P2RFunction<Long, Integer, Boolean> action,
long... objects
) {
forEach(Lists.toList(objects), action);
}
/**
* 对长整型可变参数数组执行指定的操作仅处理元素值
* 当操作返回 true 遍历将提前终止
*
* @param action 要对每个元素执行的操作只接收元素值作为参数返回 Boolean 值决定是否继续遍历
* @param objects 要遍历的长整型可变参数数组
*/
private static void forEach(
P1RFunction<Long, Boolean> action,
long... objects
) {
forEach(Lists.toList(objects), action);
}
/**
* 对浮点数组执行指定的操作操作包含元素值和索引
* 当操作返回 true 遍历将提前终止
*
* @param objects 要遍历的浮点数组
* @param action 要对每个元素执行的操作接收元素值和索引作为参数返回 Boolean 值决定是否继续遍历
*/
public static void forEach(
float[] objects,
P2RFunction<Float, Integer, Boolean> action
) {
forEach(action, objects);
}
/**
* 对浮点可变参数数组执行指定的操作操作包含元素值和索引
* 当操作返回 true 遍历将提前终止
*
* @param action 要对每个元素执行的操作接收元素值和索引作为参数返回 Boolean 值决定是否继续遍历
* @param objects 要遍历的浮点可变参数数组
*/
private static void forEach(
P2RFunction<Float, Integer, Boolean> action,
float... objects
) {
forEach(Lists.toList(objects), action);
}
/**
* 对浮点可变参数数组执行指定的操作仅处理元素值
* 当操作返回 true 遍历将提前终止
*
* @param action 要对每个元素执行的操作只接收元素值作为参数返回 Boolean 值决定是否继续遍历
* @param objects 要遍历的浮点可变参数数组
*/
private static void forEach(
P1RFunction<Float, Boolean> action,
float... objects
) {
forEach(Lists.toList(objects), action);
}
/**
* 对双精度浮点数组执行指定的操作操作包含元素值和索引
* 当操作返回 true 遍历将提前终止
*
* @param objects 要遍历的双精度浮点数组
* @param action 要对每个元素执行的操作接收元素值和索引作为参数返回 Boolean 值决定是否继续遍历
*/
public static void forEach(
double[] objects,
P2RFunction<Double, Integer, Boolean> action
) {
forEach(action, objects);
}
/**
* 对双精度浮点可变参数数组执行指定的操作操作包含元素值和索引
* 当操作返回 true 遍历将提前终止
*
* @param action 要对每个元素执行的操作接收元素值和索引作为参数返回 Boolean 值决定是否继续遍历
* @param objects 要遍历的双精度浮点可变参数数组
*/
private static void forEach(
P2RFunction<Double, Integer, Boolean> action,
double... objects
) {
forEach(Lists.toList(objects), action);
}
/**
* 对双精度浮点可变参数数组执行指定的操作仅处理元素值
* 当操作返回 true 遍历将提前终止
*
* @param action 要对每个元素执行的操作只接收元素值作为参数返回 Boolean 值决定是否继续遍历
* @param objects 要遍历的双精度浮点可变参数数组
*/
private static void forEach(
P1RFunction<Double, Boolean> action,
double... objects
) {
forEach(Lists.toList(objects), action);
}
/**
* 对字符数组执行指定的操作操作包含元素值和索引
* 当操作返回 true 遍历将提前终止
*
* @param objects 要遍历的字符数组
* @param action 要对每个元素执行的操作接收元素值和索引作为参数返回 Boolean 值决定是否继续遍历
*/
public static void forEach(
char[] objects,
P2RFunction<Character, Integer, Boolean> action
) {
forEach(action, objects);
}
/**
* 对字符可变参数数组执行指定的操作操作包含元素值和索引
* 当操作返回 true 遍历将提前终止
*
* @param action 要对每个元素执行的操作接收元素值和索引作为参数返回 Boolean 值决定是否继续遍历
* @param objects 要遍历的字符可变参数数组
*/
private static void forEach(
P2RFunction<Character, Integer, Boolean> action,
char... objects
) {
forEach(Lists.toList(objects), action);
}
/**
* 对字符可变参数数组执行指定的操作仅处理元素值
* 当操作返回 true 遍历将提前终止
*
* @param action 要对每个元素执行的操作只接收元素值作为参数返回 Boolean 值决定是否继续遍历
* @param objects 要遍历的字符可变参数数组
*/
private static void forEach(
P1RFunction<Character, Boolean> action,
char... objects
) {
forEach(Lists.toList(objects), action);
}
/**
* 对布尔数组执行指定的操作操作包含元素值和索引
* 当操作返回 true 遍历将提前终止
*
* @param objects 要遍历的布尔数组
* @param action 要对每个元素执行的操作接收元素值和索引作为参数返回 Boolean 值决定是否继续遍历
*/
public static void forEach(
boolean[] objects,
P2RFunction<Character, Integer, Boolean> action
) {
forEach(objects, action);
}
/**
* 对布尔可变参数数组执行指定的操作操作包含元素值和索引
* 当操作返回 true 遍历将提前终止
*
* @param action 要对每个元素执行的操作接收元素值和索引作为参数返回 Boolean 值决定是否继续遍历
* @param objects 要遍历的布尔可变参数数组
*/
private static void forEach(
P2RFunction<Boolean, Integer, Boolean> action,
boolean... objects
) {
forEach(Lists.toList(objects), action);
}
/**
* 对布尔可变参数数组执行指定的操作仅处理元素值
* 当操作返回 true 遍历将提前终止
*
* @param action 要对每个元素执行的操作只接收元素值作为参数返回 Boolean 值决定是否继续遍历
* @param objects 要遍历的布尔可变参数数组
*/
private static void forEach(
P1RFunction<Boolean, Boolean> action,
boolean... objects
) {
forEach(Lists.toList(objects), action);
}
}

View File

@ -1,479 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile Lists.java
* LastUpdate 2025-09-14 22:12:16
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.collection;
import com.mingliqiye.utils.random.RandomInt;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.Collection;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Lists工具类提供了一系列创建List实现的便捷方法
*
* @author MingLiPro
*/
public class Lists {
/**
* 创建一个空的ArrayList实例
*
* @param <T> 列表元素的类型
* @return 新创建的空ArrayList实例
*/
public static <T> List<T> newArrayList() {
return new ArrayList<>();
}
/**
* 根据可变参数创建一个包含指定元素的ArrayList实例
*
* @param ts 要添加到列表中的元素可以为0个或多个
* @param <T> 列表元素的类型
* @return 包含指定元素的新ArrayList实例
*/
public static <T> List<T> newArrayList(T... ts) {
List<T> list = newArrayList();
list.addAll(Arrays.asList(ts));
return list;
}
/**
* 根据已有列表创建一个新的ArrayList实例
*
* @param list 要复制的列表
* @param <T> 列表元素的类型
* @return 包含原列表所有元素的新ArrayList实例
*/
public static <T> List<T> newArrayList(List<T> list) {
List<T> newList = newArrayList();
newList.addAll(list);
return newList;
}
/**
* 根据可迭代对象创建一个ArrayList实例
*
* @param iterable 可迭代对象
* @param <T> 列表元素的类型
* @return 包含可迭代对象中所有元素的新ArrayList实例
*/
public static <T> List<T> newArrayList(Iterable<T> iterable) {
List<T> list = newArrayList();
for (T t : iterable) {
list.add(t);
}
return list;
}
/**
* 创建一个指定初始容量的空ArrayList实例
*
* @param size 初始容量大小
* @param <T> 列表元素的类型
* @return 指定初始容量的空ArrayList实例
*/
public static <T> List<T> newArrayList(int size) {
return new ArrayList<>(size);
}
/**
* 创建一个指定大小并用单个元素填充的ArrayList实例
*
* @param size 列表大小
* @param t 用于填充列表的元素
* @param <T> 列表元素的类型
* @return 指定大小且所有元素都相同的ArrayList实例
*/
public static <T> List<T> newArrayList(int size, T t) {
List<T> list = newArrayList(size);
for (int i = 0; i < size; i++) {
list.add(t);
}
return list;
}
/**
* 创建一个指定大小并交替使用两个元素填充的ArrayList实例
*
* @param size 列表大小
* @param t 第一个填充元素索引为偶数时使用
* @param t1 第二个填充元素索引为奇数时使用
* @param <T> 列表元素的类型
* @return 指定大小且交替填充两个元素的ArrayList实例
*/
public static <T> List<T> newArrayList(int size, T t, T t1) {
List<T> list = newArrayList(size);
for (int i = 0; i < size; i++) {
list.add(i % 2 == 0 ? t : t1);
}
return list;
}
/**
* 创建一个指定大小并循环使用三个元素填充的ArrayList实例
*
* @param size 列表大小
* @param t 第一个填充元素索引模3等于0时使用
* @param t1 第二个填充元素索引模3等于1时使用
* @param t2 第三个填充元素索引模3等于2时使用
* @param <T> 列表元素的类型
* @return 指定大小且循环填充三个元素的ArrayList实例
*/
public static <T> List<T> newArrayList(int size, T t, T t1, T t2) {
List<T> list = newArrayList(size);
for (int i = 0; i < size; i++) {
list.add(i % 3 == 0 ? t : i % 3 == 1 ? t1 : t2);
}
return list;
}
/**
* 创建一个指定大小并循环使用四个元素填充的ArrayList实例
*
* @param size 列表大小
* @param t 第一个填充元素索引模4等于0时使用
* @param t1 第二个填充元素索引模4等于1时使用
* @param t2 第三个填充元素索引模4等于2时使用
* @param t3 第四个填充元素索引模4等于3时使用
* @param <T> 列表元素的类型
* @return 指定大小且循环填充四个元素的ArrayList实例
*/
public static <T> List<T> newArrayList(int size, T t, T t1, T t2, T t3) {
List<T> list = newArrayList(size);
for (int i = 0; i < size; i++) {
list.add(i % 4 == 0 ? t : i % 4 == 1 ? t1 : i % 4 == 2 ? t2 : t3);
}
return list;
}
/**
* 创建一个空的LinkedList实例
*
* @param <T> 列表元素的类型
* @return 新创建的空LinkedList实例
*/
public static <T> List<T> newLinkedList() {
return new LinkedList<>();
}
/**
* 根据可变参数创建一个包含指定元素的LinkedList实例
*
* @param ts 要添加到列表中的元素可以为0个或多个
* @param <T> 列表元素的类型
* @return 包含指定元素的新LinkedList实例
*/
public static <T> List<T> newLinkedList(T... ts) {
List<T> list = newLinkedList();
list.addAll(Arrays.asList(ts));
return list;
}
/**
* 根据已有列表创建一个新的LinkedList实例
*
* @param list 要复制的列表
* @param <T> 列表元素的类型
* @return 包含原列表所有元素的新LinkedList实例
*/
public static <T> List<T> newLinkedList(List<T> list) {
List<T> newList = newLinkedList();
newList.addAll(list);
return newList;
}
/**
* 创建一个空的Vector实例
*
* @param <T> 列表元素的类型
* @return 新创建的空Vector实例
*/
public static <T> List<T> newVector() {
return new Vector<>();
}
/**
* 根据可变参数创建一个包含指定元素的Vector实例
*
* @param ts 要添加到列表中的元素可以为0个或多个
* @param <T> 列表元素的类型
* @return 包含指定元素的新Vector实例
*/
public static <T> List<T> newVector(T... ts) {
List<T> list = newVector();
list.addAll(Arrays.asList(ts));
return list;
}
/**
* 根据已有列表创建一个新的Vector实例
*
* @param list 要复制的列表
* @param <T> 列表元素的类型
* @return 包含原列表所有元素的新Vector实例
*/
public static <T> List<T> newVector(List<T> list) {
List<T> newList = newVector();
newList.addAll(list);
return newList;
}
/**
* 将指定列表中的每个元素转换为字符串表示形式
*
* @param <T> 列表元素的类型
* @param list 要转换的列表不能为空
* @return 包含原列表各元素字符串表示的新列表保持相同的顺序
*/
public static <T> List<String> toStringList(@NotNull List<T> list) {
// 创建与原列表相同大小的新列表用于存储字符串转换结果
List<String> newList = newArrayList(list.size());
for (T t : list) {
newList.add(t == null ? "null" : t.toString());
}
return newList;
}
/**
* 将指定数组中的每个元素转换为字符串表示形式
*
* @param <T> 数组元素的类型
* @param list 要转换的数组不能为空
* @return 包含原数组各元素字符串表示的新字符串数组
*/
public static <T> String[] toStringList(@NotNull T[] list) {
// 创建新的字符串列表用于存储转换后的结果
List<String> newList = newArrayList(list.length);
for (T t : list) {
newList.add(t == null ? "null" : t.toString());
}
return newList.toArray(new String[0]);
}
/**
* 将列表转换为数组
*
* @param ts 要转换的列表
* @param <T> 数组元素的类型
* @return 包含列表中所有元素的数组如果列表为null则返回null
*/
@Nullable
public static <T> T[] toArray(List<T> ts) {
if (ts == null) {
return null;
}
T[] items = (T[]) new Object[ts.size()];
ForEach.forEach(ts, (t, i) -> items[i] = t);
return items;
}
/**
* 将数组转换为列表
*
* @param ts 要转换的数组
* @param <T> 列表元素的类型
* @return 包含数组中所有元素的列表如果数组为null则返回null
*/
// 原始的方法 - 用于引用类型
@Nullable
public static <T> List<T> toList(T[] ts) {
return ts == null ? null : new ArrayList<>(Arrays.asList(ts));
}
@NotNull
public static <T> List<T> toList(Stream<T> ts) {
return ts == null
? newArrayList()
: new ArrayList<>(ts.collect(Collectors.toList()));
}
/**
* 将int数组转换为Integer列表
*
* @param array 要转换的int数组
* @return 包含数组中所有元素的Integer列表如果数组为null则返回null
*/
@Nullable
public static List<Integer> toList(int[] array) {
if (array == null) {
return null;
}
List<Integer> list = new ArrayList<>(array.length);
for (int value : array) {
list.add(value);
}
return list;
}
/**
* 将long数组转换为Long列表
*
* @param array 要转换的long数组
* @return 包含数组中所有元素的Long列表如果数组为null则返回null
*/
@Nullable
public static List<Long> toList(long[] array) {
if (array == null) {
return null;
}
List<Long> list = new ArrayList<>(array.length);
for (long value : array) {
list.add(value);
}
return list;
}
/**
* 将double数组转换为Double列表
*
* @param array 要转换的double数组
* @return 包含数组中所有元素的Double列表如果数组为null则返回null
*/
@Nullable
public static List<Double> toList(double[] array) {
if (array == null) {
return null;
}
List<Double> list = new ArrayList<>(array.length);
for (double value : array) {
list.add(value);
}
return list;
}
/**
* 将float数组转换为Float列表
*
* @param array 要转换的float数组
* @return 包含数组中所有元素的Float列表如果数组为null则返回null
*/
@Nullable
public static List<Float> toList(float[] array) {
if (array == null) {
return null;
}
List<Float> list = new ArrayList<>(array.length);
for (float value : array) {
list.add(value);
}
return list;
}
/**
* 将boolean数组转换为Boolean列表
*
* @param array 要转换的boolean数组
* @return 包含数组中所有元素的Boolean列表如果数组为null则返回null
*/
@Nullable
public static List<Boolean> toList(boolean[] array) {
if (array == null) {
return null;
}
List<Boolean> list = new ArrayList<>(array.length);
for (boolean value : array) {
list.add(value);
}
return list;
}
/**
* 将char数组转换为Character列表
*
* @param array 要转换的char数组
* @return 包含数组中所有元素的Character列表如果数组为null则返回null
*/
@Nullable
public static List<Character> toList(char[] array) {
if (array == null) {
return null;
}
List<Character> list = new ArrayList<>(array.length);
for (char value : array) {
list.add(value);
}
return list;
}
/**
* 将byte数组转换为Byte列表
*
* @param array 要转换的byte数组
* @return 包含数组中所有元素的Byte列表如果数组为null则返回null
*/
@Nullable
public static List<Byte> toList(byte[] array) {
if (array == null) {
return null;
}
List<Byte> list = new ArrayList<>(array.length);
for (byte value : array) {
list.add(value);
}
return list;
}
/**
* 将short数组转换为Short列表
*
* @param array 要转换的short数组
* @return 包含数组中所有元素的Short列表如果数组为null则返回null
*/
@Nullable
public static List<Short> toList(short[] array) {
if (array == null) {
return null;
}
List<Short> list = new ArrayList<>(array.length);
for (short value : array) {
list.add(value);
}
return list;
}
public static <T> List<T> toList(Iterator<T> iterator) {
List<T> list = newArrayList(10);
ForEach.forEach(iterator, item -> list.add(item));
return list;
}
public <T> T getFirst(Collection<T> collectors) {
return com.mingliqiye.utils.collection.Collection.getFirst(collectors);
}
public <T> T getLast(Collection<T> collectors) {
return com.mingliqiye.utils.collection.Collection.getFirst(collectors);
}
public <T> T getAny(Collection<T> collectors) {
return com.mingliqiye.utils.collection.Collection.getOrDefault(
collectors,
RandomInt.randomInt(0, collectors.size()),
null
);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,167 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile Sets.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.collection;
import java.util.*;
/**
* Sets工具类提供了一系列创建Set实现的便捷方法
*
* @author MingLiPro
*/
public class Sets {
/**
* 创建一个空的HashSet实例
*
* @param <T> 集合元素的类型
* @return 新创建的空HashSet实例
*/
public static <T> Set<T> newHashSet() {
return new HashSet<>();
}
/**
* 根据可变参数创建一个包含指定元素的HashSet实例
*
* @param ts 要添加到集合中的元素可以为0个或多个
* @param <T> 集合元素的类型
* @return 包含指定元素的新HashSet实例
*/
public static <T> Set<T> newHashSet(T... ts) {
Set<T> set = newHashSet();
set.addAll(Arrays.asList(ts));
return set;
}
/**
* 根据已有集合创建一个新的HashSet实例
*
* @param set 要复制的集合
* @param <T> 集合元素的类型
* @return 包含原集合所有元素的新HashSet实例
*/
public static <T> Set<T> newHashSet(Set<T> set) {
Set<T> newSet = newHashSet();
newSet.addAll(set);
return newSet;
}
/**
* 根据可迭代对象创建一个HashSet实例
*
* @param iterable 可迭代对象
* @param <T> 集合元素的类型
* @return 包含可迭代对象中所有元素的新HashSet实例
*/
public static <T> Set<T> newHashSet(Iterable<T> iterable) {
Set<T> set = newHashSet();
for (T t : iterable) {
set.add(t);
}
return set;
}
/**
* 创建一个指定初始容量的空HashSet实例
*
* @param size 初始容量大小
* @param <T> 集合元素的类型
* @return 指定初始容量的空HashSet实例
*/
public static <T> Set<T> newHashSet(int size) {
return new HashSet<>(size);
}
/**
* 创建一个空的LinkedHashSet实例
*
* @param <T> 集合元素的类型
* @return 新创建的空LinkedHashSet实例
*/
public static <T> Set<T> newLinkedHashSet() {
return new LinkedHashSet<>();
}
/**
* 根据可变参数创建一个包含指定元素的LinkedHashSet实例
*
* @param ts 要添加到集合中的元素可以为0个或多个
* @param <T> 集合元素的类型
* @return 包含指定元素的新LinkedHashSet实例
*/
public static <T> Set<T> newLinkedHashSet(T... ts) {
Set<T> set = newLinkedHashSet();
set.addAll(Arrays.asList(ts));
return set;
}
/**
* 根据已有集合创建一个新的LinkedHashSet实例
*
* @param set 要复制的集合
* @param <T> 集合元素的类型
* @return 包含原集合所有元素的新LinkedHashSet实例
*/
public static <T> Set<T> newLinkedHashSet(Set<T> set) {
Set<T> newSet = newLinkedHashSet();
newSet.addAll(set);
return newSet;
}
/**
* 创建一个空的TreeSet实例
*
* @param <T> 集合元素的类型必须实现Comparable接口
* @return 新创建的空TreeSet实例
*/
public static <T extends Comparable<T>> Set<T> newTreeSet() {
return new TreeSet<>();
}
/**
* 根据可变参数创建一个包含指定元素的TreeSet实例
*
* @param ts 要添加到集合中的元素可以为0个或多个
* @param <T> 集合元素的类型必须实现Comparable接口
* @return 包含指定元素的新TreeSet实例
*/
public static <T extends Comparable<T>> Set<T> newTreeSet(T... ts) {
Set<T> set = newTreeSet();
set.addAll(Arrays.asList(ts));
return set;
}
/**
* 根据已有集合创建一个新的TreeSet实例
*
* @param set 要复制的集合
* @param <T> 集合元素的类型必须实现Comparable接口
* @return 包含原集合所有元素的新TreeSet实例
*/
public static <T extends Comparable<T>> Set<T> newTreeSet(Set<T> set) {
Set<T> newSet = newTreeSet();
newSet.addAll(set);
return newSet;
}
}

View File

@ -1,106 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile IsChanged.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.concurrent;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
/**
* IsChanged 类提供了一个线程安全的包装器用于检测值是否发生变化
* 它基于 AtomicReference 实现适用于需要监控数据变更的并发场景
*
* @param <T> 泛型类型表示被包装的数据类型
* @author MingLiPro
*/
public class IsChanged<T> {
/**
* 使用 AtomicReference 来保证对数据的原子操作
*/
private final AtomicReference<T> atomicReferenceData;
/**
* 默认构造函数初始化数据为 null
*/
public IsChanged() {
this(null);
}
/**
* 带参数的构造函数使用指定的初始值初始化
*
* @param data 初始数据值
*/
public IsChanged(T data) {
atomicReferenceData = new AtomicReference<>(data);
}
/**
* 设置新的数据值不检查是否发生变化
*
* @param data 要设置的新数据值
*/
public void set(T data) {
atomicReferenceData.set(data);
}
/**
* 获取当前数据值
*
* @return 当前数据值
*/
public T get() {
return atomicReferenceData.get();
}
/**
* 设置新的数据值并返回旧的数据值
*
* @param data 要设置的新数据值
* @return 设置前的旧数据值
*/
public T setAndGet(T data) {
return atomicReferenceData.getAndSet(data);
}
/**
* 设置新的数据值如果新值与当前值不同则更新并返回 true否则返回 false
* 使用 CAS(Compare-And-Swap) 操作确保线程安全
*
* @param data 要设置的新数据值
* @return 如果值发生变化返回 true否则返回 false
*/
public boolean setAndChanged(T data) {
T currentData;
do {
currentData = get();
// 如果新值与当前值相等则认为没有变化直接返回 false
if (Objects.equals(data, currentData)) {
return false;
}
// 使用 CAS 操作尝试更新值如果失败则重试
} while (!atomicReferenceData.compareAndSet(currentData, data));
// 成功更新值返回 true 表示发生了变化
return true;
}
}

View File

@ -1,105 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile ThreadLocalDataHolder.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.data;
/**
* 泛型线程局部变量持有器
* <p>
* 封装了 ThreadLocal 的常用操作提供更便捷的 API 来管理线程本地变量
*
* @param <T> 存储的数据类型
* @author MingLiPro
*/
public class ThreadLocalDataHolder<T> {
private final ThreadLocal<T> threadLocal;
/**
* 构造函数初始化 ThreadLocal 实例
*/
public ThreadLocalDataHolder() {
this.threadLocal = new ThreadLocal<>();
}
/**
* 获取当前线程存储的值
*
* @return 当前线程存储的值如果没有则返回null
*/
public T get() {
return threadLocal.get();
}
/**
* 设置当前线程的值
*
* @param value 要存储的值
*/
public void set(T value) {
threadLocal.set(value);
}
/**
* 移除当前线程存储的值
* <p>
* 防止内存泄漏使用完毕后应调用此方法清理资源
*/
public void remove() {
threadLocal.remove();
}
/**
* 获取当前线程存储的值如果不存在则返回默认值
*
* @param defaultValue 默认值
* @return 当前线程存储的值或默认值
*/
public T getOrDefault(T defaultValue) {
T value = threadLocal.get();
return value != null ? value : defaultValue;
}
/**
* 安全获取值避免NPE
* <p>
* 在某些异常情况下防止抛出异常直接返回 null
*
* @return 值或null
*/
public T safeGet() {
try {
return threadLocal.get();
} catch (Exception e) {
return null;
}
}
/**
* 检查当前线程是否有值
*
* @return 是否有值
*/
public boolean isPresent() {
return threadLocal.get() != null;
}
}

View File

@ -1,368 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile FileUtil.java
* LastUpdate 2025-09-14 22:12:16
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.file;
import com.mingliqiye.utils.string.StringUtils;
import lombok.Getter;
import lombok.Setter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.List;
/**
* 文件工具类提供常用的文件操作方法
*
* @author MingLiPro
*/
public class FileUtil {
/**
* 默认字符集
*/
@Getter
@Setter
private static Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
/**
* 读取文件内容为字符串
*
* @param filePath 文件路径
* @return 文件内容字符串
* @throws IOException 读取文件时发生错误
*/
public static String readFileToString(String filePath) throws IOException {
return readFileToString(filePath, DEFAULT_CHARSET);
}
/**
* 读取文件内容为字符串
*
* @param filePath 文件路径
* @param charset 字符集
* @return 文件内容字符串
* @throws IOException 读取文件时发生错误
*/
public static String readFileToString(String filePath, Charset charset)
throws IOException {
Path path = Paths.get(filePath);
byte[] bytes = Files.readAllBytes(path);
return new String(bytes, charset);
}
/**
* 将字符串写入文件
*
* @param filePath 文件路径
* @param content 要写入的内容
* @throws IOException 写入文件时发生错误
*/
public static void writeStringToFile(String filePath, String content)
throws IOException {
writeStringToFile(filePath, content, DEFAULT_CHARSET);
}
/**
* 将字符串写入文件
*
* @param filePath 文件路径
* @param content 要写入的内容
* @param charset 字符集
* @throws IOException 写入文件时发生错误
*/
public static void writeStringToFile(
String filePath,
String content,
Charset charset
) throws IOException {
Path path = Paths.get(filePath);
if (path.getParent() != null) {
Files.createDirectories(path.getParent());
}
Files.write(path, content.getBytes(charset));
}
/**
* 读取文件内容为字符串列表按行分割
*
* @param filePath 文件路径
* @return 文件内容按行分割的字符串列表
* @throws IOException 读取文件时发生错误
*/
public static List<String> readLines(String filePath) throws IOException {
return readLines(filePath, DEFAULT_CHARSET);
}
/**
* 读取文件内容为字符串列表按行分割
*
* @param filePath 文件路径
* @param charset 字符集
* @return 文件内容按行分割的字符串列表
* @throws IOException 读取文件时发生错误
*/
public static List<String> readLines(String filePath, Charset charset)
throws IOException {
Path path = Paths.get(filePath);
return Files.readAllLines(path, charset);
}
/**
* 将字符串列表写入文件每行一个元素
*
* @param filePath 文件路径
* @param lines 要写入的行内容列表
* @throws IOException 写入文件时发生错误
*/
public static void writeLines(String filePath, List<String> lines)
throws IOException {
writeLines(filePath, lines, DEFAULT_CHARSET);
}
/**
* 将字符串列表写入文件每行一个元素
*
* @param filePath 文件路径
* @param lines 要写入的行内容列表
* @param charset 字符集
* @throws IOException 写入文件时发生错误
*/
public static void writeLines(
String filePath,
List<String> lines,
Charset charset
) throws IOException {
Path path = Paths.get(filePath);
Files.createDirectories(path.getParent());
Files.write(path, lines, charset);
}
/**
* 复制文件
*
* @param sourcePath 源文件路径
* @param targetPath 目标文件路径
* @throws IOException 复制文件时发生错误
*/
public static void copyFile(String sourcePath, String targetPath)
throws IOException {
Path source = Paths.get(sourcePath);
Path target = Paths.get(targetPath);
Files.createDirectories(target.getParent());
Files.copy(source, target);
}
/**
* 删除文件
*
* @param filePath 文件路径
* @return 如果文件删除成功返回true否则返回false
*/
public static boolean deleteFile(String filePath) {
try {
Path path = Paths.get(filePath);
return Files.deleteIfExists(path);
} catch (IOException e) {
return false;
}
}
/**
* 检查文件是否存在
*
* @param filePath 文件路径
* @return 如果文件存在返回true否则返回false
*/
public static boolean exists(String filePath) {
Path path = Paths.get(filePath);
return Files.exists(path);
}
/**
* 获取文件大小
*
* @param filePath 文件路径
* @return 文件大小字节如果文件不存在返回-1
*/
public static long getFileSize(String filePath) {
try {
Path path = Paths.get(filePath);
return Files.size(path);
} catch (IOException e) {
return -1;
}
}
/**
* 创建目录
*
* @param dirPath 目录路径
* @return 如果目录创建成功返回true否则返回false
*/
public static boolean createDirectory(String dirPath) {
try {
Path path = Paths.get(dirPath);
Files.createDirectories(path);
return true;
} catch (IOException e) {
return false;
}
}
/**
* 获取文件扩展名
*
* @param fileName 文件名
* @return 文件扩展名不包含点号如果无扩展名返回空字符串
*/
public static String getFileExtension(String fileName) {
if (StringUtils.isEmpty(fileName)) {
return "";
}
int lastDotIndex = fileName.lastIndexOf('.');
if (lastDotIndex == -1 || lastDotIndex == fileName.length() - 1) {
return "";
}
return fileName.substring(lastDotIndex + 1);
}
/**
* 获取不带扩展名的文件名
*
* @param fileName 文件名
* @return 不带扩展名的文件名
*/
public static String getFileNameWithoutExtension(String fileName) {
if (StringUtils.isEmpty(fileName)) {
return "";
}
int lastDotIndex = fileName.lastIndexOf('.');
if (lastDotIndex == -1) {
return fileName;
}
return fileName.substring(0, lastDotIndex);
}
/**
* 读取文件内容为字节数组
*
* @param filePath 文件路径
* @return 文件内容的字节数组
* @throws IOException 读取文件时发生错误
*/
public static byte[] readFileToByteArray(String filePath)
throws IOException {
Path path = Paths.get(filePath);
return Files.readAllBytes(path);
}
/**
* 将字节数组写入文件
*
* @param filePath 文件路径
* @param data 要写入的字节数据
* @throws IOException 写入文件时发生错误
*/
public static void writeByteArrayToFile(String filePath, byte[] data)
throws IOException {
Path path = Paths.get(filePath);
Files.createDirectories(path.getParent());
Files.write(path, data);
}
/**
* 将字节数组追加到文件末尾
*
* @param filePath 文件路径
* @param data 要追加的字节数据
* @throws IOException 追加数据时发生错误
*/
public static void appendByteArrayToFile(String filePath, byte[] data)
throws IOException {
Path path = Paths.get(filePath);
Files.createDirectories(path.getParent());
Files.write(
path,
data,
StandardOpenOption.CREATE,
StandardOpenOption.APPEND
);
}
/**
* 分块读取大文件为字节数组列表
*
* @param filePath 文件路径
* @param chunkSize 每块大小字节
* @return 文件内容按指定大小分割的字节数组列表
* @throws IOException 读取文件时发生错误
*/
public static List<byte[]> readFileToByteArrayChunks(
String filePath,
int chunkSize
) throws IOException {
List<byte[]> chunks = new ArrayList<>();
Path path = Paths.get(filePath);
try (InputStream inputStream = Files.newInputStream(path)) {
byte[] buffer = new byte[chunkSize];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
byte[] chunk = new byte[bytesRead];
System.arraycopy(buffer, 0, chunk, 0, bytesRead);
chunks.add(chunk);
}
}
return chunks;
}
/**
* 将字节数组列表写入文件
*
* @param filePath 文件路径
* @param chunks 字节数组列表
* @throws IOException 写入文件时发生错误
*/
public static void writeByteArrayChunksToFile(
String filePath,
List<byte[]> chunks
) throws IOException {
Path path = Paths.get(filePath);
Files.createDirectories(path.getParent());
try (OutputStream outputStream = Files.newOutputStream(path)) {
for (byte[] chunk : chunks) {
outputStream.write(chunk);
}
}
}
}

View File

@ -1,93 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile Debouncer.java
* LastUpdate 2025-09-09 08:37:34
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.functions;
import java.util.concurrent.*;
/**
* 防抖器类用于实现防抖功能防止在短时间内重复执行相同任务
*
* @author MingLiPro
*/
public class Debouncer {
private final ScheduledExecutorService scheduler =
Executors.newSingleThreadScheduledExecutor();
private final ConcurrentHashMap<Object, Future<?>> delayedMap =
new ConcurrentHashMap<>();
private final long delay;
/**
* 构造函数创建一个防抖器实例
*
* @param delay 延迟时间
* @param unit 时间单位
*/
public Debouncer(long delay, TimeUnit unit) {
this.delay = unit.toMillis(delay);
}
/**
* 执行防抖操作如果在指定延迟时间内再次调用相同key的任务则取消之前的任务并重新计时
*
* @param key 任务的唯一标识符用于区分不同任务
* @param task 要执行的任务
*/
public void debounce(final Object key, final Runnable task) {
// 提交新任务并获取之前可能存在的任务
final Future<?> prev = delayedMap.put(
key,
scheduler.schedule(
() -> {
try {
task.run();
} finally {
// 任务执行完成后从映射中移除
delayedMap.remove(key);
}
},
delay,
TimeUnit.MILLISECONDS
)
);
// 如果之前存在任务则取消它
if (prev != null) {
prev.cancel(true);
}
}
/**
* 关闭防抖器取消所有待执行的任务并关闭调度器
*/
public void shutdown() {
// 先取消所有延迟任务
for (Future<?> future : delayedMap.values()) {
future.cancel(true);
}
delayedMap.clear();
// 再关闭调度器
scheduler.shutdownNow();
}
}

View File

@ -1,39 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile P10Function.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.functions;
@FunctionalInterface
public interface P10Function<P, P1, P2, P3, P4, P5, P6, P7, P8, P9> {
void call(
P p,
P1 p1,
P2 p2,
P3 p3,
P4 p4,
P5 p5,
P6 p6,
P7 p7,
P8 p8,
P9 p9
);
}

View File

@ -1,28 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile P10RFunction.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.functions;
@FunctionalInterface
public interface P10RFunction<P, P1, P2, P3, P4, P5, P6, P7, P8, P9, R> {
R call(P p, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9);
}

View File

@ -1,28 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile P1Function.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.functions;
@FunctionalInterface
public interface P1Function<P> {
void call(P p);
}

View File

@ -1,28 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile P1RFunction.java
* LastUpdate 2025-09-09 08:37:34
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.functions;
@FunctionalInterface
public interface P1RFunction<P, R> {
R call(P p);
}

View File

@ -1,28 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile P2Function.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.functions;
@FunctionalInterface
public interface P2Function<P, P1> {
void call(P p, P1 p1);
}

View File

@ -1,28 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile P2RFunction.java
* LastUpdate 2025-09-09 08:37:34
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.functions;
@FunctionalInterface
public interface P2RFunction<P, P1, R> {
R call(P p, P1 p1);
}

View File

@ -1,28 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile P3Function.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.functions;
@FunctionalInterface
public interface P3Function<P, P1, P2> {
void call(P p, P1 p1, P2 p2);
}

View File

@ -1,28 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile P3RFunction.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.functions;
@FunctionalInterface
public interface P3RFunction<P, P1, P2, R> {
R call(P p, P1 p1, P2 p2);
}

View File

@ -1,28 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile P4Function.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.functions;
@FunctionalInterface
public interface P4Function<P, P1, P2, P3> {
void call(P p, P1 p1, P2 p2, P3 p3);
}

View File

@ -1,28 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile P4RFunction.java
* LastUpdate 2025-09-09 08:37:34
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.functions;
@FunctionalInterface
public interface P4RFunction<P, P1, P2, P3, R> {
R call(P p, P1 p1, P2 p2, P3 p3);
}

View File

@ -1,28 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile P5Function.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.functions;
@FunctionalInterface
public interface P5Function<P, P1, P2, P3, P4> {
void call(P p, P1 p1, P2 p2, P3 p3, P4 p4);
}

View File

@ -1,28 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile P5RFunction.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.functions;
@FunctionalInterface
public interface P5RFunction<P, P1, P2, P3, P4, R> {
R call(P p, P1 p1, P2 p2, P3 p3, P4 p4);
}

View File

@ -1,28 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile P6Function.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.functions;
@FunctionalInterface
public interface P6Function<P, P1, P2, P3, P4, P5> {
void call(P p, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5);
}

View File

@ -1,28 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile P6RFunction.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.functions;
@FunctionalInterface
public interface P6RFunction<P, P1, P2, P3, P4, P5, R> {
R call(P p, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5);
}

View File

@ -1,28 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile P7Function.java
* LastUpdate 2025-09-09 08:37:34
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.functions;
@FunctionalInterface
public interface P7Function<P, P1, P2, P3, P4, P5, P6> {
void call(P p, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6);
}

View File

@ -1,28 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile P7RFunction.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.functions;
@FunctionalInterface
public interface P7RFunction<P, P1, P2, P3, P4, P5, P6, R> {
R call(P p, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6);
}

View File

@ -1,28 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile P8Function.java
* LastUpdate 2025-09-09 08:37:34
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.functions;
@FunctionalInterface
public interface P8Function<P, P1, P2, P3, P4, P5, P6, P7> {
void call(P p, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7);
}

View File

@ -1,28 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile P9Function.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.functions;
@FunctionalInterface
public interface P9Function<P, P1, P2, P3, P4, P5, P6, P7, P8> {
void call(P p, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8);
}

View File

@ -1,28 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile P9RFunction.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.functions;
@FunctionalInterface
public interface P9RFunction<P, P1, P2, P3, P4, P5, P6, P7, P8, R> {
R call(P p, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8);
}

View File

@ -1,114 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile HashUtils.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.hash;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.mindrot.jbcrypt.BCrypt;
/**
* 提供常用的哈希计算工具方法包括文件哈希值计算BCrypt 加密等
*
* @author MingLiPro
*/
public class HashUtils {
static {
Security.addProvider(new BouncyCastleProvider());
}
/**
* 计算指定文件的哈希值
*
* @param file 要计算哈希值的文件对象
* @param algorithm 使用的哈希算法名称 SHA-256MD5
* @return 文件的十六进制格式哈希值字符串
* @throws IOException 当文件不存在或读取过程中发生 I/O 错误时抛出
* @throws NoSuchAlgorithmException 当指定的哈希算法不可用时抛出
*/
public static String calculateFileHash(File file, String algorithm)
throws IOException, NoSuchAlgorithmException {
// 检查文件是否存在
if (!file.exists()) {
throw new IOException("File not found: " + file.getAbsolutePath());
}
MessageDigest digest = MessageDigest.getInstance(algorithm);
try (FileInputStream fis = new FileInputStream(file)) {
byte[] buffer = new byte[8192];
int bytesRead;
// 分块读取文件内容并更新摘要
while ((bytesRead = fis.read(buffer)) != -1) {
digest.update(buffer, 0, bytesRead);
}
}
return bytesToHex(digest.digest());
}
/**
* 将字节数组转换为十六进制字符串表示
*
* @param bytes 输入的字节数组
* @return 对应的十六进制字符串
*/
private static String bytesToHex(byte[] bytes) {
StringBuilder hexString = new StringBuilder(2 * bytes.length);
for (byte b : bytes) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) {
hexString.append('0');
}
hexString.append(hex);
}
return hexString.toString();
}
/**
* 使用 BCrypt 算法对字符串进行加密
*
* @param string 需要加密的明文字符串
* @return 加密后的 BCrypt 哈希字符串
*/
public static String bcrypt(String string) {
return BCrypt.hashpw(string, BCrypt.gensalt());
}
/**
* 验证给定字符串与 BCrypt 哈希是否匹配
*
* @param string 明文字符串
* @param bcrypted 已经使用 BCrypt 加密的哈希字符串
* @return 如果匹配返回 true否则返回 false
*/
public static boolean checkBcrypt(String string, String bcrypted) {
return BCrypt.checkpw(string, bcrypted);
}
}

View File

@ -1,69 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile Response.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.http;
import com.mingliqiye.utils.time.DateTime;
import com.mingliqiye.utils.time.Formatter;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
@ToString
@EqualsAndHashCode
@Getter
public class Response<T> {
private final String time = DateTime.now().format(
Formatter.STANDARD_DATETIME_MILLISECOUND7
);
private String message;
private T data;
private int statusCode;
public Response(String message, T data, int statusCode) {
this.message = message;
this.data = data;
this.statusCode = statusCode;
}
public static <T> Response<T> ok(T data) {
return new Response<>("操作成功", data, 200);
}
public Response<T> setMessage(String message) {
this.message = message;
return this;
}
public Response<T> setData(T data) {
this.data = data;
return Response.ok(getData())
.setMessage(getMessage())
.setStatusCode(getStatusCode());
}
public Response<T> setStatusCode(int statusCode) {
this.statusCode = statusCode;
return this;
}
}

View File

@ -1,222 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile Range.java
* LastUpdate 2025-09-14 22:12:16
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.iterator;
import kotlin.ranges.ClosedRange;
import kotlin.ranges.OpenEndRange;
import lombok.Getter;
import lombok.val;
import org.jetbrains.annotations.NotNull;
import java.util.Iterator;
/**
* 范围 Range<br>
* Iterable 可遍历对象<br>
* 类似 KT的 {@code 0..10 = Range.of(0,10)} {@code 0..10 step 2 = Range.of(0,10,2)}
* @author MingLiPro
* @since 3.2.6
*/
@Getter
public class Range
implements Iterable<Integer>, ClosedRange<Integer>, OpenEndRange<Integer> {
private final int start;
private final int end;
private final int step;
private int current;
/**
* 创建一个范围 <br>
* 最大值{@code Integer.MAX_VALUE = 2147483647 } <br>
* 最小值{@code Integer.MIN_VALUE = -2147483648} <br>
* @param start 开始 (包含)
* @param end 完毕 (包含)
* @see Integer
*/
public Range(int start, int end) {
this(start, end, 1);
}
/**
* 创建一个范围 <br>
* 最大值{@code Integer.MAX_VALUE = 2147483647 } <br>
* 最小值{@code Integer.MIN_VALUE = -2147483648} <br>
* @param start 开始 (包含)
* @param end 完毕 (包含)
* @param step 步长
* @see Integer
*/
public Range(int start, int end, int step) {
this.start = start;
this.current = start;
this.step = step;
this.end = end + 1;
}
/**
* 创建一个范围 {@code 0 - range}<br>
* 最大值{@code Integer.MAX_VALUE = 2147483647 } <br>
* 最小值{@code Integer.MIN_VALUE = -2147483648} <br>
* @param range 完毕 (包含)
* @see Integer
*/
public Range(int range) {
this(0, range);
}
/**
* 创建一个范围 {@code 0 - range}<br>
* 最大值{@code Integer.MAX_VALUE = 2147483647 } <br>
* 最小值{@code Integer.MIN_VALUE = -2147483648} <br>
* @param range 完毕 (包含)
* @see Integer
* @return Range 对象
*/
public static Range of(int range) {
return new Range(range);
}
/**
* 创建一个范围 <br>
* 最大值{@code Integer.MAX_VALUE = 2147483647 } <br>
* 最小值{@code Integer.MIN_VALUE = -2147483648} <br>
* @param start 开始 (包含)
* @param end 完毕 (包含)
* @see Integer
* @return Range 对象
*/
public static Range of(int start, int end) {
return new Range(start, end);
}
/**
* 创建一个范围 <br>
* 最大值{@code Integer.MAX_VALUE = 2147483647 } <br>
* 最小值{@code Integer.MIN_VALUE = -2147483648} <br>
* @param start 开始 (包含)
* @param end 完毕 (包含)
* @param step 步长
* @see Integer
*/
public static Range of(int start, int end, int step) {
return new Range(start, end, step);
}
/**
* 创建一个范围 <br>
* 最大值{@code Integer.MAX_VALUE = 2147483647 } <br>
* 最小值{@code Integer.MIN_VALUE = -2147483648} <br>
* @param start 开始 (包含)
* @param end 完毕 (包含)
* @param step 步长
* @see Integer
*/
public static Range range(int start, int end, int step) {
return new Range(start, end, step);
}
/**
* 创建一个范围 {@code 0 - range}<br>
* 最大值{@code Integer.MAX_VALUE = 2147483647 } <br>
* 最小值{@code Integer.MIN_VALUE = -2147483648} <br>
* @param range 完毕 (包含)
* @see Integer
* @return Range 对象
*/
public static Range range(int range) {
return new Range(range);
}
/**
* 创建一个范围 <br>
* 最大值{@code Integer.MAX_VALUE = 2147483647 } <br>
* 最小值{@code Integer.MIN_VALUE = -2147483648} <br>
* @param start 开始 (包含)
* @param end 完毕 (包含)
* @see Integer
* @return Range 对象
*/
public static Range range(int start, int end) {
return new Range(start, end);
}
/**
* 获取迭代器
* @return 迭代器
*/
@Override
public @NotNull Iterator<Integer> iterator() {
return new Iterator<Integer>() {
@Override
public boolean hasNext() {
return current < end;
}
@Override
public Integer next() {
if (current >= end) {
return null;
}
try {
return current;
} finally {
current = current + step;
}
}
};
}
@Override
public boolean isEmpty() {
return current < end;
}
@Override
public @NotNull Integer getEndInclusive() {
val va = end - step;
return Math.max(va, 0);
}
@Override
public boolean contains(@NotNull Integer integer) {
if (step == 0) return false;
if (step > 0) {
if (integer < start || integer > end) return false;
} else {
if (integer > start || integer < end) return false;
}
return (integer - start) % step == 0;
}
@Override
public @NotNull Integer getEndExclusive() {
return end;
}
@Override
public @NotNull Integer getStart() {
return start;
}
}

View File

@ -1,187 +0,0 @@
package com.mingliqiye.utils.json;
import com.google.gson.*;
public class GsonJsonApi implements JsonApi {
private final Gson gson;
private final Gson gsonUnicode;
private final Gson gsonPretty;
private final Gson gsonPrettyUnicode;
public GsonJsonApi() {
gson = new GsonBuilder()
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
.create();
gsonUnicode = new GsonBuilder()
.disableHtmlEscaping()
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
.create();
gsonPretty = new GsonBuilder()
.setPrettyPrinting()
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
.create();
gsonPrettyUnicode = new GsonBuilder()
.setPrettyPrinting()
.disableHtmlEscaping()
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
.create();
}
public GsonJsonApi(Gson gson) {
this.gson = gson
.newBuilder()
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
.create();
this.gsonUnicode = gson
.newBuilder()
.disableHtmlEscaping()
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
.create();
this.gsonPretty = gson
.newBuilder()
.setPrettyPrinting()
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
.create();
this.gsonPrettyUnicode = gson
.newBuilder()
.setPrettyPrinting()
.disableHtmlEscaping()
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
.create();
}
@Override
public <T> T parse(String json, Class<T> clazz) {
return gson.fromJson(json, clazz);
}
@Override
public <T> T parse(String json, JsonTypeReference<T> type) {
return gson.fromJson(json, type.getType());
}
@Override
public String format(Object object) {
return gson.toJson(object);
}
@Override
public String formatUnicode(Object object) {
return gsonUnicode.toJson(object);
}
@Override
public String formatPretty(Object object) {
return gsonPretty.toJson(object);
}
@Override
public String formatPrettyUnicode(Object object) {
return gsonPrettyUnicode.toJson(object);
}
@Override
public boolean isValidJson(String json) {
try {
JsonElement element = JsonParser.parseString(json);
return true;
} catch (JsonSyntaxException e) {
return false;
} catch (Exception e) {
return false;
}
}
@Override
public String merge(String... jsons) {
JsonObject merged = new JsonObject();
for (String json : jsons) {
if (json == null || json.isEmpty()) {
continue;
}
try {
JsonObject obj = JsonParser.parseString(json).getAsJsonObject();
for (String key : obj.keySet()) {
merged.add(key, obj.get(key));
}
} catch (Exception e) {
// 忽略无效的 JSON 字符串
}
}
return gson.toJson(merged);
}
@Override
public String getNodeValue(String json, String path) {
try {
JsonElement element = JsonParser.parseString(json);
String[] paths = path.split("\\.");
JsonElement current = element;
for (String p : paths) {
if (current.isJsonObject()) {
current = current.getAsJsonObject().get(p);
} else {
return null;
}
if (current == null) {
return null;
}
}
return current.isJsonPrimitive()
? current.getAsString()
: current.toString();
} catch (Exception e) {
return null;
}
}
@Override
public String updateNodeValue(String json, String path, Object newValue) {
try {
JsonObject obj = JsonParser.parseString(json).getAsJsonObject();
String[] paths = path.split("\\.");
JsonObject current = obj;
// 导航到倒数第二层
for (int i = 0; i < paths.length - 1; i++) {
String p = paths[i];
if (!current.has(p) || !current.get(p).isJsonObject()) {
current.add(p, new JsonObject());
}
current = current.getAsJsonObject(p);
}
// 设置最后一层的值
String lastPath = paths[paths.length - 1];
if (newValue == null) {
current.remove(lastPath);
} else {
JsonElement element = gson.toJsonTree(newValue);
current.add(lastPath, element);
}
return gson.toJson(obj);
} catch (Exception e) {
return json;
}
}
@Override
public <T, D> D convert(T source, Class<D> destinationClass) {
String json = gson.toJson(source);
return gson.fromJson(json, destinationClass);
}
@Override
public <T, D> D convert(T source, JsonTypeReference<D> destinationType) {
String json = gson.toJson(source);
return gson.fromJson(json, destinationType.getType());
}
}

View File

@ -1,341 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile JacksonJsonApi.java
* LastUpdate 2025-09-09 09:31:31
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.json;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.io.IOException;
import java.util.List;
import java.util.Map;
/**
* 基于Jackson的JSON处理实现类提供JSON字符串解析格式化合并节点操作等功能
*/
public class JacksonJsonApi implements JsonApi {
private final ObjectMapper objectMapper;
/**
* 使用默认的ObjectMapper构造实例
*/
public JacksonJsonApi() {
this.objectMapper = new ObjectMapper();
}
/**
* 使用指定的ObjectMapper构造实例
*
* @param objectMapper 自定义的ObjectMapper实例
*/
public JacksonJsonApi(ObjectMapper objectMapper) {
this.objectMapper = objectMapper.copy();
}
/**
* 将JSON字符串解析为指定类型的对象
*
* @param json 待解析的JSON字符串
* @param clazz 目标对象类型
* @param <T> 泛型参数表示目标对象类型
* @return 解析后的对象
* @throws JsonException 当解析失败时抛出异常
*/
@Override
public <T> T parse(String json, Class<T> clazz) {
try {
return objectMapper.readValue(json, clazz);
} catch (IOException e) {
throw new JsonException("Failed to parse JSON string", e);
}
}
/**
* 将JSON字符串解析为复杂泛型结构的对象如ListMap等
*
* @param json JSON字符串
* @param type 泛型类型引用
* @param <T> 泛型参数表示目标对象类型
* @return 解析后的对象
* @throws JsonException 当解析失败时抛出异常
*/
@Override
public <T> T parse(String json, JsonTypeReference<T> type) {
try {
ObjectReader reader = objectMapper.readerFor(
objectMapper.constructType(type.getType())
);
return reader.readValue(json);
} catch (IOException e) {
throw new JsonException("Failed to parse JSON string", e);
}
}
/**
* 将对象格式化为JSON字符串
*
* @param object 待格式化的对象
* @return 格式化后的JSON字符串
* @throws JsonException 当格式化失败时抛出异常
*/
@Override
public String format(Object object) {
try {
return objectMapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
throw new JsonException(
"Failed to format object to JSON string",
e
);
}
}
@Override
public String formatUnicode(Object object) {
try {
return objectMapper
.writer()
.with(JsonGenerator.Feature.ESCAPE_NON_ASCII)
.writeValueAsString(object);
} catch (JsonProcessingException e) {
throw new JsonException(e);
}
}
/**
* 将对象格式化为美化带缩进的JSON字符串
*
* @param object 待格式化的对象
* @return 美化后的JSON字符串
* @throws JsonException 当格式化失败时抛出异常
*/
@Override
public String formatPretty(Object object) {
try {
return objectMapper
.writerWithDefaultPrettyPrinter()
.writeValueAsString(object);
} catch (JsonProcessingException e) {
throw new JsonException(
"Failed to format object to pretty JSON string",
e
);
}
}
@Override
public String formatPrettyUnicode(Object object) {
try {
return objectMapper
.writerWithDefaultPrettyPrinter()
.with(JsonGenerator.Feature.ESCAPE_NON_ASCII)
.writeValueAsString(object);
} catch (JsonProcessingException e) {
throw new JsonException(
"Failed to format object to pretty JSON string",
e
);
}
}
/**
* 将JSON字符串解析为指定元素类型的List
*
* @param json JSON字符串
* @param elementType List中元素的类型
* @param <T> 泛型参数表示List中元素的类型
* @return 解析后的List对象
*/
@Override
public <T> List<T> parseList(String json, Class<T> elementType) {
return parse(json, JsonTypeUtils.listType(elementType));
}
/**
* 将JSON字符串解析为指定键值类型的Map
*
* @param json JSON字符串
* @param keyType Map中键的类型
* @param valueType Map中值的类型
* @param <K> 泛型参数表示Map中键的类型
* @param <V> 泛型参数表示Map中值的类型
* @return 解析后的Map对象
*/
@Override
public <K, V> Map<K, V> parseMap(
String json,
Class<K> keyType,
Class<V> valueType
) {
return parse(json, JsonTypeUtils.MapType(keyType, valueType));
}
/**
* 判断给定字符串是否是有效的JSON格式
*
* @param json 待验证的字符串
* @return 如果是有效JSON返回true否则返回false
*/
@Override
public boolean isValidJson(String json) {
try {
objectMapper.readTree(json);
return true;
} catch (Exception e) {
return false;
}
}
/**
* 合并多个JSON字符串为一个JSON对象
*
* @param jsons 多个JSON字符串
* @return 合并后的JSON字符串
* @throws JsonException 当合并失败时抛出异常
*/
@Override
public String merge(String... jsons) {
ObjectNode result = objectMapper.createObjectNode();
for (String json : jsons) {
try {
JsonNode node = objectMapper.readTree(json);
if (node.isObject()) {
result.setAll((ObjectNode) node);
}
} catch (IOException e) {
// 忽略无效的JSON字符串
}
}
try {
return objectMapper.writeValueAsString(result);
} catch (JsonProcessingException e) {
throw new JsonException("Failed to merge JSON strings", e);
}
}
/**
* 获取JSON字符串中指定路径的节点值
*
* @param json JSON字符串
* @param path 节点路径使用"."分隔
* @return 节点值的文本表示如果路径不存在则返回null
* @throws JsonException 当获取节点值失败时抛出异常
*/
@Override
public String getNodeValue(String json, String path) {
try {
JsonNode node = objectMapper.readTree(json);
String[] paths = path.split("\\.");
for (String p : paths) {
node = node.get(p);
if (node == null) {
return null;
}
}
return node.asText();
} catch (IOException e) {
throw new JsonException("Failed to get node value", e);
}
}
/**
* 更新JSON字符串中指定路径的节点值
*
* @param json JSON字符串
* @param path 节点路径使用"."分隔
* @param newValue 新的节点值
* @return 更新后的JSON字符串
* @throws JsonException 当更新节点值失败时抛出异常
*/
@Override
public String updateNodeValue(String json, String path, Object newValue) {
try {
JsonNode node = objectMapper.readTree(json);
if (node instanceof ObjectNode) {
ObjectNode objectNode = (ObjectNode) node;
String[] paths = path.split("\\.");
JsonNode current = objectNode;
// 导航到目标节点的父节点
for (int i = 0; i < paths.length - 1; i++) {
current = current.get(paths[i]);
if (current == null || !(current instanceof ObjectNode)) {
return json; // 路径不存在或无效
}
}
// 更新值
if (current instanceof ObjectNode) {
ObjectNode parent = (ObjectNode) current;
if (newValue == null) {
parent.remove(paths[paths.length - 1]);
} else {
parent.set(
paths[paths.length - 1],
objectMapper.valueToTree(newValue)
);
}
}
return objectMapper.writeValueAsString(objectNode);
}
return json;
} catch (IOException e) {
throw new JsonException("Failed to update node value", e);
}
}
/**
* 在不同对象类型之间进行转换
*
* @param source 源对象
* @param destinationClass 目标对象类型
* @param <T> 源对象类型
* @param <D> 目标对象类型
* @return 转换后的对象
*/
@Override
public <T, D> D convert(T source, Class<D> destinationClass) {
return objectMapper.convertValue(source, destinationClass);
}
/**
* 在不同泛型对象类型之间进行转换
*
* @param source 源对象
* @param destinationType 目标对象的泛型类型引用
* @param <T> 源对象类型
* @param <D> 目标对象类型
* @return 转换后的对象
*/
@Override
public <T, D> D convert(T source, JsonTypeReference<D> destinationType) {
return objectMapper.convertValue(
source,
objectMapper.constructType(destinationType.getType())
);
}
}

View File

@ -1,390 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile JsonApi.java
* LastUpdate 2025-09-09 09:22:02
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.json;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
/**
* JSON处理接口提供JSON字符串与Java对象之间的相互转换功能
*/
public interface JsonApi {
/**
* 将JSON字符串解析为指定类型的对象
*
* @param json 待解析的JSON字符串
* @param clazz 目标对象的Class类型
* @param <T> 泛型参数表示目标对象的类型
* @return 解析后的对象实例
*/
<T> T parse(String json, Class<T> clazz);
/**
* 将JSON字符串解析为指定泛型类型对象
*
* @param json 待解析的JSON字符串
* @param type 目标对象的Type类型支持泛型
* @param <T> 泛型参数表示目标对象的类型
* @return 解析后的对象实例
*/
<T> T parse(String json, JsonTypeReference<T> type);
/**
* 将对象格式化为JSON字符串
*
* @param object 待格式化的对象
* @return 格式化后的JSON字符串
*/
String format(Object object);
String formatUnicode(Object object);
default <T> T parseFrom(String path, Class<T> clazz) throws IOException {
return parseFrom(Paths.get(path), clazz);
}
default <T> T parseFrom(Path path, Class<T> clazz) throws IOException {
return parseFrom(path.toFile(), clazz);
}
default <T> T parseFrom(File file, Class<T> clazz) throws IOException {
try (InputStream inputStream = Files.newInputStream(file.toPath())) {
return parseFrom(inputStream, clazz);
}
}
default <T> T parseFrom(InputStream inputStream, Class<T> clazz)
throws IOException {
if (inputStream == null) {
throw new IllegalArgumentException("inputStream cannot be null");
}
if (clazz == null) {
throw new IllegalArgumentException("clazz cannot be null");
}
byte[] bytes = new byte[1024];
try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
int readlength;
while ((readlength = inputStream.read(bytes)) != -1) {
bos.write(bytes, 0, readlength);
}
return parse(bos.toByteArray(), clazz);
}
}
default <T> T parseFrom(String path, JsonTypeReference<T> type)
throws IOException {
return parseFrom(Paths.get(path), type);
}
default <T> T parseFrom(Path path, JsonTypeReference<T> type)
throws IOException {
return parseFrom(path.toFile(), type);
}
default <T> T parseFrom(File file, JsonTypeReference<T> type)
throws IOException {
try (InputStream inputStream = Files.newInputStream(file.toPath())) {
return parseFrom(inputStream, type);
}
}
default <T> T parseFrom(InputStream inputStream, JsonTypeReference<T> type)
throws IOException {
if (inputStream == null) {
throw new IllegalArgumentException("inputStream cannot be null");
}
if (type == null) {
throw new IllegalArgumentException("type cannot be null");
}
byte[] bytes = new byte[1024];
try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
int readlength;
while ((readlength = inputStream.read(bytes)) != -1) {
bos.write(bytes, 0, readlength);
}
return parse(bos.toByteArray(), type);
}
}
/**
* 将字节数组形式的JSON解析为指定类型的对象
*
* @param json 待解析的JSON字节数组
* @param clazz 目标对象的Class类型
* @param <T> 泛型参数表示目标对象的类型
* @return 解析后的对象实例
*/
default <T> T parse(byte[] json, Class<T> clazz) {
return parse(new String(json), clazz);
}
/**
* 将字节数组形式的JSON解析为指定泛型类型对象
*
* @param json 待解析的JSON字节数组
* @param type 目标对象的Type类型支持泛型
* @param <T> 泛型参数表示目标对象的类型
* @return 解析后的对象实例
*/
default <T> T parse(byte[] json, JsonTypeReference<T> type) {
return parse(new String(json), type);
}
/**
* 将JSON字符串解析为指定类型的对象解析失败时返回默认值
*
* @param json 待解析的JSON字符串
* @param clazz 目标对象的Class类型
* @param defaultValue 解析失败时返回的默认值
* @param <T> 泛型参数表示目标对象的类型
* @return 解析后的对象实例或默认值
*/
default <T> T parse(String json, Class<T> clazz, T defaultValue) {
try {
return parse(json, clazz);
} catch (Exception e) {
return defaultValue;
}
}
/**
* 将JSON字符串解析为指定泛型类型对象解析失败时返回默认值
*
* @param json 待解析的JSON字符串
* @param type 目标对象的Type类型支持泛型
* @param defaultValue 解析失败时返回的默认值
* @param <T> 泛型参数表示目标对象的类型
* @return 解析后的对象实例或默认值
*/
default <T> T parse(
String json,
JsonTypeReference<T> type,
T defaultValue
) {
try {
return parse(json, type);
} catch (Exception e) {
return defaultValue;
}
}
/**
* 将对象格式化为美化格式的JSON字符串带缩进和换行
*
* @param object 待格式化的对象
* @return 格式化后的美化JSON字符串
*/
String formatPretty(Object object);
default byte[] formatPrettyBytes(Object object) {
return formatPretty(object).getBytes();
}
String formatPrettyUnicode(Object object);
default byte[] formatPrettyUnicodeBytes(Object object) {
return formatPrettyUnicode(object).getBytes();
}
default void formatPretty(Object object, String file) throws IOException {
formatPretty(object, Paths.get(file));
}
default void formatPretty(Object object, Path file) throws IOException {
formatPretty(object, file.toFile());
}
default void formatPretty(Object object, File file) throws IOException {
try (FileOutputStream fos = new FileOutputStream(file)) {
formatPretty(object, fos);
}
}
default void formatPretty(Object object, OutputStream stream)
throws IOException {
stream.write(formatPrettyBytes(object));
}
default void formatPrettyUnicode(Object object, String file)
throws IOException {
formatPrettyUnicode(object, Paths.get(file));
}
default void formatPrettyUnicode(Object object, Path file)
throws IOException {
formatPrettyUnicode(object, file.toFile());
}
default void formatPrettyUnicode(Object object, File file)
throws IOException {
try (FileOutputStream fos = new FileOutputStream(file)) {
formatPrettyUnicode(object, fos);
}
}
default void formatPrettyUnicode(Object object, OutputStream stream)
throws IOException {
stream.write(formatPrettyUnicodeBytes(object));
}
default byte[] formatBytes(Object object) {
return format(object).getBytes();
}
default byte[] formatUnicodeBytes(Object object) {
return formatUnicode(object).getBytes();
}
default void format(Object object, String file) throws IOException {
format(object, Paths.get(file));
}
default void format(Object object, Path file) throws IOException {
format(object, file.toFile());
}
default void format(Object object, File file) throws IOException {
try (FileOutputStream fos = new FileOutputStream(file)) {
format(object, fos);
}
}
default void format(Object object, OutputStream stream) throws IOException {
stream.write(formatPrettyBytes(object));
}
default void formatUnicode(Object object, String file) throws IOException {
formatUnicode(object, Paths.get(file));
}
default void formatUnicode(Object object, Path file) throws IOException {
formatUnicode(object, file.toFile());
}
default void formatUnicode(Object object, File file) throws IOException {
try (FileOutputStream fos = new FileOutputStream(file)) {
formatUnicode(object, fos);
}
}
default void formatUnicode(Object object, OutputStream stream)
throws IOException {
stream.write(formatPrettyUnicodeBytes(object));
}
/**
* 将JSON字符串解析为指定元素类型的List集合
*
* @param json 待解析的JSON字符串
* @param elementType List中元素的类型
* @param <T> 泛型参数表示List中元素的类型
* @return 解析后的List集合
*/
default <T> List<T> parseList(String json, Class<T> elementType) {
return parse(json, JsonTypeUtils.listType(elementType));
}
/**
* 将JSON字符串解析为指定键值类型的Map集合
*
* @param json 待解析的JSON字符串
* @param keyType Map中键的类型
* @param valueType Map中值的类型
* @param <K> 泛型参数表示Map中键的类型
* @param <V> 泛型参数表示Map中值的类型
* @return 解析后的Map集合
*/
default <K, V> Map<K, V> parseMap(
String json,
Class<K> keyType,
Class<V> valueType
) {
JsonTypeReference<Map<K, V>> mapType = new JsonTypeReference<
Map<K, V>
>() {};
return parse(json, mapType);
}
/**
* 验证字符串是否为有效的JSON格式
*
* @param json 待验证的字符串
* @return 如果是有效的JSON格式返回true否则返回false
*/
boolean isValidJson(String json);
/**
* 将对象转换为JSON字节数组
*
* @param object 待转换的对象
* @return 转换后的JSON字节数组
*/
default byte[] toBytes(Object object) {
return format(object).getBytes();
}
/**
* 将对象转换为美化格式的JSON字节数组
*
* @param object 待转换的对象
* @return 转换后的美化格式JSON字节数组
*/
default byte[] toBytesPretty(Object object) {
return formatPretty(object).getBytes();
}
/**
* 合并多个JSON字符串为一个JSON对象
*
* @param jsons 待合并的JSON字符串数组
* @return 合并后的JSON字符串
*/
String merge(String... jsons);
/**
* 获取JSON字符串中指定路径节点的值
*
* @param json JSON字符串
* @param path 节点路径"user.name"
* @return 节点值的字符串表示
*/
String getNodeValue(String json, String path);
/**
* 更新JSON字符串中指定路径节点的值
*
* @param json 原始JSON字符串
* @param path 节点路径"user.name"
* @param newValue 新的节点值
* @return 更新后的JSON字符串
*/
String updateNodeValue(String json, String path, Object newValue);
<T, D> D convert(T source, Class<D> destinationClass);
<T, D> D convert(T source, JsonTypeReference<D> destinationType);
}

View File

@ -1,175 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile JsonTypeReference.java
* LastUpdate 2025-09-09 09:20:05
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.json;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Objects;
import lombok.Getter;
/**
* 通用的 JSON 类型引用类用于在运行时保留泛型类型信息
* 适用于所有 JSON JacksonGsonFastjson
*
* @param <T> 引用的泛型类型
*/
@Getter
public abstract class JsonTypeReference<T>
implements Comparable<JsonTypeReference<T>> {
protected final Type type;
/**
* 构造函数通过反射获取泛型类型信息
* 仅供内部匿名子类使用
*/
protected JsonTypeReference() {
Type superClass = getClass().getGenericSuperclass();
// 检查是否为匿名子类防止直接实例化导致无法获取泛型信息
if (superClass instanceof Class) {
throw new IllegalArgumentException(
"必须使用匿名子类方式创建 JsonTypeReference" +
"例如: new JsonTypeReference<List<String>>() {}"
);
}
this.type =
((ParameterizedType) superClass).getActualTypeArguments()[0];
}
/**
* 构造函数直接指定类型
* @param type 具体的类型信息
*/
protected JsonTypeReference(Type type) {
this.type = Objects.requireNonNull(type, "Type cannot be null");
}
/**
* 创建类型引用实例
* @param <T> 目标类型
* @return 类型引用实例
*/
public static <T> JsonTypeReference<T> of() {
return new JsonTypeReference<T>() {};
}
/**
* 根据 Class 创建类型引用
* @param clazz 目标类
* @param <T> 目标类型
* @return 类型引用实例
*/
public static <T> JsonTypeReference<T> of(Class<T> clazz) {
return new JsonTypeReference<T>(clazz) {};
}
/**
* 根据 Type 创建类型引用
* @param type 目标类型
* @param <T> 目标类型
* @return 类型引用实例
*/
public static <T> JsonTypeReference<T> of(Type type) {
return new JsonTypeReference<T>(type) {};
}
/**
* 获取原始类型去掉泛型参数的类型
* @return 原始类型 Class
*/
@SuppressWarnings("unchecked")
public Class<T> getRawType() {
Type rawType = type;
// 如果是参数化类型则提取原始类型部分
if (type instanceof ParameterizedType) {
rawType = ((ParameterizedType) type).getRawType();
}
if (rawType instanceof Class) {
return (Class<T>) rawType;
}
throw new IllegalStateException("无法获取原始类型: " + type);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
JsonTypeReference<?> that = (JsonTypeReference<?>) o;
// 对于 ParameterizedType需要更完整的比较
if (
this.type instanceof ParameterizedType &&
that.type instanceof ParameterizedType
) {
ParameterizedType thisParamType = (ParameterizedType) this.type;
ParameterizedType thatParamType = (ParameterizedType) that.type;
return (
Objects.equals(
thisParamType.getRawType(),
thatParamType.getRawType()
) &&
Arrays.equals(
thisParamType.getActualTypeArguments(),
thatParamType.getActualTypeArguments()
) &&
Objects.equals(
thisParamType.getOwnerType(),
thatParamType.getOwnerType()
)
);
}
return Objects.equals(type, that.type);
}
@Override
public int hashCode() {
// 针对 ParameterizedType 进行完整哈希计算
if (type instanceof ParameterizedType) {
ParameterizedType paramType = (ParameterizedType) type;
return Objects.hash(
paramType.getRawType(),
Arrays.hashCode(paramType.getActualTypeArguments()),
paramType.getOwnerType()
);
}
return Objects.hash(type);
}
@Override
public String toString() {
return "JsonTypeReference{" + type + '}';
}
@Override
public int compareTo(JsonTypeReference<T> o) {
return this.type.toString().compareTo(o.type.toString());
}
}

View File

@ -1,253 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile JsonTypeUtils.java
* LastUpdate 2025-09-09 09:18:08
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.json;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* JSON 类型工具类提供类型相关的工具方法
*/
public class JsonTypeUtils {
private JsonTypeUtils() {
// 工具类防止实例化
}
/**
* 检查给定的类型是否是指定类或其子类/实现类
*
* @param type 要检查的类型
* @param expectedClass 期望匹配的类
* @return 如果类型匹配则返回 true否则返回 false
*/
public static boolean isTypeOf(Type type, Class<?> expectedClass) {
if (type instanceof Class) {
return expectedClass.isAssignableFrom((Class<?>) type);
} else if (type instanceof ParameterizedType) {
return isTypeOf(
((ParameterizedType) type).getRawType(),
expectedClass
);
}
return false;
}
/**
* 获取泛型类型的参数类型
*
* @param type 泛型类型
* @param index 参数索引从0开始
* @return 指定位置的泛型参数类型
* @throws IllegalArgumentException 当无法获取指定索引的泛型参数时抛出异常
*/
public static Type getGenericParameter(Type type, int index) {
if (type instanceof ParameterizedType) {
Type[] typeArgs =
((ParameterizedType) type).getActualTypeArguments();
if (index >= 0 && index < typeArgs.length) {
return typeArgs[index];
}
}
throw new IllegalArgumentException(
"无法获取泛型参数: " + type + " at index " + index
);
}
/**
* 获取类型名称支持普通类和泛型类型
*
* @param type 类型对象
* @return 类型名称字符串
*/
public static String getTypeName(Type type) {
if (type instanceof Class) {
return ((Class<?>) type).getSimpleName();
} else if (type instanceof ParameterizedType) {
ParameterizedType pType = (ParameterizedType) type;
Class<?> rawType = (Class<?>) pType.getRawType();
Type[] typeArgs = pType.getActualTypeArguments();
StringBuilder sb = new StringBuilder(rawType.getSimpleName());
sb.append("<");
for (int i = 0; i < typeArgs.length; i++) {
if (i > 0) sb.append(", ");
sb.append(getTypeName(typeArgs[i]));
}
sb.append(">");
return sb.toString();
}
return type.getTypeName();
}
/**
* 创建一个表示数组类型的引用对象
*
* @param componentType 数组元素的类型
* @param <T> 元素类型
* @return 表示数组类型的 JsonTypeReference 对象
*/
public static <T> JsonTypeReference<T[]> arrayType(Class<T> componentType) {
return new JsonTypeReference<T[]>() {
private final Type arrayType = java.lang.reflect.Array.newInstance(
componentType,
0
).getClass();
@Override
public Type getType() {
return new ParameterizedType() {
private final Type[] actualTypeArguments = new Type[] {
componentType,
};
@Override
public Type[] getActualTypeArguments() {
return actualTypeArguments;
}
@Override
public Type getRawType() {
return arrayType;
}
@Override
public Type getOwnerType() {
return null;
}
};
}
};
}
/**
* 创建一个表示 List 类型的引用对象
*
* @param componentType List 中元素的类型
* @param <T> 元素类型
* @return 表示 List 类型的 JsonTypeReference 对象
* @throws IllegalArgumentException 如果 componentType null则抛出异常
*/
public static <T> JsonTypeReference<List<T>> listType(
Class<T> componentType
) {
if (componentType == null) {
throw new IllegalArgumentException("componentType cannot be null");
}
return new JsonTypeReference<List<T>>() {
@Override
public Type getType() {
return new ParameterizedType() {
@Override
public Type[] getActualTypeArguments() {
return new Type[] { componentType };
}
@Override
public Type getRawType() {
return List.class;
}
@Override
public Type getOwnerType() {
return null;
}
};
}
};
}
/**
* 创建一个表示 Map 类型的引用对象
*
* @param keyType Map 键的类型
* @param valueType Map 值的类型
* @param <K> 键类型
* @param <V> 值类型
* @return 表示 Map 类型的 JsonTypeReference 对象
* @throws IllegalArgumentException 如果 keyType valueType null则抛出异常
*/
public static <K, V> JsonTypeReference<Map<K, V>> MapType(
Class<K> keyType,
Class<V> valueType
) {
if (keyType == null) {
throw new IllegalArgumentException("keyType cannot be null");
}
if (valueType == null) {
throw new IllegalArgumentException("valueType cannot be null");
}
return new JsonTypeReference<Map<K, V>>() {
@Override
public Type getType() {
return new ParameterizedType() {
@Override
public Type[] getActualTypeArguments() {
return new Type[] { keyType, valueType };
}
@Override
public Type getRawType() {
return Map.class;
}
@Override
public Type getOwnerType() {
return null;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof ParameterizedType)) return false;
ParameterizedType that = (ParameterizedType) obj;
return (
Objects.equals(getRawType(), that.getRawType()) &&
Arrays.equals(
getActualTypeArguments(),
that.getActualTypeArguments()
) &&
Objects.equals(getOwnerType(), that.getOwnerType())
);
}
@Override
public int hashCode() {
return (
Arrays.hashCode(getActualTypeArguments()) ^
Objects.hashCode(getRawType()) ^
Objects.hashCode(getOwnerType())
);
}
};
}
};
}
}

View File

@ -1,32 +0,0 @@
package com.mingliqiye.utils.json.converters;
import com.mingliqiye.utils.time.DateTime;
import com.mingliqiye.utils.time.Formatter;
public class DateTimeJsonConverter extends JsonStringConverter<DateTime> {
@Override
public Class<DateTime> getTClass() {
return DateTime.class;
}
@Override
public String convert(DateTime obj) {
if (obj == null) {
return null;
}
return obj.format(Formatter.STANDARD_DATETIME);
}
@Override
public DateTime deConvert(String string) {
if (string == null) {
return null;
}
return DateTime.parse(
string,
Formatter.STANDARD_DATETIME_MILLISECOUND7,
true
);
}
}

View File

@ -1,88 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile FastjsonJsonStringConverterAdapter.java
* LastUpdate 2025-09-14 22:12:16
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.json.converters;
import com.alibaba.fastjson2.JSONReader;
import com.alibaba.fastjson2.JSONWriter;
import com.alibaba.fastjson2.reader.ObjectReader;
import com.alibaba.fastjson2.writer.ObjectWriter;
import java.lang.reflect.Type;
public class FastjsonJsonStringConverterAdapter<
T extends JsonStringConverter<TT>,
TT
> {
private final JsonStringConverter<TT> jsonStringConverter;
public FastjsonJsonStringConverterAdapter(T jsonStringConverter) {
this.jsonStringConverter = jsonStringConverter;
}
public static <
T extends JsonStringConverter<TT>,
TT
> FastjsonJsonStringConverterAdapter<T, TT> of(T t) {
return new FastjsonJsonStringConverterAdapter<>(t);
}
/**
* 获取FastJson对象写入器
*
* @return FastJson的ObjectWriter实例
*/
public ObjectWriter<T> getFastJsonObjectWriter() {
return (
JSONWriter writer,
Object object,
Object fieldName,
Type fieldType,
long features
) -> {
// 如果对象为null则写入null
if (object == null) {
writer.writeNull();
return;
}
writer.writeString(jsonStringConverter.convert((TT) object));
};
}
/**
* 获取FastJson对象读取器
*
* @return FastJson的ObjectReader实例
*/
public ObjectReader<TT> getFastJsonObjectReader() {
return (
JSONReader reader,
Type fieldType,
Object fieldName,
long features
) -> {
String value = reader.readString();
return jsonStringConverter.deConvert(value);
};
}
}

View File

@ -1,72 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile GsonJsonStringConverterAdapter.java
* LastUpdate 2025-09-14 22:12:16
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.json.converters;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;
public class GsonJsonStringConverterAdapter<
T extends JsonStringConverter<TT>,
TT
> {
private final JsonStringConverter<TT> jsonStringConverter;
public GsonJsonStringConverterAdapter(T jsonStringConverter) {
this.jsonStringConverter = jsonStringConverter;
}
public static <
T extends JsonStringConverter<TT>,
TT
> GsonJsonStringConverterAdapter<T, TT> of(T t) {
return new GsonJsonStringConverterAdapter<>(t);
}
/**
* 获取Gson类型适配器
*
* @return Gson的TypeAdapter实例
*/
public TypeAdapter<TT> getGsonTypeAdapter() {
return new TypeAdapter<TT>() {
@Override
public void write(JsonWriter out, TT value) throws IOException {
if (value == null) {
out.nullValue();
return;
}
out.value(jsonStringConverter.convert(value));
}
@Override
public TT read(JsonReader in) throws IOException {
String value = in.nextString();
return jsonStringConverter.deConvert(value);
}
};
}
}

View File

@ -1,91 +0,0 @@
package com.mingliqiye.utils.json.converters;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.module.SimpleModule;
import java.io.IOException;
/**
* JSON转换器的适配器
* @param <T> JSON转换器
* @param <TT> JSON转换器的泛型
* @author MingLiPro
*/
public class JacksonJsonStringConverterAdapter<
T extends JsonStringConverter<TT>,
TT
> {
private final JsonStringConverter<TT> jsonStringConverter;
private JacksonJsonStringConverterAdapter(T jsonStringConverter) {
this.jsonStringConverter = jsonStringConverter;
}
/**
*
* @param t JSON转换器实例
* @return JSON转换器的适配器
* @param <T> JSON转换器
* @param <TT> JSON转换器的泛型
*/
public static <
T extends JsonStringConverter<TT>,
TT
> JacksonJsonStringConverterAdapter<T, TT> of(T t) {
return new JacksonJsonStringConverterAdapter<>(t);
}
/**
* 获取Jackson反序列化器
*
* @return Jackson的JsonDeserializer实例
*/
public JsonDeserializer<TT> getJacksonJsonDeserializer() {
return new JsonDeserializer<TT>() {
@Override
public TT deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException {
if (p.isNaN()) return null;
return jsonStringConverter.deConvert(p.getValueAsString());
}
};
}
/**
* 获取Jackson序列化器
*
* @return Jackson的JsonSerializer实例
*/
public JsonSerializer<TT> getJacksonJsonSerializer() {
return new JsonSerializer<TT>() {
@Override
public void serialize(
TT value,
JsonGenerator gen,
SerializerProvider serializers
) throws IOException {
if (value == null) {
gen.writeNull();
return;
}
gen.writeString(jsonStringConverter.convert(value));
}
};
}
/**
*
* 获取 Jackson 的格式化模块
*
* @return 格式化模块
*/
public Module getJacksonModule() {
Class<TT> tClass = jsonStringConverter.getTClass();
SimpleModule m = new SimpleModule(tClass.getSimpleName());
m.addSerializer(tClass, getJacksonJsonSerializer());
m.addDeserializer(tClass, getJacksonJsonDeserializer());
return m;
}
}

View File

@ -1,60 +0,0 @@
package com.mingliqiye.utils.json.converters;
/**
* JSON转换器接口提供对象与字符串之间的相互转换功能并支持多种JSON库
*
* @param <T> 需要转换的对象类型
*/
public abstract class JsonStringConverter<T> {
public abstract Class<T> getTClass();
/**
* 将对象转换为字符串
*
* @param obj 待转换的对象
* @return 转换后的字符串
*/
abstract String convert(T obj);
/**
* 将字符串转换为对象
*
* @param string 待转换的字符串
* @return 转换后的对象
*/
abstract T deConvert(String string);
/**
* 获取 Fastjson 的适配器
* @return 适配器实例
*/
public FastjsonJsonStringConverterAdapter<
JsonStringConverter<T>,
T
> getFastjsonJsonStringConverterAdapter() {
return FastjsonJsonStringConverterAdapter.of(this);
}
/**
* 获取 Gson 的适配器
* @return 适配器实例
*/
public GsonJsonStringConverterAdapter<
JsonStringConverter<T>,
T
> getGsonJsonStringConverterAdapter() {
return GsonJsonStringConverterAdapter.of(this);
}
/**
* 获取 Jackson 的适配器
* @return 适配器实例
*/
public JacksonJsonStringConverterAdapter<
JsonStringConverter<T>,
T
> getJacksonJsonStringConverterAdapter() {
return JacksonJsonStringConverterAdapter.of(this);
}
}

View File

@ -1,27 +0,0 @@
package com.mingliqiye.utils.json.converters;
import com.mingliqiye.utils.uuid.UUID;
public class UUIDJsonStringConverter extends JsonStringConverter<UUID> {
@Override
public Class<UUID> getTClass() {
return UUID.class;
}
@Override
public String convert(UUID obj) {
if (obj == null) {
return null;
}
return obj.toUUIDString();
}
@Override
public UUID deConvert(String string) {
if (string == null) {
return null;
}
return UUID.of(string);
}
}

View File

@ -1,80 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile Pseudocryptography.java
* LastUpdate 2025-09-14 22:12:16
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.minecraft.pe.json;
import com.mingliqiye.utils.collection.ForEach;
import com.mingliqiye.utils.file.FileUtil;
import com.mingliqiye.utils.json.JsonApi;
import com.mingliqiye.utils.json.JsonTypeReference;
import com.mingliqiye.utils.string.StringUtils;
import lombok.val;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Pseudocryptography {
private final JsonApi jsonApi;
public Pseudocryptography(JsonApi jsonApi) {
this.jsonApi = jsonApi;
}
private Object prossed(Object object) {
if (object instanceof Map) {
System.out.println(object.getClass());
val map = new HashMap<>((Map<Object, Object>) object);
val map2 = new HashMap<>(map.size() + 3);
map.forEach((key, value) -> {
if (key instanceof String) {
map2.put(prossed(key), prossed(value));
}
});
return map2;
} else if (object instanceof String) {
return StringUtils.stringToUnicode((String) object);
} else if (object instanceof List) {
ForEach.forEach((List<Object>) object, (t, i) -> {
((List<Object>) object).set(i, prossed(t));
});
}
return object;
}
public void decode(String path) {
try {
final Map<String, Object> map = jsonApi.parseFrom(
path,
new JsonTypeReference<HashMap<String, Object>>() {}
);
String s = jsonApi.format(prossed(map)).replace("\\\\u", "\\u");
FileUtil.writeStringToFile(StringUtils.format("old-{}", path), s);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -1,32 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile Description.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.minecraft.slp;
import lombok.Data;
@Data
public class Description {
private String text;
private Extra[] extra;
}

View File

@ -1,34 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile Extra.java
* LastUpdate 2025-09-09 08:37:34
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.minecraft.slp;
import lombok.Data;
@Data
public class Extra {
private String text;
private String color;
private Boolean bold;
private Boolean italic;
}

View File

@ -1,37 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile MinecraftServerStatus.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.minecraft.slp;
import lombok.Data;
@Data
public class MinecraftServerStatus {
private Description description;
private Players players;
private Version version;
private String favicon;
private boolean enforcesSecureChat;
private boolean previewsChat;
private String jsonData;
}

View File

@ -1,219 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile SLP.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.minecraft.slp;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mingliqiye.utils.network.NetworkEndpoint;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
/**
* Minecraft 服务器列表协议Server List Ping, SLP工具类
* 提供了与 Minecraft 服务器通信以获取其状态信息的功能
*/
public class SLP {
private static final ObjectMapper objectMapper = new ObjectMapper();
/**
* int32 值截断为无符号 short2 字节并按大端序写入字节数组
*
* @param value 需要转换的整数int32
* @return 包含两个字节的数组表示无符号 short
*/
public static byte[] toUnsignedShort(int value) {
byte[] array = new byte[2];
ByteBuffer.wrap(array, 0, 2)
.order(ByteOrder.BIG_ENDIAN)
.putShort((short) (value & 0xFFFF));
return array;
}
/**
* 构造 Minecraft 握手包数据
* 握手包用于初始化客户端与服务器之间的连接
*
* @param serverIP 服务器 IP 地址或域名
* @param serverPort 服务器端口号
* @param type 连接类型通常为 1 表示获取状态
* @return 握手包的完整字节数组
* @throws IOException 如果构造过程中发生 IO 错误
*/
public static byte[] getHandshakePack(
String serverIP,
int serverPort,
int type
) throws IOException {
ByteArrayOutputStream pack = new ByteArrayOutputStream();
ByteArrayOutputStream byteArrayOutputStream =
new ByteArrayOutputStream();
pack.write(0x00); // 握手包标识符
pack.write(toVarInt(1156)); // 协议版本号示例值
byte[] sip = serverIP.getBytes();
pack.write(toVarInt(sip.length)); // 服务器地址长度
pack.write(sip); // 服务器地址
pack.write(toUnsignedShort(serverPort)); // 服务器端口
pack.write(toVarInt(type)); // 下一阶段类型1 表示状态请求
byteArrayOutputStream.write(toVarInt(pack.size())); // 包长度前缀
byteArrayOutputStream.write(pack.toByteArray());
return byteArrayOutputStream.toByteArray();
}
/**
* 获取状态请求包的固定字节表示
* 此包用于向服务器请求当前状态信息
*
* @return 状态请求包的字节数组
*/
public static byte[] getStatusPack() {
return new byte[] { 0x01, 0x00 };
}
/**
* 从输入流中读取服务器返回的状态 JSON 数据并解析为 MinecraftServerStatus 实体对象
*
* @param inputStream 输入流包含服务器响应的数据
* @return 解析后的 MinecraftServerStatus 对象
* @throws IOException 如果读取过程中发生 IO 错误
*/
public static MinecraftServerStatus getStatusJsonEntity(
DataInputStream inputStream
) throws IOException {
readVarInt(inputStream); // 忽略第一个 VarInt包长度
inputStream.readByte(); // 忽略包标识符
int lengthjson = readVarInt(inputStream); // 读取 JSON 数据长度
byte[] data = new byte[lengthjson];
inputStream.readFully(data); // 读取完整的 JSON 数据
MinecraftServerStatus serverStatus = objectMapper.readValue(
data,
MinecraftServerStatus.class
);
serverStatus.setJsonData(new String(data)); // 设置原始 JSON 字符串
return serverStatus;
}
/**
* 从输入流中读取一个 VarInt 类型的整数最多 5 个字节
*
* @param in 输入流
* @return 解码后的整数值
* @throws IOException 如果读取过程中发生 IO 错误
*/
public static int readVarInt(DataInputStream in) throws IOException {
int value = 0;
int length = 0;
byte currentByte;
do {
currentByte = in.readByte();
value |= (currentByte & 0x7F) << (length * 7);
length += 1;
if (length > 5) {
throw new RuntimeException("VarInt too long");
}
} while ((currentByte & 0x80) != 0);
return value;
}
/**
* 将一个 int32 整数编码为 VarInt 格式的字节数组1 5 个字节
*
* @param value 需要编码的整数
* @return 编码后的 VarInt 字节数组
*/
public static byte[] toVarInt(int value) {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
while (true) {
if ((value & 0xFFFFFF80) == 0) {
buffer.write(value); // 最后一个字节
break;
}
buffer.write((value & 0x7F) | 0x80); // 写入带继续位的字节
value >>>= 7; // 右移 7 位继续处理
}
return buffer.toByteArray();
}
/**
* 创建一个新的 Socket 连接到指定的网络端点并设置超时时间
*
* @param networkEndpoint 目标网络端点包括主机和端口
* @return 已连接的 Socket 实例
* @throws IOException 如果连接失败或发生 IO 错误
*/
public static Socket getNewConnect(NetworkEndpoint networkEndpoint)
throws IOException {
Socket socket = new Socket();
socket.setSoTimeout(5000); // 设置读取超时时间为 5
socket.connect(networkEndpoint.toInetSocketAddress()); // 执行连接操作
return socket;
}
/**
* 使用 "host:port" 格式的字符串连接到 Minecraft 服务器并获取其状态信息
*
* @param s 域名或 IP 地址加端口号组成的字符串例如 "127.0.0.1:25565"
* @return 服务器状态实体对象
* @throws IOException 如果连接失败或发生 IO 错误
*/
public static MinecraftServerStatus getServerStatus(String s)
throws IOException {
return getServerStatus(NetworkEndpoint.of(s));
}
/**
* 使用指定的主机名和端口号连接到 Minecraft 服务器并获取其状态信息
*
* @param s 主机名或 IP 地址
* @param i 端口号
* @return 服务器状态实体对象
* @throws IOException 如果连接失败或发生 IO 错误
*/
public static MinecraftServerStatus getServerStatus(String s, Integer i)
throws IOException {
return getServerStatus(NetworkEndpoint.of(s, i));
}
/**
* 使用 NetworkEndpoint 实例连接到 Minecraft 服务器并获取其状态信息
*
* @param e 网络端点实例包含主机和端口信息
* @return 服务器状态实体对象
* @throws IOException 如果连接失败或发生 IO 错误
* @see NetworkEndpoint
*/
public static MinecraftServerStatus getServerStatus(NetworkEndpoint e)
throws IOException {
Socket socket = getNewConnect(e); // 建立 TCP 连接
OutputStream out = socket.getOutputStream(); // 获取输出流发送数据
DataInputStream in = new DataInputStream(socket.getInputStream()); // 获取输入流接收数据
out.write(getHandshakePack(e.getHost(), e.getPort(), 1)); // 发送握手包
out.write(getStatusPack()); // 发送状态请求包
return getStatusJsonEntity(in); // 读取并解析服务器响应
}
}

View File

@ -1,32 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile Version.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.minecraft.slp;
import lombok.Data;
@Data
public class Version {
private String name;
private int protocol;
}

View File

@ -1,218 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile NetworkAddress.java
* LastUpdate 2025-09-14 22:12:16
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.network;
import com.mingliqiye.utils.string.StringUtils;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import java.io.Serializable;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.regex.Pattern;
/**
* 网络地址类用于表示一个网络地址IP或域名并提供相关操作
* 支持IPv4和IPv6地址的解析与验证
*
* @author MingLiPro
*/
public class NetworkAddress implements Serializable {
/**
* IPv6标识
*/
public static int IPV6 = 6;
/**
* IPv4标识
*/
public static int IPV4 = 4;
/**
* IPv4地址正则表达式
*/
static String IPV4REG =
"^((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})(\\.((2" +
"(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})){3}$";
/**
* 编译后的IPv4地址匹配模式
*/
private static final Pattern IPV4_PATTERN = Pattern.compile(IPV4REG);
/**
* IPv6地址正则表达式
*/
static String IPV6REG =
"^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$|" +
"^(::([0-9a-fA-F]{1,4}:){0,6}[0-9a-fA-F]{1,4})$" +
"|" +
"^(::)$|" +
"^([0-9a-fA-F]{1,4}::([0-9a-fA-F]{1,4}:){0,5}[0-9a-fA-F]{1,4})$|" +
"^(([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4})$|" +
"^(([0-9a-fA-F]{1,4}:){6}(([0-9]{1,3}\\.){3}[0-9]{1,3}))$|" +
"^::([fF]{4}:)?(([0-9]{1,3}\\.){3}[0-9]{1,3})$";
/**
* 编译后的IPv6地址匹配模式
*/
private static final Pattern IPV6_PATTERN = Pattern.compile(IPV6REG);
/**
* IP地址类型4 表示 IPv46 表示 IPv6
*/
@Getter
private int IPv;
/**
* IP地址字符串
*/
@Getter
private String ip;
/**
* 域名如果输入的是域名
*/
private String domain;
/**
* 标识是否是域名解析来的IP
*/
private boolean isdom;
/**
* 构造方法根据传入的字符串判断是IP地址还是域名并进行相应处理
*
* @param domip 可能是IP地址或域名的字符串
*/
NetworkAddress(String domip) {
try {
// 尝试将输入识别为IP地址
IPv = testIp(domip);
ip = domip;
} catch (NetworkException e) {
try {
// 如果不是有效IP则尝试作为域名解析
String ips = getHostIp(domip);
IPv = testIp(ips);
ip = ips;
isdom = true;
domain = domip;
} catch (UnknownHostException ex) {
throw new NetworkException(ex);
}
}
}
/**
* 静态工厂方法创建 NetworkAddress 实例
*
* @param domip 可能是IP地址或域名的字符串
* @return 新建的 NetworkAddress 实例
*/
public static NetworkAddress of(String domip) {
return new NetworkAddress(domip);
}
/**
* 静态工厂方法通过 InetAddress 创建 NetworkAddress 实例
*
* @param inetAddress InetAddress 对象
* @return 新建的 NetworkAddress 实例
*/
public static NetworkAddress of(InetAddress inetAddress) {
return new NetworkAddress(inetAddress.getHostAddress());
}
/**
* 从DNS服务器解析域名获取对应的IP地址
*
* @param domain 域名
* @return 解析出的第一个IP地址
* @throws UnknownHostException 如果域名无法解析
*/
public static String getHostIp(@NotNull String domain)
throws UnknownHostException {
InetAddress[] addresses = InetAddress.getAllByName(domain.trim());
return addresses[0].getHostAddress();
}
/**
* 检测给定字符串是否为有效的IPv4或IPv6地址
*
* @param ip 要检测的IP地址字符串
* @return 4 表示IPv46 表示IPv6
* @throws NetworkException 如果IP格式无效
*/
public static int testIp(String ip) {
if (ip == null) {
throw new NetworkException("IP地址不能为null");
}
String trimmedIp = ip.trim();
// 判断是否匹配IPv4格式
if (IPV4_PATTERN.matcher(trimmedIp).matches()) {
return IPV4;
}
// 判断是否匹配IPv6格式
if (IPV6_PATTERN.matcher(trimmedIp).matches()) {
return IPV6;
}
// 不符合任一格式时抛出异常
throw new NetworkException(
StringUtils.format("[{}] 不是有效的IPv4或IPv6地址", ip)
);
}
/**
* 将当前 NetworkAddress 转换为 InetAddress 对象
*
* @return InetAddress 对象
*/
public InetAddress toInetAddress() {
try {
return InetAddress.getByName(ip != null ? ip : domain);
} catch (UnknownHostException e) {
throw new RuntimeException(e);
}
}
/**
* 返回 NetworkAddress 的字符串表示形式
*
* @return 字符串表示
*/
public String toString() {
return isdom
? StringUtils.format(
"NetworkAddress(IP='{}',type='{}'," + "domain='{}')",
ip,
IPv,
domain
)
: StringUtils.format("NetworkAddress(IP='{}',type='{}')", ip, IPv);
}
}

View File

@ -1,164 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile NetworkEndpoint.java
* LastUpdate 2025-09-14 22:12:16
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.network;
import com.mingliqiye.utils.string.StringUtils;
import lombok.Getter;
import java.io.Serializable;
import java.net.InetSocketAddress;
/**
* IP和端口聚集类用于封装网络地址与端口信息
* 该类提供了与InetSocketAddress之间的相互转换功能
*
* @author MingLiPro
* @see InetSocketAddress
*/
public class NetworkEndpoint implements Serializable {
@Getter
private final NetworkAddress networkAddress;
@Getter
private final NetworkPort networkPort;
/**
* 构造函数使用指定的网络地址和端口创建NetworkEndpoint实例
*
* @param networkAddress 网络地址对象
* @param networkPort 网络端口对象
* @see NetworkAddress
* @see NetworkPort
*/
private NetworkEndpoint(
NetworkAddress networkAddress,
NetworkPort networkPort
) {
this.networkAddress = networkAddress;
this.networkPort = networkPort;
}
/**
* 根据给定的InetSocketAddress对象创建NetworkEndpoint实例
*
* @param address InetSocketAddress对象
* @return 新建的NetworkEndpoint实例
* @see InetSocketAddress
*/
public static NetworkEndpoint of(InetSocketAddress address) {
return new NetworkEndpoint(
new NetworkAddress(address.getHostString()),
new NetworkPort(address.getPort())
);
}
/**
* 根据主机名或IP字符串和端口号创建NetworkEndpoint实例
*
* @param s 主机名或IP地址字符串
* @param i 端口号
* @return 新建的NetworkEndpoint实例
*/
public static NetworkEndpoint of(String s, Integer i) {
NetworkAddress networkAddress = new NetworkAddress(s);
NetworkPort networkPort = new NetworkPort(i);
return new NetworkEndpoint(networkAddress, networkPort);
}
/**
* 根据"host:port"格式的字符串创建NetworkEndpoint实例
* 例如"127.0.0.1:8080"
*
* @param s "host:port"格式的字符串
* @return 新建的NetworkEndpoint实例
*/
public static NetworkEndpoint of(String s) {
// 查找最后一个冒号的位置以支持IPv6地址中的冒号
int lastColonIndex = s.lastIndexOf(':');
return of(
s.substring(0, lastColonIndex),
Integer.parseInt(s.substring(lastColonIndex + 1))
);
}
/**
* 将当前NetworkEndpoint转换为InetSocketAddress对象
*
* @return 对应的InetSocketAddress对象
* @see InetSocketAddress
*/
public InetSocketAddress toInetSocketAddress() {
return new InetSocketAddress(
networkAddress.toInetAddress(),
networkPort.getPort()
);
}
/**
* 将当前NetworkEndpoint转换为"host:port"格式的字符串
* 例如"127.0.0.1:25563"
*
* @return 格式化后的字符串
*/
public String toHostPortString() {
return StringUtils.format(
"{}:{}",
networkAddress.getIp(),
networkPort.getPort()
);
}
/**
* 返回NetworkEndpoint的详细字符串表示形式
* 格式NetworkEndpoint(IP=...,Port=...,Endpoint=...)
*
* @return 包含详细信息的字符串
*/
public String toString() {
return StringUtils.format(
"NetworkEndpoint(IP={},Port={},Endpoint={})",
networkAddress.getIp(),
networkPort.getPort(),
toHostPortString()
);
}
/**
* 获取主机名或IP地址字符串
*
* @return 主机名或IP地址
*/
public String getHost() {
return networkAddress.getIp();
}
/**
* 获取端口号
*
* @return 端口号
*/
public Integer getPort() {
return networkPort.getPort();
}
}

View File

@ -1,64 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile NetworkPort.java
* LastUpdate 2025-09-14 22:12:16
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.network;
import com.mingliqiye.utils.string.StringUtils;
import lombok.Getter;
import java.io.Serializable;
/**
* 网络端口类
*
* @author MingLiPro
*/
public class NetworkPort implements Serializable {
@Getter
private final int port;
/**
* 构造函数创建一个网络端口对象
*
* @param port 端口号必须在0-65535范围内
*/
public NetworkPort(int port) {
testPort(port);
this.port = port;
}
/**
* 验证端口号是否合法
*
* @param port 待验证的端口号
* @throws NetworkException 当端口号不在合法范围(0-65535)内时抛出异常
*/
public static void testPort(int port) {
// 验证端口号范围是否在0-65535之间
if (!(0 <= port && 65535 >= port)) {
throw new NetworkException(
StringUtils.format("{} 不是正确的端口号", port)
);
}
}
}

View File

@ -1,229 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile OsPath.java
* LastUpdate 2025-09-14 22:12:16
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.path;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.nio.file.*;
import java.util.Iterator;
import java.util.Spliterator;
import java.util.function.Consumer;
public class OsPath implements Path {
private final Path path;
private OsPath(Path path) {
this.path = path;
}
public static OsPath of(String path) {
return of(Paths.get(path));
}
public static OsPath of(Path path) {
return new OsPath(path);
}
public static OsPath of(URI uri) {
return new OsPath(Paths.get(uri));
}
public static OsPath of(File file) {
return new OsPath(file.toPath());
}
public static OsPath getCwd() {
return new OsPath(Paths.get(""));
}
@Override
public @NotNull FileSystem getFileSystem() {
return path.getFileSystem();
}
@Override
public boolean isAbsolute() {
return path.isAbsolute();
}
@Override
public Path getRoot() {
return path.getRoot();
}
@Override
public Path getFileName() {
return path.getFileName();
}
@Override
public Path getParent() {
Path a = path.getParent();
if (a == null) {
a = path.toAbsolutePath().getParent();
}
return a;
}
@Override
public int getNameCount() {
return path.getNameCount();
}
@Override
public @NotNull Path getName(int index) {
return path.getName(index);
}
@Override
public @NotNull Path subpath(int beginIndex, int endIndex) {
return path.subpath(beginIndex, endIndex);
}
@Override
public boolean startsWith(@NotNull Path other) {
return path.startsWith(other);
}
@Override
public boolean startsWith(@NotNull String other) {
return path.startsWith(other);
}
@Override
public boolean endsWith(@NotNull Path other) {
return path.endsWith(other);
}
@Override
public boolean endsWith(@NotNull String other) {
return path.endsWith(other);
}
@Override
public @NotNull Path normalize() {
return path.normalize();
}
@Override
public @NotNull Path resolve(@NotNull Path other) {
return path.resolve(other);
}
@Override
public @NotNull Path resolve(@NotNull String other) {
return path.resolve(other);
}
@Override
public @NotNull Path resolveSibling(@NotNull Path other) {
return path.resolveSibling(other);
}
@Override
public @NotNull Path resolveSibling(@NotNull String other) {
return path.resolveSibling(other);
}
@Override
public @NotNull Path relativize(@NotNull Path other) {
return path.relativize(other);
}
@Override
public @NotNull URI toUri() {
return path.toUri();
}
@Override
public @NotNull Path toAbsolutePath() {
return path.toAbsolutePath();
}
@Override
public @NotNull Path toRealPath(@NotNull LinkOption... options)
throws IOException {
return path.toRealPath(options);
}
@Override
public @NotNull File toFile() {
return path.toFile();
}
@Override
public @NotNull WatchKey register(
@NotNull WatchService watcher,
WatchEvent.@NotNull Kind<?>[] events,
@NotNull WatchEvent.Modifier... modifiers
) throws IOException {
return path.register(watcher, events, modifiers);
}
@Override
public @NotNull WatchKey register(
@NotNull WatchService watcher,
WatchEvent.@NotNull Kind<?>... events
) throws IOException {
return path.register(watcher, events);
}
@Override
public @NotNull Iterator<@NotNull Path> iterator() {
return path.iterator();
}
@Override
public int compareTo(@NotNull Path other) {
return path.compareTo(other);
}
@Override
public boolean equals(Object other) {
return path.equals(other);
}
@Override
public int hashCode() {
return path.hashCode();
}
@Override
public @NotNull String toString() {
return path.toString();
}
@Override
public void forEach(Consumer<? super Path> action) {
path.forEach(action);
}
@Override
public Spliterator<Path> spliterator() {
return path.spliterator();
}
}

View File

@ -1,25 +0,0 @@
package com.mingliqiye.utils.springboot.converters;
import static com.mingliqiye.utils.time.Formatter.STANDARD_DATETIME;
import com.mingliqiye.utils.time.DateTime;
import org.jetbrains.annotations.NotNull;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
/**
* spring boot DateTime到字符串转换器
*
* @author MingliPro
* @see DateTime
*
*
*/
@Component
public class DateTimeToStringConverter implements Converter<DateTime, String> {
@Override
public String convert(@NotNull DateTime source) {
return source.format(STANDARD_DATETIME);
}
}

View File

@ -1,25 +0,0 @@
package com.mingliqiye.utils.springboot.converters;
import static com.mingliqiye.utils.time.Formatter.STANDARD_DATETIME_MILLISECOUND7;
import com.mingliqiye.utils.time.DateTime;
import org.jetbrains.annotations.NotNull;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
/**
* spring boot 字符串到DateTime转换器
*
* @author MingliPro
* @see DateTime
*
*
*/
@Component
public class StringToDateTimeConverter implements Converter<String, DateTime> {
@Override
public DateTime convert(@NotNull String source) {
return DateTime.parse(source, STANDARD_DATETIME_MILLISECOUND7, true);
}
}

View File

@ -1,20 +0,0 @@
package com.mingliqiye.utils.springboot.converters;
import com.mingliqiye.utils.uuid.UUID;
import org.jetbrains.annotations.NotNull;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
/**
* spring boot 字符串到UUID转换器
* @see UUID
* @author MingliPro
*/
@Component
public class StringToUUIDConverter implements Converter<String, UUID> {
@Override
public UUID convert(@NotNull String source) {
return UUID.of(source);
}
}

View File

@ -1,20 +0,0 @@
package com.mingliqiye.utils.springboot.converters;
import com.mingliqiye.utils.uuid.UUID;
import org.jetbrains.annotations.NotNull;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
/**
* spring boot UUID到字符串转换器
* @see UUID
* @author MingliPro
*/
@Component
public class UUIDToStringConverter implements Converter<UUID, String> {
@Override
public String convert(@NotNull UUID source) {
return source.toUUIDString();
}
}

View File

@ -1,279 +0,0 @@
package com.mingliqiye.utils.stream;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.jetbrains.annotations.NotNull;
/**
* 自定义的输入输出流工具类支持线程安全的数据读写操作<br>
* 谁闲着没事干用本地输入输出<br>
* 实现了 AutoCloseableCloseable Flushable 接口便于资源管理
*
* @author MingLiPro
*/
public class InOutSteam implements AutoCloseable, Closeable, Flushable {
private final Lock lock = new ReentrantLock();
List<Byte> bytes;
/**
* 从内部缓冲区中读取最多 len 个字节到指定的字节数组 b
*
* @param b 目标字节数组用于存储读取的数据
* @param off 起始偏移位置
* @param len 最大读取字节数
* @return 实际读取的字节数如果已到达流末尾则返回 -1
* @throws IndexOutOfBoundsException 如果 off len 参数非法
*/
public int read(byte@NotNull [] b, int off, int len) {
if (bytes == null) return -1;
if (bytes.isEmpty()) {
return 0;
}
if (off < 0 || len < 0 || off + len > b.length) {
throw new IndexOutOfBoundsException();
}
try {
lock.lock();
int bytesRead = Math.min(len, bytes.size());
for (int i = 0; i < bytesRead; i++) {
b[off + i] = bytes.get(i);
}
if (bytesRead > 0) {
bytes.subList(0, bytesRead).clear();
}
return bytesRead;
} finally {
lock.unlock();
}
}
/**
* 读取一个字节的数据
*
* @return 下一个字节数据0~255如果已到达流末尾则返回 -1
*/
public int read() {
if (bytes == null) return -1;
try {
lock.lock();
if (bytes.isEmpty()) {
return -1;
}
return bytes.remove(0);
} finally {
lock.unlock();
}
}
/**
* 从内部缓冲区中读取最多 b.length 个字节到指定的字节数组 b
*
* @param b 目标字节数组用于存储读取的数据
* @return 实际读取的字节数如果已到达流末尾则返回 -1
*/
public int read(byte@NotNull [] b) {
if (bytes == null) return -1;
return read(b, 0, b.length);
}
/**
* 跳过并丢弃此输入流中数据的 n 个字节
*
* @param n 要跳过的字节数
* @return 实际跳过的字节数
*/
public long skip(long n) {
if (bytes == null) return -1;
if (bytes.isEmpty()) {
return 0;
}
try {
lock.lock();
if (n <= 0) {
return 0;
}
long bytesToSkip = Math.min(n, bytes.size());
// 移除跳过的字节
if (bytesToSkip > 0) {
bytes.subList(0, (int) bytesToSkip).clear();
}
return bytesToSkip;
} finally {
lock.unlock();
}
}
/**
* 返回此输入流下一个方法调用可以不受阻塞地从此输入流读取或跳过的估计字节数
*
* @return 可以无阻塞读取的字节数
*/
public int available() {
if (bytes == null) return -1;
try {
lock.lock();
return bytes.size();
} finally {
lock.unlock();
}
}
/**
* 获取与当前对象关联的 InputStream 实例
*
* @return InputStream 实例
*/
public InputStream getInputStream() {
if (inputStream == null) {
inputStream = inputStream();
}
return inputStream;
}
private InputStream inputStream;
private OutputStream outputStream;
/**
* 获取与当前对象关联的 OutputStream 实例
*
* @return OutputStream 实例
*/
public OutputStream getOutputStream() {
if (outputStream == null) {
outputStream = outputStream();
}
return outputStream;
}
/**
* 创建并返回一个包装后的 InputStream 实例
*
* @return 新创建的 InputStream 实例
*/
private InputStream inputStream() {
return new InputStreanWrapper(
new InputStream() {
@Override
public int read() {
return InOutSteam.this.read();
}
@Override
public int read(byte@NotNull [] b, int off, int len) {
return InOutSteam.this.read(b, off, len);
}
@Override
public long skip(long n) {
return InOutSteam.this.skip(n);
}
@Override
public int available() {
return InOutSteam.this.available();
}
}
);
}
/**
* 创建并返回一个 OutputStream 实例
*
* @return 新创建的 OutputStream 实例
*/
private OutputStream outputStream() {
return new OutputStream() {
@Override
public void write(int b) {
InOutSteam.this.write(b);
}
@Override
public void write(byte@NotNull [] b, int off, int len) {
InOutSteam.this.write(b, off, len);
}
};
}
/**
* 构造函数初始化内部字节列表
*/
public InOutSteam() {
bytes = new ArrayList<>();
}
/**
* 将指定的字节写入此输出流
*
* @param b 要写入的字节
*/
public void write(int b) {
try {
lock.lock();
bytes.add((byte) b);
} finally {
lock.unlock();
}
}
/**
* 将指定字节数组中的部分数据写入此输出流
*
* @param b 数据源字节数组
* @param off 起始偏移位置
* @param len 写入的字节数
* @throws IndexOutOfBoundsException 如果 off len 参数非法
*/
public void write(byte@NotNull [] b, int off, int len) {
if (off < 0 || len < 0 || off + len > b.length) {
throw new IndexOutOfBoundsException("Invalid offset or length");
}
try {
lock.lock();
for (int i = off; i < off + len; i++) {
bytes.add(b[i]);
}
} finally {
lock.unlock();
}
}
/**
* 将整个字节数组写入此输出流
*
* @param b 要写入的字节数组
*/
public void write(byte@NotNull [] b) {
write(b, 0, b.length);
}
/**
* 刷新此输出流并强制写出所有缓冲的输出字节
* 当前实现为空方法
*/
@Override
public void flush() {}
/**
* 关闭此流并释放与其相关的所有资源
* 清空并置空内部字节列表
*/
@Override
public void close() {
bytes.clear();
bytes = null;
}
}

View File

@ -1,99 +0,0 @@
package com.mingliqiye.utils.stream;
import com.mingliqiye.utils.collection.Lists;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import lombok.val;
/**
* 输入流工具类提供对InputStream的常用操作封装
*/
public class InputStreamUtils {
/**
* 默认缓冲区大小1MB
*/
public static final int DEFAULT_BUFFER_SIZE = 1024 * 1024;
/**
* 将输入流读取到字节数组中<br>
* 请在外部自行关闭输入流对象 避免资源泄露
*
* @param inputStream 输入流对象用于读取数据
* @return 包含输入流所有数据的字节数组
* @throws IOException 当读取输入流或写入输出流时发生IO异常
*/
public static byte[] readToArray(InputStream inputStream)
throws IOException {
// 使用ByteArrayOutputStream来收集输入流中的所有数据
try (val byteArrayOutputStream = new ByteArrayOutputStream()) {
val bytes = new byte[DEFAULT_BUFFER_SIZE];
int length;
// 循环读取输入流数据直到读取完毕
while ((length = inputStream.read(bytes)) != -1) {
byteArrayOutputStream.write(bytes, 0, length);
}
return byteArrayOutputStream.toByteArray();
}
}
/**
* 将输入流读取到Byte列表中<br>
* 请在外部自行关闭输入流对象 避免资源泄露
*
* @param inputStream 输入流对象用于读取数据
* @return 包含输入流所有数据的Byte列表
* @throws IOException 当读取输入流时发生IO异常
*/
public static List<Byte> readToList(InputStream inputStream)
throws IOException {
return Lists.toList(readToArray(inputStream));
}
/**
* 将输入流读取为字符串<br>
* 请在外部自行关闭输入流对象 避免资源泄露
*
* @param inputStream 输入流对象用于读取数据
* @return 输入流对应的字符串内容
* @throws IOException 当读取输入流时发生IO异常
*/
public static String readToString(InputStream inputStream)
throws IOException {
return new String(readToArray(inputStream));
}
/**
* 将输入流的数据传输到输出流中<br>
* 请在外部自行关闭输入流输出流对象 避免资源泄露
*
* @param inputStream 源输入流用于读取数据
* @param outputStream 目标输出流用于写入数据
* @return 传输的总字节数
* @throws IOException 当读取或写入流时发生IO异常
*/
public static long transferTo(
InputStream inputStream,
OutputStream outputStream
) throws IOException {
if (inputStream == null) {
throw new IllegalArgumentException("inputStream can not be null");
}
if (outputStream == null) {
throw new IllegalArgumentException("outputStream can not be null");
}
val bytes = new byte[DEFAULT_BUFFER_SIZE];
int length;
long readAll = 0L;
// 循环读取并写入数据直到输入流读取完毕
while ((length = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, length);
readAll += length;
}
outputStream.flush();
return readAll;
}
}

View File

@ -1,120 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile InputStreanWrapper.java
* LastUpdate 2025-09-14 22:12:16
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.stream;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
public class InputStreanWrapper extends InputStream implements AutoCloseable {
@Getter
private final InputStream inputStream;
public InputStreanWrapper(InputStream inputStream) {
this.inputStream = inputStream;
}
private static InputStreanWrapper of(InputStream inputStream) {
return new InputStreanWrapper(inputStream);
}
@Override
public int available() throws IOException {
return inputStream.available();
}
@Override
public int read() throws IOException {
return inputStream.read();
}
@Override
public int read(byte@NotNull [] b) throws IOException {
return inputStream.read(b);
}
@Override
public int read(byte@NotNull [] b, int off, int len) throws IOException {
return inputStream.read(b, off, len);
}
@Override
public long skip(long n) throws IOException {
return inputStream.skip(n);
}
@Override
public void mark(int readlimit) {
inputStream.mark(readlimit);
}
@Override
public void reset() throws IOException {
inputStream.reset();
}
@Override
public boolean markSupported() {
return inputStream.markSupported();
}
@Override
public void close() {
try {
inputStream.close();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 输入流转换为输出流 <br>
* jdk8 兼容实现 jdk9+ <br>
* 请使用 InputStream.transferTo()
*
* @param outputStream 输出流
* @return 转换的字节数
* @throws IOException IO错误
*/
public long transferToOutputStream(OutputStream outputStream)
throws IOException {
return InputStreamUtils.transferTo(inputStream, outputStream);
}
public byte[] readToArray() throws IOException {
return InputStreamUtils.readToArray(inputStream);
}
public List<Byte> readToList() throws IOException {
return InputStreamUtils.readToList(inputStream);
}
public String readToString() throws IOException {
return InputStreamUtils.readToString(inputStream);
}
}

View File

@ -1,81 +0,0 @@
package com.mingliqiye.utils.stream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
public class OutputStreamWrapper extends OutputStream implements AutoCloseable {
@Getter
private final OutputStream outputStream;
private final ByteArrayOutputStream byteArrayOutputStream =
new ByteArrayOutputStream();
public OutputStreamWrapper(OutputStream outputStream) {
this.outputStream = outputStream;
}
public static OutputStreamWrapper of(OutputStream outputStream) {
return new OutputStreamWrapper(outputStream);
}
@Override
public void write(int b) throws IOException {
byteArrayOutputStream.write(b);
}
@Override
public void write(byte@NotNull [] b) throws IOException {
byteArrayOutputStream.write(b);
}
public void write(List<Byte> b) throws IOException {
write(b, 0, b.size());
}
@Override
public void write(byte@NotNull [] b, int off, int len) throws IOException {
byteArrayOutputStream.write(b, off, len);
}
public void write(List<Byte> b, int off, int len) throws IOException {
byte[] bytes = new byte[b.size()];
for (int i = 0; i < b.size(); i++) {
bytes[i] = b.get(i);
}
byteArrayOutputStream.write(bytes, off, len);
}
@Override
public void flush() throws IOException {
outputStream.write(byteArrayOutputStream.toByteArray());
byteArrayOutputStream.reset();
}
public int getBufferCachedSize() {
return byteArrayOutputStream.size();
}
public byte[] getBufferCachedBytes() {
return byteArrayOutputStream.toByteArray();
}
@Override
public void close() {
try {
outputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public long transferFromOutputStream(InputStream inputStream)
throws IOException {
return InputStreamUtils.transferTo(inputStream, outputStream);
}
}

View File

@ -15,19 +15,20 @@
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile Players.java
* LastUpdate 2025-09-09 08:37:33
* CurrentFile StreamEmptyException.java
* LastUpdate 2025-09-20 13:24:07
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.minecraft.slp;
package com.mingliqiye.utils.stream;
import lombok.Data;
public class StreamEmptyException extends java.lang.RuntimeException {
@Data
public class Players {
public StreamEmptyException(String message) {
super(message);
}
private int max;
private int online;
private PlayerSample[] sample;
public StreamEmptyException(String message, Throwable cause) {
super(message, cause);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +0,0 @@
package com.mingliqiye.utils.stream.interfaces;
public interface GetIdable<T> extends Getable<T> {
T getId();
default T get() {
return getId();
}
}

View File

@ -1,9 +0,0 @@
package com.mingliqiye.utils.stream.interfaces;
public interface GetKeyable<T> {
T getKey();
default T get() {
return getKey();
}
}

View File

@ -1,9 +0,0 @@
package com.mingliqiye.utils.stream.interfaces;
public interface GetNameable<T> extends Getable<T> {
T getName();
default T get() {
return getName();
}
}

View File

@ -1,5 +0,0 @@
package com.mingliqiye.utils.stream.interfaces;
public interface Getable<T> {
T get();
}

View File

@ -1,561 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile DateTime.java
* LastUpdate 2025-09-14 22:12:16
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.time;
import com.mingliqiye.utils.jna.WinKernel32Api;
import com.mingliqiye.utils.jna.WinKernel32ApiFactory;
import com.mingliqiye.utils.system.SystemUtils;
import lombok.Getter;
import lombok.Setter;
import lombok.val;
import lombok.var;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import java.io.Serializable;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import static com.mingliqiye.utils.jna.WinKernel32ApiFactory.FILETIME_EPOCH_OFFSET;
import static com.mingliqiye.utils.jna.WinKernel32ApiFactory.NANOS_PER_100NS;
import static com.mingliqiye.utils.logger.Loggers.getMingLiLoggerFactory;
/**
* 时间类用于处理日期时间的转换格式化等操作
* 提供了多种静态方法来创建 DateTime 实例并支持与 DateLocalDateTime 等类型的互转
*<br>
* windows java 1.8 及以下 使用windows Api 获取高精度时间
*
* @author MingLiPro
* @see java.time
* @see LocalDateTime
* @see ChronoUnit
* @see Date
* @see DateTimeFormatter
* @see ZoneId
* @see Instant
*/
@Setter
public final class DateTime implements Serializable {
private static final WinKernel32Api WIN_KERNEL_32_API;
static {
if (
SystemUtils.getJavaVersionAsInteger() == 8 &&
SystemUtils.isWindows()
) {
final Logger log = getMingLiLoggerFactory().getLogger(
"mingli-utils DateTime"
);
val a = WinKernel32ApiFactory.getWinKernel32Apis();
if (a.size() > 1) {
log.warn(
"Multiple Size:{} WinKernel32Api implementations found.",
a.size()
);
a.forEach(api ->
log.warn(
"Found WinKernel32Api: {}",
api.getClass().getName()
)
);
}
if (a.isEmpty()) {
WIN_KERNEL_32_API = null;
log.warn(
"No WinKernel32Api implementation found. Use Jdk1.8 LocalDateTime"
);
} else {
WIN_KERNEL_32_API = a.get(a.size() - 1);
log.info(
"Found and Use WinKernel32Api: {}",
WIN_KERNEL_32_API.getClass().getName()
);
}
} else {
WIN_KERNEL_32_API = null;
}
}
@Getter
private ZoneId zoneId = ZoneId.systemDefault();
@Getter
private LocalDateTime localDateTime;
/**
* 私有构造函数使用指定的 LocalDateTime 初始化实例
*
* @param time LocalDateTime 对象
*/
private DateTime(LocalDateTime time) {
setLocalDateTime(time);
}
/**
* 私有构造函数使用当前系统时间初始化实例
*/
private DateTime() {
setLocalDateTime(LocalDateTime.now());
}
/**
* 获取当前时间的 DateTime 实例
* 如果运行在 Java 1.8 环境下则通过 WinKernel32 获取高精度时间
*
* @return 返回当前时间的 DateTime 实例
*/
public static DateTime now() {
if (WIN_KERNEL_32_API != null) {
return DateTime.of(
WIN_KERNEL_32_API.getTime()
.atZone(ZoneId.systemDefault())
.toLocalDateTime()
);
}
return new DateTime();
}
/**
* Date 对象转换为 DateTime 实例
*
* @param zoneId 时区信息
* @param date Date 对象
* @return 返回对应的 DateTime 实例
*/
public static DateTime of(Date date, ZoneId zoneId) {
return new DateTime(date.toInstant().atZone(zoneId).toLocalDateTime());
}
/**
* Date 对象转换为 DateTime 实例使用系统默认时区
*
* @param date Date 对象
* @return 返回对应的 DateTime 实例
*/
public static DateTime of(Date date) {
return new DateTime(
date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()
);
}
/**
* 根据 LocalDateTime 创建 DateTime 实例
*
* @param localDateTime LocalDateTime 对象
* @return 返回对应的 DateTime 实例
*/
public static DateTime of(LocalDateTime localDateTime) {
return new DateTime(localDateTime);
}
/**
* 解析时间字符串并生成 DateTime 实例
*
* @param timestr 时间字符串
* @param formatter 格式化模板
* @param fillZero 是否补零到模板长度
* @return 返回解析后的 DateTime 实例
*/
public static DateTime parse(
String timestr,
String formatter,
boolean fillZero
) {
return new DateTime(
LocalDateTime.parse(
fillZero ? getFillZeroByLen(timestr, formatter) : timestr,
DateTimeFormatter.ofPattern(formatter)
)
);
}
/**
* 使用 Formatter 枚举解析时间字符串并生成 DateTime 实例
*
* @param timestr 时间字符串
* @param formatter 格式化模板枚举
* @param fillZero 是否补零到模板长度
* @return 返回解析后的 DateTime 实例
*/
public static DateTime parse(
String timestr,
Formatter formatter,
boolean fillZero
) {
return parse(timestr, formatter.getValue(), fillZero);
}
/**
* 使用 Formatter 枚举解析时间字符串并生成 DateTime 实例默认不补零
*
* @param timestr 时间字符串
* @param formatter 格式化模板枚举
* @return 返回解析后的 DateTime 实例
*/
public static DateTime parse(String timestr, Formatter formatter) {
return parse(timestr, formatter.getValue());
}
/**
* 解析时间字符串并生成 DateTime 实例默认不补零
*
* @param timestr 时间字符串
* @param formatter 格式化模板
* @return 返回解析后的 DateTime 实例
*/
public static DateTime parse(String timestr, String formatter) {
return parse(timestr, formatter, false);
}
/**
* 补零处理时间字符串以匹配格式化模板长度
*
* @param dstr 原始时间字符串
* @param formats 格式化模板
* @return 补零后的时间字符串
*/
private static String getFillZeroByLen(String dstr, String formats) {
if (dstr.length() == formats.length()) {
return dstr;
}
if (formats.length() > dstr.length()) {
if (dstr.length() == 19) {
dstr += ".";
}
var sb = new StringBuilder(dstr);
for (int i = 0; i < formats.length() - dstr.length(); i++) {
sb.append("0");
}
return sb.toString();
}
throw new IllegalArgumentException(
String.format(
"Text: '%s' len %s < %s %s",
dstr,
dstr.length(),
formats,
formats.length()
)
);
}
/**
* 根据年日创建 DateTime 实例
*
* @param year 年份
* @param month 月份 (1-12)
* @param day 日期 (1-31)
* @return 返回指定日期的 DateTime 实例时间部分为 00:00:00
*/
public static DateTime of(int year, int month, int day) {
return new DateTime(LocalDateTime.of(year, month, day, 0, 0));
}
/**
* 根据年分创建 DateTime 实例
*
* @param year 年份
* @param month 月份 (1-12)
* @param day 日期 (1-31)
* @param hour 小时 (0-23)
* @param minute 分钟 (0-59)
* @return 返回指定日期时间的 DateTime 实例秒部分为 00
*/
public static DateTime of(
int year,
int month,
int day,
int hour,
int minute
) {
return new DateTime(LocalDateTime.of(year, month, day, hour, minute));
}
/**
* FILETIME 转换为 LocalDateTime
*
* @param fileTime FILETIME 时间戳100纳秒单位自1601年1月1日起
* @return 转换后的 LocalDateTime 实例
*/
public static LocalDateTime fileTimeToLocalDateTime(long fileTime) {
// 1. FILETIME (100ns间隔 since 1601) 转换为 Unix 时间戳 (纳秒 since 1970)
long unixNanos = (fileTime + FILETIME_EPOCH_OFFSET) * NANOS_PER_100NS;
// 2. 从纳秒时间戳创建 Instant
Instant instant = Instant.ofEpochSecond(
unixNanos / 1_000_000_000L,
unixNanos % 1_000_000_000L
);
// 3. 转换为系统默认时区的 LocalDateTime
return instant.atZone(ZoneId.systemDefault()).toLocalDateTime();
}
/**
* 根据年秒创建 DateTime 实例
*
* @param year 年份
* @param month 月份 (1-12)
* @param day 日期 (1-31)
* @param hour 小时 (0-23)
* @param minute 分钟 (0-59)
* @param second (0-59)
* @return 返回指定日期时间的 DateTime 实例
*/
public static DateTime of(
int year,
int month,
int day,
int hour,
int minute,
int second
) {
return new DateTime(
LocalDateTime.of(year, month, day, hour, minute, second)
);
}
/**
* 根据年纳秒创建 DateTime 实例
*
* @param year 年份
* @param month 月份 (1-12)
* @param day 日期 (1-31)
* @param hour 小时 (0-23)
* @param minute 分钟 (0-59)
* @param second (0-59)
* @param nano 纳秒 (0-999,999,999)
* @return 返回指定日期时间的 DateTime 实例
*/
public static DateTime of(
int year,
int month,
int day,
int hour,
int minute,
int second,
int nano
) {
return new DateTime(
LocalDateTime.of(year, month, day, hour, minute, second, nano)
);
}
/**
* 根据毫秒时间戳创建 DateTime 实例
*
* @param epochMilli 毫秒时间戳
* @return 返回对应时间的 DateTime 实例
*/
public static DateTime of(long epochMilli) {
return new DateTime(
Instant.ofEpochMilli(epochMilli)
.atZone(ZoneId.systemDefault())
.toLocalDateTime()
);
}
/**
* 根据毫秒时间戳和时区创建 DateTime 实例
*
* @param epochMilli 毫秒时间戳
* @param zoneId 时区信息
* @return 返回对应时间的 DateTime 实例
*/
public static DateTime of(long epochMilli, ZoneId zoneId) {
return new DateTime(
Instant.ofEpochMilli(epochMilli).atZone(zoneId).toLocalDateTime()
);
}
/**
* 将当前 DateTime 转换为 Date 对象
*
* @return 返回对应的 Date 对象
*/
public Date toDate() {
return Date.from(localDateTime.atZone(getZoneId()).toInstant());
}
/**
* 获取当前 DateTime 中的 LocalDateTime 实例
*
* @return 返回 LocalDateTime 对象
*/
public LocalDateTime toLocalDateTime() {
return localDateTime;
}
/**
* 在当前时间基础上增加指定的时间偏移量
*
* @param dateTimeOffset 时间偏移对象
* @return 返回修改后的 DateTime 实例
*/
public DateTime add(DateTimeOffset dateTimeOffset) {
return new DateTime(
this.localDateTime.plus(
dateTimeOffset.getOffset(),
dateTimeOffset.getOffsetType()
)
);
}
/**
* 在当前时间基础上减少指定的时间偏移量
*
* @param dateTimeOffset 时间偏移对象
* @return 返回修改后的 DateTime 实例
*/
public DateTime sub(DateTimeOffset dateTimeOffset) {
return new DateTime(
this.localDateTime.plus(
-dateTimeOffset.getOffset(),
dateTimeOffset.getOffsetType()
)
);
}
/**
* 使用指定格式化模板将当前时间格式化为字符串
*
* @param formatter 格式化模板
* @return 返回格式化后的时间字符串
*/
public String format(String formatter) {
return format(formatter, false);
}
/**
* 使用 Formatter 枚举将当前时间格式化为字符串
*
* @param formatter 格式化模板枚举
* @return 返回格式化后的时间字符串
*/
public String format(Formatter formatter) {
return format(formatter.getValue());
}
/**
* 使用指定格式化模板将当前时间格式化为字符串并可选择是否去除末尾多余的零
*
* @param formatter 格式化模板
* @param repcZero 是否去除末尾多余的零
* @return 返回格式化后的时间字符串
*/
public String format(String formatter, boolean repcZero) {
var formatted = DateTimeFormatter.ofPattern(formatter).format(
toLocalDateTime()
);
if (repcZero) {
// 处理小数点后多余的0
formatted = formatted.replaceAll("(\\.\\d*?)0+\\b", "$1");
formatted = formatted.replaceAll("\\.$", "");
}
return formatted;
}
/**
* 使用 Formatter 枚举将当前时间格式化为字符串并可选择是否去除末尾多余的零
*
* @param formatter 格式化模板枚举
* @param repcZero 是否去除末尾多余的零
* @return 返回格式化后的时间字符串
*/
public String format(Formatter formatter, boolean repcZero) {
return format(formatter.getValue(), repcZero);
}
/**
* 返回当前时间的标准字符串表示形式
*
* @return 返回标准格式的时间字符串
*/
@Override
public String toString() {
return String.format(
"DateTime(%s)",
format(Formatter.STANDARD_DATETIME_MILLISECOUND7, true)
);
}
/**
* 比较当前DateTime对象与指定对象是否相等
*
* @param obj 要比较的对象
* @return 如果对象相等则返回true否则返回false
*/
@Override
public boolean equals(Object obj) {
// 检查对象类型是否为DateTime
if (obj instanceof DateTime) {
// 比较两个DateTime对象转换为LocalDateTime后的值
return toLocalDateTime().equals(((DateTime) obj).toLocalDateTime());
}
return false;
}
/**
* 将当前 DateTime 转换为 Instant 对象
*
* @return 返回 Instant 对象
*/
@NotNull
public Instant toInstant() {
return localDateTime.atZone(zoneId).toInstant();
}
/**
* 判断当前时间是否在指定时间之后
*
* @param dateTime 指定时间
* @return 如果当前时间在指定时间之后则返回 true否则返回 false
*/
public boolean isAfter(DateTime dateTime) {
if (dateTime == null) {
return false;
}
return toInstant().isAfter(dateTime.toInstant());
}
/**
* 判断当前时间是否在指定时间之前
*
* @param dateTime 指定时间
* @return 如果当前时间在指定时间之前则返回 true否则返回 false
*/
public boolean isBefore(DateTime dateTime) {
if (dateTime == null) {
return false;
}
return toInstant().isBefore(dateTime.toInstant());
}
}

View File

@ -1,65 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile DateTimeOffset.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.time;
import java.time.temporal.ChronoUnit;
import lombok.Getter;
/**
* 时间位移
*
* @author MingLiPro
*/
@Getter
public class DateTimeOffset {
private final ChronoUnit offsetType;
private final Long offset;
private DateTimeOffset(ChronoUnit offsetType, Long offset) {
this.offsetType = offsetType;
this.offset = offset;
}
/**
* 创建一个新的DateTimeOffset实例
*
* @param offsetType 偏移量的单位类型指定偏移量的计算单位
* @param offset 偏移量的数值可以为正数负数或零
* @return 返回一个新的DateTimeOffset对象包含指定的偏移量信息
*/
public static DateTimeOffset of(ChronoUnit offsetType, Long offset) {
return new DateTimeOffset(offsetType, offset);
}
/**
* 创建一个 DateTimeOffset 实例
*
* @param offset 偏移量数值
* @param offsetType 偏移量的时间单位类型
* @return 返回一个新的 DateTimeOffset 实例
*/
public static DateTimeOffset of(Long offset, ChronoUnit offsetType) {
return new DateTimeOffset(offsetType, offset);
}
}

View File

@ -1,65 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile DateTimeUnit.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.time;
/**
* 时间单位常量定义
*
* @author MingLiPro
*/
public interface DateTimeUnit {
// 时间单位常量
String YEAR = "year";
String MONTH = "month";
String WEEK = "week";
String DAY = "day";
String HOUR = "hour";
String MINUTE = "minute";
String SECOND = "second";
String MILLISECOND = "millisecond";
String MICROSECOND = "microsecond";
String NANOSECOND = "nanosecond";
// 时间单位缩写
String YEAR_ABBR = "y";
String MONTH_ABBR = "M";
String WEEK_ABBR = "w";
String DAY_ABBR = "d";
String HOUR_ABBR = "h";
String MINUTE_ABBR = "m";
String SECOND_ABBR = "s";
String MILLISECOND_ABBR = "ms";
String MICROSECOND_ABBR = "μs";
String NANOSECOND_ABBR = "ns";
// 时间单位转换系数毫秒为基准
long MILLIS_PER_SECOND = 1000L;
long MILLIS_PER_MINUTE = 60 * MILLIS_PER_SECOND;
long MILLIS_PER_HOUR = 60 * MILLIS_PER_MINUTE;
long MILLIS_PER_DAY = 24 * MILLIS_PER_HOUR;
long MILLIS_PER_WEEK = 7 * MILLIS_PER_DAY;
// 月份和年的毫秒数仅为近似值
long MILLIS_PER_MONTH = 30 * MILLIS_PER_DAY; // 近似值
long MILLIS_PER_YEAR = 365 * MILLIS_PER_DAY; // 近似值
}

View File

@ -1,115 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile Formatter.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.time;
import lombok.Getter;
/**
* 时间格式化枚举类
* <p>
* 定义了常用的时间格式化模式用于日期时间的解析和格式化操作
* 每个枚举常量包含对应的格式化字符串和字符串长度
* </p>
*/
public enum Formatter {
/**
* 标准日期时间格式yyyy-MM-dd HH:mm:ss
*/
STANDARD_DATETIME("yyyy-MM-dd HH:mm:ss"),
/**
* 标准日期时间格式(7位毫秒)yyyy-MM-dd HH:mm:ss.SSSSSSS
*/
STANDARD_DATETIME_MILLISECOUND7("yyyy-MM-dd HH:mm:ss.SSSSSSS"),
/**
* 标准日期时间格式(6位毫秒)yyyy-MM-dd HH:mm:ss.SSSSSS
*/
STANDARD_DATETIME_MILLISECOUND6("yyyy-MM-dd HH:mm:ss.SSSSSS"),
/**
* 标准日期时间格式(5位毫秒)yyyy-MM-dd HH:mm:ss.SSSSS
*/
STANDARD_DATETIME_MILLISECOUND5("yyyy-MM-dd HH:mm:ss.SSSSS"),
/**
* 标准日期时间格式(4位毫秒)yyyy-MM-dd HH:mm:ss.SSSS
*/
STANDARD_DATETIME_MILLISECOUND4("yyyy-MM-dd HH:mm:ss.SSSS"),
/**
* 标准日期时间格式(3位毫秒)yyyy-MM-dd HH:mm:ss.SSS
*/
STANDARD_DATETIME_MILLISECOUND3("yyyy-MM-dd HH:mm:ss.SSS"),
/**
* 标准日期时间格式(2位毫秒)yyyy-MM-dd HH:mm:ss.SS
*/
STANDARD_DATETIME_MILLISECOUND2("yyyy-MM-dd HH:mm:ss.SS"),
/**
* 标准日期时间格式(1位毫秒)yyyy-MM-dd HH:mm:ss.S
*/
STANDARD_DATETIME_MILLISECOUND1("yyyy-MM-dd HH:mm:ss.S"),
/**
* 标准ISO格式yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
*/
STANDARD_ISO("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"),
/**
* 标准日期时间秒格式yyyy-MM-dd HH:mm:ss
*/
STANDARD_DATETIME_SECOUND("yyyy-MM-dd HH:mm:ss"),
/**
* 标准日期格式yyyy-MM-dd
*/
STANDARD_DATE("yyyy-MM-dd"),
/**
* ISO8601格式yyyy-MM-dd'T'HH:mm:ss.SSS'000'
*/
ISO8601("yyyy-MM-dd'T'HH:mm:ss.SSS'000'"),
/**
* 紧凑型日期时间格式yyyyMMddHHmmss
*/
COMPACT_DATETIME("yyyyMMddHHmmss");
@Getter
private final String value;
@Getter
private final int len;
/**
* 构造函数
*
* @param value 格式化模式字符串
*/
Formatter(String value) {
this.value = value;
this.len = value.length();
}
}

View File

@ -1,128 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile DateTimeTypeHandler.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.time.typehandlers;
import com.mingliqiye.utils.time.DateTime;
import com.mingliqiye.utils.time.Formatter;
import java.sql.*;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
/**
* DateTime类型处理器类
* 用于在MyBatis中处理DateTime类型与数据库VARCHAR类型之间的转换
*/
@MappedTypes({ DateTime.class })
@MappedJdbcTypes(JdbcType.VARCHAR)
public class DateTimeTypeHandler extends BaseTypeHandler<DateTime> {
/**
* 设置非空参数值
* 将DateTime对象转换为Timestamp并设置到PreparedStatement中
*
* @param ps PreparedStatement对象
* @param i 参数索引位置
* @param parameter DateTime参数值
* @param jdbcType JDBC类型
* @throws SQLException SQL异常
*/
@Override
public void setNonNullParameter(
PreparedStatement ps,
int i,
DateTime parameter,
JdbcType jdbcType
) throws SQLException {
ps.setTimestamp(i, Timestamp.valueOf(parameter.getLocalDateTime()));
}
/**
* 从ResultSet中获取可为空的结果值
* 根据列名获取字符串值并解析为DateTime对象
*
* @param rs ResultSet对象
* @param columnName 列名
* @return DateTime对象如果值为null则返回null
* @throws SQLException SQL异常
*/
@Override
public DateTime getNullableResult(ResultSet rs, String columnName)
throws SQLException {
return parse(rs.getString(columnName));
}
/**
* 从ResultSet中获取可为空的结果值
* 根据列索引获取字符串值并解析为DateTime对象
*
* @param rs ResultSet对象
* @param columnIndex 列索引
* @return DateTime对象如果值为null则返回null
* @throws SQLException SQL异常
*/
@Override
public DateTime getNullableResult(ResultSet rs, int columnIndex)
throws SQLException {
return parse(rs.getString(columnIndex));
}
/**
* 从CallableStatement中获取可为空的结果值
* 根据列索引获取字符串值并解析为DateTime对象
*
* @param cs CallableStatement对象
* @param columnIndex 列索引
* @return DateTime对象如果值为null则返回null
* @throws SQLException SQL异常
*/
@Override
public DateTime getNullableResult(CallableStatement cs, int columnIndex)
throws SQLException {
return parse(cs.getString(columnIndex));
}
/**
* 解析字符串为DateTime对象
*
* @param s 待解析的字符串
* @return DateTime对象如果字符串为null则返回null
*/
public DateTime parse(String s) {
if (s == null) {
return null;
}
return DateTime.parse(s, Formatter.STANDARD_DATETIME_MILLISECOUND7);
}
/**
* 格式化DateTime对象为字符串
*
* @param t DateTime对象
* @return 格式化后的字符串
*/
public String format(DateTime t) {
return t.format(Formatter.STANDARD_DATETIME_MILLISECOUND7);
}
}

View File

@ -16,7 +16,7 @@
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile AesUtils.kt
* LastUpdate 2025-09-14 18:43:04
* LastUpdate 2025-09-19 21:35:53
* UpdateUser MingLiPro
*/
@ -25,8 +25,7 @@
package com.mingliqiye.utils.aes
import com.mingliqiye.utils.base64.decode
import com.mingliqiye.utils.base64.encode
import com.mingliqiye.utils.base.BASE64
import java.nio.charset.StandardCharsets
import java.security.GeneralSecurityException
import java.security.MessageDigest
@ -72,8 +71,8 @@ fun encrypt(sSrc: String, sKey: String?): String? {
val encrypted = cipher.doFinal(
sSrc.toByteArray(StandardCharsets.UTF_8)
)
return encode(
"${encode(iv)}:${encode(encrypted)}".toByteArray()
return BASE64.encode(
"${BASE64.encode(iv)}:${BASE64.encode(encrypted)}".toByteArray()
)
}
@ -86,13 +85,13 @@ fun encrypt(sSrc: String, sKey: String?): String? {
fun decrypt(sSrc: String, sKey: String): String? {
try {
// 分割IV和加密数据
val sSrcs = String(decode(sSrc))
val sSrcs = String(BASE64.decode(sSrc))
val parts: Array<String?> = sSrcs.split(":".toRegex(), limit = 2).toTypedArray()
if (parts.size != 2) {
return null
}
val iv = decode(parts[0]!!)
val encryptedData = decode(parts[1]!!)
val iv = BASE64.decode(parts[0]!!)
val encryptedData = BASE64.decode(parts[1]!!)
if (iv.size != GCM_IV_LENGTH) {
return null
}
@ -122,3 +121,4 @@ private fun createSecretKey(sKey: String): SecretKeySpec {
val digest = md.digest(key)
return SecretKeySpec(digest, ALGORITHM)
}

View File

@ -0,0 +1,54 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile Base16.kt
* LastUpdate 2025-09-17 10:56:07
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.base
/**
* Base16编解码器实现类
* 提供字节数组与十六进制字符串之间的相互转换功能
*/
class Base16 : BaseCodec {
/**
* 将字节数组编码为十六进制字符串
* @param bytes 待编码的字节数组
* @return 编码后的十六进制字符串每个字节对应两位十六进制字符
*/
override fun encode(bytes: ByteArray): String {
// 将每个字节转换为两位十六进制字符串并拼接
return bytes.joinToString("") {
it.toInt().and(0xff).toString(16).padStart(2, '0')
}
}
/**
* 将十六进制字符串解码为字节数组
* @param string 待解码的十六进制字符串
* @return 解码后的字节数组
*/
override fun decode(string: String): ByteArray {
// 按每两个字符分组,转换为字节
return string.chunked(2).map {
it.toInt(16).toByte()
}.toByteArray()
}
}

View File

@ -0,0 +1,313 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile Base256.kt
* LastUpdate 2025-09-20 14:01:29
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.base
/**
* Base256 字符集 256
*
* 256个字符 要字符集的下面复制
*
* !#$%&()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~§±×÷
*
*/
class Base256 : BaseCodec {
companion object {
val code = arrayOf(
'!',
'#',
'$',
'%',
'&',
'(',
')',
'*',
'+',
',',
'-',
'.',
'/',
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
':',
';',
'<',
'=',
'>',
'?',
'@',
'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
'K',
'L',
'M',
'N',
'O',
'P',
'Q',
'R',
'S',
'T',
'U',
'V',
'W',
'X',
'Y',
'Z',
'[',
']',
'^',
'_',
'`',
'a',
'b',
'c',
'd',
'e',
'f',
'g',
'h',
'i',
'j',
'k',
'l',
'm',
'n',
'o',
'p',
'q',
'r',
's',
't',
'u',
'v',
'w',
'x',
'y',
'z',
'{',
'|',
'}',
'~',
'§',
'±',
'×',
'÷',
'←',
'↑',
'→',
'↓',
'⇒',
'⇔',
'∀',
'∃',
'∅',
'∆',
'∇',
'∈',
'∉',
'∋',
'∌',
'∏',
'∑',
'',
'∓',
'',
'',
'∘',
'∙',
'√',
'∛',
'∜',
'∞',
'∟',
'∠',
'',
'∥',
'∧',
'',
'∩',
'',
'∫',
'∬',
'∭',
'∮',
'∯',
'∰',
'∱',
'∲',
'∳',
'∴',
'∵',
'',
'∷',
'≈',
'≠',
'≡',
'≤',
'≥',
'≦',
'≧',
'≪',
'≫',
'≺',
'≻',
'⊂',
'⊃',
'⊆',
'⊇',
'⊈',
'⊉',
'⊊',
'⊋',
'⊕',
'⊖',
'⊗',
'⊘',
'⊙',
'⊚',
'⊛',
'⊜',
'⊝',
'⊞',
'⊟',
'⊠',
'⊡',
'⊢',
'⊣',
'',
'⊥',
'⊦',
'⊧',
'⊨',
'⊩',
'⊪',
'⊫',
'⊬',
'⊭',
'⊮',
'⊯',
'⋀',
'',
'⋂',
'',
'⋄',
'⋅',
'⋆',
'⋇',
'⋈',
'⋉',
'⋊',
'⋋',
'⋌',
'⋍',
'⋎',
'⋏',
'⋐',
'⋑',
'⋒',
'⋓',
'⋔',
'⋕',
'⋖',
'⋗',
'⋘',
'⋙',
'⋚',
'⋛',
'⋜',
'⋝',
'⋞',
'⋟',
'⋠',
'⋡',
'⋢',
'⋣',
'⋤',
'⋥',
'⋦',
'⋧',
'⋨',
'⋩',
'▁',
'▂',
'▃',
'▄',
'▅',
'▆',
'▇',
'█',
'▉',
'▊',
'▋',
'▌',
'▍',
'▎',
'▏',
'▐',
'░',
'▒',
'▓',
'▔',
'▕',
'▖',
'▗',
'▘',
'▙'
)
val codeMap = code.mapIndexed { index, c -> c to index }.toMap()
}
override fun encode(bytes: ByteArray): String {
val result = CharArray(bytes.size)
for (i in bytes.indices) {
val unsignedByte = bytes[i].toInt() and 0xFF
result[i] = code[unsignedByte]
}
return String(result)
}
override fun decode(string: String): ByteArray {
val result = ByteArray(string.length)
for (i in string.indices) {
result[i] = codeMap[string[i]]!!.toByte()
}
return result
}
}

View File

@ -0,0 +1,62 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile Base64.kt
* LastUpdate 2025-09-17 10:56:32
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.base
/*
* Base64编解码工具类
* 提供Base64编码和解码功能的实现
*/
class Base64 : BaseCodec {
/*
* Base64编码器实例
* 用于执行字节数组到Base64字符串的编码操作
*/
val BASE_64_ENCODER: java.util.Base64.Encoder = java.util.Base64.getEncoder()
/*
* Base64解码器实例
* 用于执行Base64字符串到字节数组的解码操作
*/
val BASE_64_DECODER: java.util.Base64.Decoder = java.util.Base64.getDecoder()
/*
* 将字节数组编码为Base64字符串
*
* @param bytes 待编码的字节数组
* @return 编码后的Base64字符串
*/
override fun encode(bytes: ByteArray): String {
return BASE_64_ENCODER.encodeToString(bytes)
}
/*
* 将Base64字符串解码为字节数组
*
* @param string 待解码的Base64字符串
* @return 解码后的字节数组
*/
override fun decode(string: String): ByteArray {
return BASE_64_DECODER.decode(string)
}
}

View File

@ -0,0 +1,404 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile Base91.kt
* LastUpdate 2025-09-19 20:08:46
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.base
/**
* Base91 编解码工具类用于将字节数组编码为 Base91 字符串或将 Base91 字符串解码为原始字节数组
*
* Base91 是一种高效的二进制到文本的编码方式相较于 Base64它使用更少的字符来表示相同的数据
*/
class Base91 : BaseCodec {
companion object {
/**
* Base91 编码表 91 个可打印 ASCII 字符
*/
val ENCODING_TABLE: CharArray = charArrayOf(
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '!', '#', '$',
'%', '&', '(', ')', '*', '+', ',', '.', '/', ':', ';', '<', '=',
'>', '?', '@', '[', ']', '^', '_', '`', '{', '|', '}', '~', '"'
)
/**
* Base91 解码表大小为 256用于快速查找字符对应的数值
* 初始化时将所有元素设为 -1表示无效字符然后根据 ENCODING_TABLE 填充有效字符的索引
*/
val DECODING_TABLE: Array<Int> = arrayOf(
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
62,
90,
63,
64,
65,
66,
-1,
67,
68,
69,
70,
71,
-1,
72,
73,
52,
53,
54,
55,
56,
57,
58,
59,
60,
61,
74,
75,
76,
77,
78,
79,
80,
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
81,
-1,
82,
83,
84,
85,
26,
27,
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41,
42,
43,
44,
45,
46,
47,
48,
49,
50,
51,
86,
87,
88,
89,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1
)
}
/**
* 将字节数组编码为 Base91 字符串
*
* @param bytes 待编码的字节数组
* @return 编码后的 Base91 字符串
*/
override fun encode(bytes: ByteArray): String {
if (bytes.isEmpty()) return ""
val sb = StringBuilder()
var ebq = 0 // 编码缓冲区,用于暂存待处理的位数据
var en = 0 // 当前缓冲区中的有效位数
for (b in bytes) {
// 将当前字节加入缓冲区
ebq = ebq or ((b.toInt() and 0xFF) shl en)
en += 8
// 每当缓冲区中有超过 13 位的数据时,尝试进行编码
if (en > 13) {
var ev = ebq and 0x1FFF // 取出低 13 位作为候选值
if (ev > 88) {
// 如果候选值大于 88则使用 13 位编码
ebq = ebq shr 13
en -= 13
} else {
// 否则使用 14 位编码
ev = ebq and 0x3FFF
ebq = ebq shr 14
en -= 14
}
// 将两个字符追加到结果中
sb.append(ENCODING_TABLE[ev % 91])
sb.append(ENCODING_TABLE[ev / 91])
}
}
// 处理剩余未编码的数据
if (en > 0) {
sb.append(ENCODING_TABLE[ebq % 91])
if (en > 7 || ebq > 90) {
sb.append(ENCODING_TABLE[ebq / 91])
}
}
return sb.toString()
}
/**
* Base91 字符串解码为原始字节数组
*
* @param string 待解码的 Base91 字符串
* @return 解码后的字节数组
*/
override fun decode(string: String): ByteArray {
if (string.isEmpty()) return ByteArray(0)
var dbq = 0 // 解码缓冲区,用于暂存待处理的位数据
var dn = 0 // 当前缓冲区中的有效位数
var dv = -1 // 当前读取到的 Base91 值
val buffer = ByteArray(string.length * 13 / 8) // 预分配输出缓冲区
var index = 0 // 输出缓冲区写入位置
for (c in string.toCharArray()) {
// 忽略不在编码表中的字符
if (DECODING_TABLE[c.code] == -1) continue
if (dv == -1) {
// 第一次读取字符,保存为 dv
dv = DECODING_TABLE[c.code]
} else {
// 第二次读取字符,组合成完整的 Base91 值
dv += DECODING_TABLE[c.code] * 91
dbq = dbq or (dv shl dn)
// 根据值大小判断是 13 位还是 14 位编码
dn += if ((dv and 0x1FFF) > 88) 13 else 14
// 将缓冲区中完整的字节写入输出数组
do {
buffer[index++] = (dbq and 0xFF).toByte()
dbq = dbq shr 8
dn -= 8
} while (dn > 7)
dv = -1 // 重置 dv准备下一轮读取
}
}
// 处理最后剩余的一个字符(如果存在)
if (dv != -1) {
buffer[index++] = ((dbq or (dv shl dn)) and 0xFF).toByte()
}
// 返回实际使用的部分
return buffer.copyOf(index)
}
}

View File

@ -0,0 +1,173 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile BaseCodec.kt
* LastUpdate 2025-09-18 14:07:35
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.base
import java.io.File
import java.io.IOException
import java.nio.file.Path
interface BaseCodec {
/**
* 将字节数组编码为Base64字符串
*
* @param bytes 需要编码的字节数组
* @return 编码后的Base64字符串
*/
fun encode(bytes: ByteArray): String
/**
* 将Base64字符串解码为字节数组
*
* @param string 需要解码的Base64字符串
* @return 解码后的字节数组
*/
fun decode(string: String): ByteArray
/**
* 将文件内容编码为Base64字符串
*
* @param file 需要编码的文件
* @return 文件内容的Base64编码字符串
* @throws IOException 当文件读取失败时抛出
*/
@Throws(IOException::class)
fun encode(file: File): String {
return encode(file.readBytes())
}
/**
* 将Base64字符串解码并写入文件
*
* @param file 目标文件
* @param string 需要解码的Base64字符串
* @throws IOException 当文件写入失败时抛出
*/
@Throws(IOException::class)
fun decode(file: File, string: String) {
file.writeBytes(decode(string))
}
/**
* 安全地将文件内容编码为Base64字符串出现异常时返回null
*
* @param file 需要编码的文件
* @return 文件内容的Base64编码字符串失败时返回null
*/
fun encodeSafe(file: File): String? {
return try {
encode(file)
} catch (_: Exception) {
null
}
}
/**
* 安全地将Base64字符串解码并写入文件返回操作是否成功
*
* @param file 目标文件
* @param string 需要解码的Base64字符串
* @return 操作成功返回true失败返回false
*/
fun decodeSafe(file: File, string: String): Boolean {
return try {
decode(file, string)
true
} catch (_: Exception) {
false
}
}
/**
* 将路径对应的文件内容编码为Base64字符串
*
* @param path 需要编码的文件路径
* @return 文件内容的Base64编码字符串
* @throws IOException 当文件读取失败时抛出
*/
@Throws(IOException::class)
fun encode(path: Path): String {
return encode(path.toFile().readBytes())
}
/**
* 将Base64字符串解码并写入路径指定的文件
*
* @param path 目标文件路径
* @param string 需要解码的Base64字符串
* @throws IOException 当文件写入失败时抛出
*/
@Throws(IOException::class)
fun decode(path: Path, string: String) {
path.toFile().writeBytes(decode(string))
}
/**
* 安全地将路径对应的文件内容编码为Base64字符串出现异常时返回null
*
* @param path 需要编码的文件路径
* @return 文件内容的Base64编码字符串失败时返回null
*/
fun encodeSafe(path: Path): String? {
return try {
encode(path)
} catch (_: Exception) {
null
}
}
/**
* 安全地将Base64字符串解码并写入路径指定的文件返回操作是否成功
*
* @param path 目标文件路径
* @param string 需要解码的Base64字符串
* @return 操作成功返回true失败返回false
*/
fun decodeSafe(path: Path, string: String): Boolean {
return try {
decode(path, string)
true
} catch (_: Exception) {
false
}
}
/**
* 将字符串编码为Base64字符串
*
* @param string 需要编码的字符串
* @return 编码后的Base64字符串
*/
fun encode(string: String): String {
return encode(string.toByteArray())
}
/**
* 将Base64字符串解码为字符串
*
* @param string 需要解码的Base64字符串
* @return 解码后的字符串
*/
fun decodetoString(string: String): String {
return decode(string).toString(Charsets.UTF_8)
}
}

View File

@ -0,0 +1,63 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile BaseUtils.kt
* LastUpdate 2025-09-19 20:18:09
* UpdateUser MingLiPro
*/
@file:JvmName("BaseUtils")
package com.mingliqiye.utils.base
/**
* Base64编解码器实例
* 使用懒加载方式初始化Base64编解码器对象
* 保证线程安全且只在首次访问时创建实例
*/
val BASE64: BaseCodec by lazy {
Base64()
}
/**
* Base91编解码器实例
* 使用懒加载方式初始化Base91编解码器对象
* 保证线程安全且只在首次访问时创建实例
*/
val BASE91: BaseCodec by lazy {
Base91()
}
/**
* Base91编解码器实例
* 使用懒加载方式初始化Base91编解码器对象
* 保证线程安全且只在首次访问时创建实例
*/
val BASE16: BaseCodec by lazy {
Base16()
}
/**
* Base256编解码器实例
* 使用懒加载方式初始化Base256编解码器对象
* 保证线程安全且只在首次访问时创建实例
*/
val BASE256: BaseCodec by lazy {
Base256()
}

View File

@ -1,160 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile Base64Utils.kt
* LastUpdate 2025-09-14 18:44:22
* UpdateUser MingLiPro
*/
@file:JvmName("Base64Utils")
package com.mingliqiye.utils.base64
import java.io.File
import java.io.IOException
import java.nio.file.Path
import java.util.*
val BASE_64_ENCODER: Base64.Encoder = Base64.getEncoder()
val BASE_64_DECODER: Base64.Decoder = Base64.getDecoder()
/**
* 将字节数组编码为Base64字符串
*
* @param bytes 需要编码的字节数组
* @return 编码后的Base64字符串
*/
fun encode(bytes: ByteArray): String {
return BASE_64_ENCODER.encodeToString(bytes)
}
/**
* 将Base64字符串解码为字节数组
*
* @param string 需要解码的Base64字符串
* @return 解码后的字节数组
*/
fun decode(string: String): ByteArray {
return BASE_64_DECODER.decode(string)
}
/**
* 将文件内容编码为Base64字符串
*
* @param file 需要编码的文件
* @return 文件内容的Base64编码字符串
* @throws IOException 当文件读取失败时抛出
*/
@Throws(IOException::class)
fun encode(file: File): String {
return encode(file.readBytes())
}
/**
* 将Base64字符串解码并写入文件
*
* @param file 目标文件
* @param string 需要解码的Base64字符串
* @throws IOException 当文件写入失败时抛出
*/
@Throws(IOException::class)
fun decode(file: File, string: String) {
file.writeBytes(decode(string))
}
/**
* 安全地将文件内容编码为Base64字符串出现异常时返回null
*
* @param file 需要编码的文件
* @return 文件内容的Base64编码字符串失败时返回null
*/
fun encodeSafe(file: File): String? {
return try {
encode(file)
} catch (_: Exception) {
null
}
}
/**
* 安全地将Base64字符串解码并写入文件返回操作是否成功
*
* @param file 目标文件
* @param string 需要解码的Base64字符串
* @return 操作成功返回true失败返回false
*/
fun decodeSafe(file: File, string: String): Boolean {
return try {
decode(file, string)
true
} catch (_: Exception) {
false
}
}
/**
* 将路径对应的文件内容编码为Base64字符串
*
* @param path 需要编码的文件路径
* @return 文件内容的Base64编码字符串
* @throws IOException 当文件读取失败时抛出
*/
@Throws(IOException::class)
fun encode(path: Path): String {
return encode(path.toFile().readBytes())
}
/**
* 将Base64字符串解码并写入路径指定的文件
*
* @param path 目标文件路径
* @param string 需要解码的Base64字符串
* @throws IOException 当文件写入失败时抛出
*/
@Throws(IOException::class)
fun decode(path: Path, string: String) {
path.toFile().writeBytes(decode(string))
}
/**
* 安全地将路径对应的文件内容编码为Base64字符串出现异常时返回null
*
* @param path 需要编码的文件路径
* @return 文件内容的Base64编码字符串失败时返回null
*/
fun encodeSafe(path: Path): String? {
return try {
encode(path)
} catch (_: Exception) {
null
}
}
/**
* 安全地将Base64字符串解码并写入路径指定的文件返回操作是否成功
*
* @param path 目标文件路径
* @param string 需要解码的Base64字符串
* @return 操作成功返回true失败返回false
*/
fun decodeSafe(path: Path, string: String): Boolean {
return try {
decode(path, string)
true
} catch (_: Exception) {
false
}
}

View File

@ -0,0 +1,59 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile BCrypt.kt
* LastUpdate 2025-09-19 20:17:41
* UpdateUser MingLiPro
*/
@file:JvmName("BCrypt")
package com.mingliqiye.utils.bcrypt
import java.security.SecureRandom
import org.mindrot.jbcrypt.BCrypt as JBCrypt
fun hashpw(string: String): String {
return hashpw(string, gensalt())
}
fun hashpw(string: String, salt: String = gensalt()): String {
return JBCrypt.hashpw(string, salt)
}
fun checkpw(string: String, bcrypted: String): Boolean {
return JBCrypt.checkpw(string, bcrypted)
}
fun gensalt(): String {
return JBCrypt.gensalt()
}
fun gensalt(long: Int): String {
return JBCrypt.gensalt(long)
}
fun gensalt(long: Int, secureRandom: SecureRandom): String {
return JBCrypt.gensalt(long, secureRandom)
}

View File

@ -1,241 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile Factory.kt
* LastUpdate 2025-09-14 19:09:28
* UpdateUser MingLiPro
*/
@file:JvmName("Factory")
package com.mingliqiye.utils.bean
import com.mingliqiye.utils.bean.annotation.ComponentBean
import com.mingliqiye.utils.bean.annotation.InjectBean
import java.io.File
import java.net.URL
import java.util.*
import java.util.concurrent.ConcurrentHashMap
import kotlin.reflect.KClass
/**
* 存储所有已注册的Bean实例键为Bean名称值为Bean实例
*/
private val BEANS: ConcurrentHashMap<String, Any> = ConcurrentHashMap()
/**
* 存储按类型查找的Bean实例键为Bean的Class对象值为Bean实例
*/
private val TYPE_BEANS: ConcurrentHashMap<KClass<*>, Any> = ConcurrentHashMap()
/**
* 自动扫描指定类所在包下的所有类并注册为Bean
*
* @param c 指定的类用于获取其所在的包
* @throws IllegalArgumentException 如果传入的类为null或位于默认包中
*/
fun autoScan(c: Class<*>?) {
if (c == null) {
throw IllegalArgumentException("Class cannot be null")
}
val pkg = c.`package`
if (pkg == null) {
throw IllegalArgumentException("Class is in the default package")
}
scan(pkg.name)
}
/**
* 扫描指定包路径下的所有类文件并注册其中带有@ComponentBean注解的类为Bean
*
* @param basePackage 要扫描的基础包名
* @throws RuntimeException 如果在扫描过程中发生异常
*/
fun scan(basePackage: String) {
try {
val path = basePackage.replace('.', '/')
val classLoader = Thread.currentThread().contextClassLoader
val resources: Enumeration<URL> = classLoader.getResources(path)
while (resources.hasMoreElements()) {
val resource = resources.nextElement()
val file = File(resource.toURI())
scanDirectory(file, basePackage)
}
injectDependencies()
} catch (e: Exception) {
throw RuntimeException(e)
}
}
/**
* 递归扫描目录中的所有类文件并注册符合条件的类为Bean
*
* @param directory 当前要扫描的目录
* @param packageName 当前目录对应的包名
* @throws Exception 如果在扫描或类加载过程中发生异常
*/
private fun scanDirectory(directory: File, packageName: String) {
val files = directory.listFiles() ?: return
for (file in files) {
if (file.isDirectory) {
scanDirectory(file, "$packageName.${file.name}")
} else if (file.name.endsWith(".class")) {
val className = packageName + '.' + file.name.replace(".class", "")
registerComponent(Class.forName(className))
}
}
}
/**
* 注册一个带有@ComponentBean注解的类为Bean实例
*
* @param clazz 要注册的类
* @throws Exception 如果在实例化类或处理注解时发生异常
*/
private fun registerComponent(clazz: Class<*>) {
if (clazz.isAnnotationPresent(ComponentBean::class.java)) {
val component = clazz.getAnnotation(ComponentBean::class.java)
val name = component.value.ifEmpty { clazz.name }
val instance = clazz.getDeclaredConstructor().newInstance()
BEANS[name] = instance
val kClass = clazz.kotlin
TYPE_BEANS[kClass] = instance
for (interfaceClass in clazz.interfaces) {
TYPE_BEANS.putIfAbsent(interfaceClass.kotlin, instance)
}
}
}
/**
* 对所有已注册的Bean进行依赖注入处理
*
* @throws Exception 如果在注入过程中发生异常
*/
private fun injectDependencies() {
for (bean in BEANS.values) {
for (field in bean.javaClass.declaredFields) {
if (field.isAnnotationPresent(InjectBean::class.java)) {
val inject = field.getAnnotation(InjectBean::class.java)
val dependency = findDependency(field.type, inject.value)
if (dependency == null) {
throw IllegalStateException(
"No suitable dependency found for field " + field.name + " in class " + bean.javaClass.name
)
}
field.isAccessible = true
field.set(bean, dependency)
}
}
}
}
/**
* 根据类型和名称查找对应的依赖实例
*
* @param type 依赖的类型
* @param name 依赖的名称可为空
* @return 找到的依赖实例未找到则返回null
*/
private fun findDependency(type: Class<*>, name: String): Any? {
if (name.isNotEmpty()) {
return BEANS[name]
}
val dependency = TYPE_BEANS[type.kotlin]
if (dependency != null) {
return dependency
}
for (interfaceType in TYPE_BEANS.keys) {
if (type.isAssignableFrom(interfaceType.java)) {
return TYPE_BEANS[interfaceType]
}
}
return null
}
/**
* 将一个对象添加到Bean容器中使用其类名作为键
*
* @param obj 要添加的对象
* @throws RuntimeException 如果在注入依赖时发生异常
*/
fun add(obj: Any) {
val clazz = obj.javaClass
val name = clazz.name
BEANS[name] = obj
TYPE_BEANS[clazz.kotlin] = obj
try {
injectDependencies()
} catch (e: Exception) {
throw RuntimeException(e)
}
}
/**
* 将一个对象以指定名称添加到Bean容器中
*
* @param name Bean的名称
* @param obj 要添加的对象
* @throws RuntimeException 如果在注入依赖时发生异常
*/
fun add(name: String, obj: Any) {
BEANS[name] = obj
TYPE_BEANS[obj.javaClass.kotlin] = obj
try {
injectDependencies()
} catch (e: Exception) {
throw RuntimeException(e)
}
}
/**
* 根据类型获取对应的Bean实例
*
* @param objclass Bean的类型
* @param T Bean的泛型类型
* @return 对应类型的Bean实例未找到则返回null
*/
@Suppress("UNCHECKED_CAST")
fun <T : Any> get(objclass: KClass<T>): T? {
return TYPE_BEANS[objclass] as? T
}
/**
* 根据名称和类型获取对应的Bean实例
*
* @param name Bean的名称
* @param objclass Bean的类型
* @param T Bean的泛型类型
* @return 对应名称和类型的Bean实例未找到则返回null
*/
@Suppress("UNCHECKED_CAST")
fun <T : Any> get(name: String, objclass: KClass<T>): T? {
return BEANS[name] as? T
}
/**
* 根据名称获取对应的Bean实例
*
* @param name Bean的名称
* @return 对应名称的Bean实例未找到则返回null
*/
fun get(name: String): Any? {
return BEANS[name]
}

View File

@ -1,43 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile ComponentBean.kt
* LastUpdate 2025-09-14 18:48:59
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.bean.annotation
import kotlin.annotation.AnnotationRetention.RUNTIME
import kotlin.annotation.AnnotationTarget.CLASS
import kotlin.annotation.AnnotationTarget.FIELD
/**
* 组件bean注解
* @author MingLiPro
*/
@Retention(RUNTIME)
@Target(CLASS)
annotation class ComponentBean(val value: String = "")
/**
* 注入bean注解
* @author MingLiPro
*/
@Retention(RUNTIME)
@Target(FIELD)
annotation class InjectBean(val value: String = "")

View File

@ -16,14 +16,13 @@
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile ByteUtils.kt
* LastUpdate 2025-09-14 19:28:38
* LastUpdate 2025-09-20 11:49:05
* UpdateUser MingLiPro
*/
@file:JvmName("ByteUtils")
package com.mingliqiye.utils.bytes
import com.mingliqiye.utils.collection.Lists
import com.mingliqiye.utils.stream.SuperStream
const val ESC_ASC: Byte = 0x10
@ -42,8 +41,20 @@ const val ESC_RESERVED: Byte = 0x06
* @return 包含每个字节对应十六进制字符串的列表
*/
fun ByteArray.getByteArrayString(): MutableList<String> {
return Lists.toList(this)!!.stream()
.map { a -> String.format("0X%02X", a!!.toInt() and 0xFF) }
.collect(SuperStream.Collectors.toList())
return this.toList().stream().map { a -> String.format("0X%02X", a!!.toInt() and 0xFF) }
.collect(SuperStream.toList()) as MutableList<String>
}
fun Char.hexDigitToValue(): Int {
return when (this) {
in '0'..'9' -> this - '0'
in 'A'..'F' -> this - 'A' + 10
in 'a'..'f' -> this - 'a' + 10
else -> throw NumberFormatException("Invalid hex character: $this")
}
}
private fun hexStringToByteArray(string: String): ByteArray {
return string.hexToByteArray()
}

View File

@ -15,8 +15,8 @@
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile CloneUtil.kt
* LastUpdate 2025-09-14 19:53:41
* CurrentFile CloneUtils.kt
* LastUpdate 2025-09-20 14:01:29
* UpdateUser MingLiPro
*/
@file:JvmName("CloneUtils")
@ -38,8 +38,7 @@ inline fun <reified T> T.deepJsonClone(jsonApi: JsonApi): T {
} catch (e: Exception) {
throw JsonException(
"Failed to deep clone object using JSON",
e
"Failed to deep clone object using JSON", e
)
}
}

View File

@ -0,0 +1,993 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile Collection.kt
* LastUpdate 2025-09-21 14:36:57
* UpdateUser MingLiPro
*/
@file:JvmName("Collections")
package com.mingliqiye.utils.collection
import com.mingliqiye.utils.stream.SuperStream
import java.util.*
import java.util.stream.Collectors
/**
* 将当前集合转换为数组
*
* @param T 集合元素类型
* @return 转换后的数组
*/
inline fun <reified T> Collection<T>.toArray(): Array<T> {
return arrayOf(*this.toTypedArray())
}
/**
* 将当前集合转换为 Map其中键为集合元素本身值由给定函数生成
*
* @param T 集合元素类型
* @param V 映射值的类型
* @param v 用于生成映射值的函数
* @return 转换后的 Map
*/
@Suppress("UNCHECKED_CAST")
inline fun <reified T, V> Collection<T>.toMap(noinline v: (T) -> V): Map<T, V> {
return this.stream().collect(
SuperStream.toMap(
v
)
) as Map<T, V>
}
/**
* 将当前集合转换为 Map其中键和值分别由给定函数生成
*
* @param T 集合元素类型
* @param V 映射值的类型
* @param K 映射键的类型
* @param k 用于生成映射键的函数
* @param v 用于生成映射值的函数
* @return 转换后的 Map
*/
inline fun <reified T, V, K> Collection<T>.toMap(noinline k: (T) -> K, noinline v: (T) -> V): Map<K, V> {
return this.stream().collect(
Collectors.toMap(
k, v
)
)
}
/**
* 将数组转换为 Set
*
* @param T 数组元素类型
* @param array 输入数组
* @return 转换后的 Set
*/
fun <T> toSet(array: Array<T>): Set<T> {
return array.toSet()
}
/**
* 获取集合中的第一个元素如果集合为空则返回 null
*
* @param T 集合元素类型
* @return 第一个元素或 null
*/
inline fun <reified T> Collection<T>.getFirst(): T? {
if (this.isEmpty()) {
return null
}
if (this is MutableList<T>) {
return this.first()
}
return this.iterator().next()
}
/**
* 获取数组中的第一个元素如果数组为空则返回 null
*
* @param T 数组元素类型
* @return 第一个元素或 null
*/
inline fun <reified T> Array<T>.getFirst(): T? {
if (this.isEmpty()) {
return null
}
return this.first()
}
/**
* 获取集合中的最后一个元素如果集合为空则返回 null
*
* @param T 集合元素类型
* @return 最后一个元素或 null
*/
inline fun <reified T> Collection<T>.getLast(): T? {
if (this.isEmpty()) {
return null
}
if (this is MutableList<T>) {
return this.last()
}
var lastElement: T? = null
for (element in this) {
lastElement = element
}
return lastElement
}
/**
* 获取数组中的最后一个元素如果数组为空则返回 null
*
* @param T 数组元素类型
* @return 最后一个元素或 null
*/
inline fun <reified T> Array<T>.getLast(): T? {
if (this.isEmpty()) {
return null
}
return this.last()
}
/**
* 根据索引获取集合中的元素若索引越界则返回默认值
*
* @param T 集合元素类型
* @param index 索引位置
* @param defaultValue 默认返回值
* @return 指定索引处的元素或默认值
*/
inline fun <reified T> Collection<T>.getOrDefault(
index: Int, defaultValue: T
): T {
if (!(!this.isEmpty() && index < this.size)) {
return defaultValue
}
if (this is List<T>) {
return this[index]
}
var i = 0
for (element in this) {
if (i == index) {
return element
}
i++
}
return defaultValue
}
/**
* 创建一个新的 ArrayList 实例
*
* @param T 元素类型
* @return 新创建的 ArrayList
*/
fun <T> newArrayList(): ArrayList<T> {
return ArrayList()
}
/**
* 创建一个指定初始容量的新 ArrayList 实例
*
* @param T 元素类型
* @param size 初始容量大小
* @return 新创建的 ArrayList
*/
fun <T> newArrayList(size: Int): ArrayList<T> {
return ArrayList()
}
/**
* 使用可变参数创建一个新的 ArrayList 实例
*
* @param T 元素类型
* @param elements 可变参数列表
* @return 新创建的 ArrayList
*/
fun <T> newArrayList(vararg elements: T): ArrayList<T> {
return newArrayList(elements.asList())
}
/**
* 将当前集合转换为新的 ArrayList 实例
*
* @param T 元素类型
* @return 新创建的 ArrayList
*/
fun <T> Collection<T>.newArrayLists(): ArrayList<T> {
return newArrayList(this)
}
/**
* 将数组转换为新的 ArrayList 实例
*
* @param T 元素类型
* @param elements 输入数组
* @return 新创建的 ArrayList
*/
fun <T> newArrayLists(elements: Array<T>): ArrayList<T> {
return newArrayList(elements.asList())
}
/**
* 将集合转换为新的 ArrayList 实例
*
* @param T 元素类型
* @param elements 输入集合
* @return 新创建的 ArrayList
*/
fun <T> newArrayList(elements: Collection<T>): ArrayList<T> {
return ArrayList(elements.toList())
}
/**
* Iterable 转换为新的 ArrayList 实例
*
* @param T 元素类型
* @param elements 输入 Iterable
* @return 新创建的 ArrayList
*/
fun <T> newArrayList(elements: Iterable<T>): ArrayList<T> {
return newArrayList(elements.toList())
}
/**
* Sequence 转换为新的 ArrayList 实例
*
* @param T 元素类型
* @param elements 输入 Sequence
* @return 新创建的 ArrayList
*/
fun <T> newArrayList(elements: Sequence<T>): ArrayList<T> {
return newArrayList(elements.toList())
}
/**
* 创建一个新的 LinkedList 实例
*
* @param T 元素类型
* @return 新创建的 LinkedList
*/
fun <T> newLinkedList(): LinkedList<T> {
return LinkedList()
}
/**
* 使用可变参数创建一个新的 LinkedList 实例
*
* @param T 元素类型
* @param elements 可变参数列表
* @return 新创建的 LinkedList
*/
fun <T> newLinkedList(vararg elements: T): LinkedList<T> {
val list = newLinkedList<T>()
list.addAll(elements.asList())
return list
}
/**
* 将集合转换为新的 LinkedList 实例
*
* @param T 元素类型
* @param elements 输入集合
* @return 新创建的 LinkedList
*/
fun <T> newLinkedList(elements: Collection<T>): LinkedList<T> {
val list = newLinkedList<T>()
list.addAll(elements)
return list
}
/**
* Iterable 转换为新的 LinkedList 实例
*
* @param T 元素类型
* @param elements 输入 Iterable
* @return 新创建的 LinkedList
*/
fun <T> newLinkedList(elements: Iterable<T>): LinkedList<T> {
val list = newLinkedList<T>()
for (element in elements) {
list.add(element)
}
return list
}
/**
* Sequence 转换为新的 LinkedList 实例
*
* @param T 元素类型
* @param elements 输入 Sequence
* @return 新创建的 LinkedList
*/
fun <T> newLinkedList(elements: Sequence<T>): LinkedList<T> {
return newLinkedList(elements.toList())
}
/**
* 创建一个新的 Vector 实例
*
* @param T 元素类型
* @return 新创建的 Vector
*/
fun <T> newVector(): Vector<T> {
return Vector()
}
/**
* 使用可变参数创建一个新的 Vector 实例
*
* @param T 元素类型
* @param elements 可变参数列表
* @return 新创建的 Vector
*/
fun <T> newVector(vararg elements: T): Vector<T> {
val vector = newVector<T>()
vector.addAll(elements.asList())
return vector
}
/**
* 将集合转换为新的 Vector 实例
*
* @param T 元素类型
* @param elements 输入集合
* @return 新创建的 Vector
*/
fun <T> newVector(elements: Collection<T>): Vector<T> {
val vector = newVector<T>()
vector.addAll(elements)
return vector
}
/**
* Iterable 转换为新的 Vector 实例
*
* @param T 元素类型
* @param elements 输入 Iterable
* @return 新创建的 Vector
*/
fun <T> newVector(elements: Iterable<T>): Vector<T> {
val vector = newVector<T>()
for (element in elements) {
vector.add(element)
}
return vector
}
/**
* Sequence 转换为新的 Vector 实例
*
* @param T 元素类型
* @param elements 输入 Sequence
* @return 新创建的 Vector
*/
fun <T> newVector(elements: Sequence<T>): Vector<T> {
return newVector(elements.toList())
}
/**
* 创建一个新的 HashSet 实例
*
* @param T 元素类型
* @return 新创建的 HashSet
*/
fun <T> newHashSet(): HashSet<T> {
return HashSet()
}
/**
* 创建一个指定初始容量的新 HashSet 实例
*
* @param T 元素类型
* @param size 初始容量大小
* @return 新创建的 HashSet
*/
fun <T> newHashSet(size: Int): HashSet<T> {
return HashSet(size)
}
/**
* 使用可变参数创建一个新的 HashSet 实例
*
* @param T 元素类型
* @param elements 可变参数列表
* @return 新创建的 HashSet
*/
fun <T> newHashSet(vararg elements: T): HashSet<T> {
val set = newHashSet<T>()
set.addAll(elements.asList())
return set
}
/**
* 将集合转换为新的 HashSet 实例
*
* @param T 元素类型
* @param elements 输入集合
* @return 新创建的 HashSet
*/
fun <T> newHashSet(elements: Collection<T>): HashSet<T> {
val set = newHashSet<T>()
set.addAll(elements)
return set
}
/**
* Iterable 转换为新的 HashSet 实例
*
* @param T 元素类型
* @param elements 输入 Iterable
* @return 新创建的 HashSet
*/
fun <T> newHashSet(elements: Iterable<T>): HashSet<T> {
val set = newHashSet<T>()
for (element in elements) {
set.add(element)
}
return set
}
/**
* Sequence 转换为新的 HashSet 实例
*
* @param T 元素类型
* @param elements 输入 Sequence
* @return 新创建的 HashSet
*/
fun <T> newHashSet(elements: Sequence<T>): HashSet<T> {
return newHashSet(elements.toSet())
}
/**
* 创建一个新的 LinkedHashSet 实例
*
* @param T 元素类型
* @return 新创建的 LinkedHashSet
*/
fun <T> newLinkedHashSet(): LinkedHashSet<T> {
return LinkedHashSet()
}
/**
* 创建一个指定初始容量的新 LinkedHashSet 实例
*
* @param T 元素类型
* @param size 初始容量大小
* @return 新创建的 LinkedHashSet
*/
fun <T> newLinkedHashSet(size: Int): LinkedHashSet<T> {
return LinkedHashSet(size)
}
/**
* 使用可变参数创建一个新的 LinkedHashSet 实例
*
* @param T 元素类型
* @param elements 可变参数列表
* @return 新创建的 LinkedHashSet
*/
fun <T> newLinkedHashSet(vararg elements: T): LinkedHashSet<T> {
val set = newLinkedHashSet<T>()
set.addAll(elements.asList())
return set
}
/**
* 将集合转换为新的 LinkedHashSet 实例
*
* @param T 元素类型
* @param elements 输入集合
* @return 新创建的 LinkedHashSet
*/
fun <T> newLinkedHashSet(elements: Collection<T>): LinkedHashSet<T> {
val set = newLinkedHashSet<T>()
set.addAll(elements)
return set
}
/**
* Iterable 转换为新的 LinkedHashSet 实例
*
* @param T 元素类型
* @param elements 输入 Iterable
* @return 新创建的 LinkedHashSet
*/
fun <T> newLinkedHashSet(elements: Iterable<T>): LinkedHashSet<T> {
val set = newLinkedHashSet<T>()
for (element in elements) {
set.add(element)
}
return set
}
/**
* Sequence 转换为新的 LinkedHashSet 实例
*
* @param T 元素类型
* @param elements 输入 Sequence
* @return 新创建的 LinkedHashSet
*/
fun <T> newLinkedHashSet(elements: Sequence<T>): LinkedHashSet<T> {
return newLinkedHashSet(elements.toSet())
}
/**
* 创建一个新的 TreeSet 实例
*
* @param T 元素类型必须实现 Comparable 接口
* @return 新创建的 TreeSet
*/
fun <T : Comparable<T>> newTreeSet(): TreeSet<T> {
return TreeSet()
}
/**
* 使用可变参数创建一个新的 TreeSet 实例
*
* @param T 元素类型必须实现 Comparable 接口
* @param elements 可变参数列表
* @return 新创建的 TreeSet
*/
fun <T : Comparable<T>> newTreeSet(vararg elements: T): TreeSet<T> {
val set = newTreeSet<T>()
set.addAll(elements.asList())
return set
}
/**
* 将集合转换为新的 TreeSet 实例
*
* @param T 元素类型必须实现 Comparable 接口
* @param elements 输入集合
* @return 新创建的 TreeSet
*/
fun <T : Comparable<T>> newTreeSet(elements: Collection<T>): TreeSet<T> {
val set = newTreeSet<T>()
set.addAll(elements)
return set
}
/**
* Iterable 转换为新的 TreeSet 实例
*
* @param T 元素类型必须实现 Comparable 接口
* @param elements 输入 Iterable
* @return 新创建的 TreeSet
*/
fun <T : Comparable<T>> newTreeSet(elements: Iterable<T>): TreeSet<T> {
val set = newTreeSet<T>()
for (element in elements) {
set.add(element)
}
return set
}
/**
* Sequence 转换为新的 TreeSet 实例
*
* @param T 元素类型必须实现 Comparable 接口
* @param elements 输入 Sequence
* @return 新创建的 TreeSet
*/
fun <T : Comparable<T>> newTreeSet(elements: Sequence<T>): TreeSet<T> {
return newTreeSet(elements.toSet())
}
/**
* 将字节数组转换为 ArrayList
*
* @param elements 输入字节数组
* @return 转换后的 ArrayList
*/
fun newArrayLists(elements: ByteArray): ArrayList<Byte> {
return ArrayList(elements.toList())
}
/**
* 将短整型数组转换为 ArrayList
*
* @param elements 输入短整型数组
* @return 转换后的 ArrayList
*/
fun newArrayLists(elements: ShortArray): ArrayList<Short> {
return ArrayList(elements.toList())
}
/**
* 将整型数组转换为 ArrayList
*
* @param elements 输入整型数组
* @return 转换后的 ArrayList
*/
fun newArrayLists(elements: IntArray): ArrayList<Int> {
return ArrayList(elements.toList())
}
/**
* 将长整型数组转换为 ArrayList
*
* @param elements 输入长整型数组
* @return 转换后的 ArrayList
*/
fun newArrayLists(elements: LongArray): ArrayList<Long> {
return ArrayList(elements.toList())
}
/**
* 将浮点数组转换为 ArrayList
*
* @param elements 输入浮点数组
* @return 转换后的 ArrayList
*/
fun newArrayLists(elements: FloatArray): ArrayList<Float> {
return ArrayList(elements.toList())
}
/**
* 将双精度浮点数组转换为 ArrayList
*
* @param elements 输入双精度浮点数组
* @return 转换后的 ArrayList
*/
fun newArrayLists(elements: DoubleArray): ArrayList<Double> {
return ArrayList(elements.toList())
}
/**
* 将布尔数组转换为 ArrayList
*
* @param elements 输入布尔数组
* @return 转换后的 ArrayList
*/
fun newArrayLists(elements: BooleanArray): ArrayList<Boolean> {
return ArrayList(elements.toList())
}
/**
* 将字符数组转换为 ArrayList
*
* @param elements 输入字符数组
* @return 转换后的 ArrayList
*/
fun newArrayLists(elements: CharArray): ArrayList<Char> {
return ArrayList(elements.toList())
}
/**
* 创建一个新的 CopyOnWriteArrayList 实例
*
* @param T 元素类型
* @return 新创建的 CopyOnWriteArrayList
*/
fun <T> newCopyOnWriteArrayList(): java.util.concurrent.CopyOnWriteArrayList<T> {
return java.util.concurrent.CopyOnWriteArrayList()
}
/**
* 使用可变参数创建一个新的 CopyOnWriteArrayList 实例
*
* @param T 元素类型
* @param elements 可变参数列表
* @return 新创建的 CopyOnWriteArrayList
*/
fun <T> newCopyOnWriteArrayList(vararg elements: T): java.util.concurrent.CopyOnWriteArrayList<T> {
return java.util.concurrent.CopyOnWriteArrayList(elements.asList())
}
/**
* 将集合转换为新的 CopyOnWriteArrayList 实例
*
* @param T 元素类型
* @param elements 输入集合
* @return 新创建的 CopyOnWriteArrayList
*/
fun <T> newCopyOnWriteArrayList(elements: Collection<T>): java.util.concurrent.CopyOnWriteArrayList<T> {
return java.util.concurrent.CopyOnWriteArrayList(elements)
}
/**
* 创建一个新的 Stack 实例
*
* @param T 元素类型
* @return 新创建的 Stack
*/
fun <T> newStack(): Stack<T> {
return Stack()
}
/**
* 使用可变参数创建一个新的 Stack 实例
*
* @param T 元素类型
* @param elements 可变参数列表
* @return 新创建的 Stack
*/
fun <T> newStack(vararg elements: T): Stack<T> {
val stack = newStack<T>()
stack.addAll(elements.asList())
return stack
}
/**
* 将集合转换为新的 Stack 实例
*
* @param T 元素类型
* @param elements 输入集合
* @return 新创建的 Stack
*/
fun <T> newStack(elements: Collection<T>): Stack<T> {
val stack = newStack<T>()
stack.addAll(elements)
return stack
}
/**
* 创建一个新的 TreeSet 实例并指定比较器
*
* @param T 元素类型
* @param comparator 用于排序的比较器
* @return 新创建的 TreeSet
*/
fun <T> newTreeSet(comparator: Comparator<T>): TreeSet<T> {
return TreeSet(comparator)
}
/**
* 使用可变参数创建一个新的 TreeSet 实例并指定比较器
*
* @param T 元素类型
* @param comparator 用于排序的比较器
* @param elements 可变参数列表
* @return 新创建的 TreeSet
*/
fun <T> newTreeSet(comparator: Comparator<T>, vararg elements: T): TreeSet<T> {
val set = newTreeSet(comparator)
set.addAll(elements.asList())
return set
}
/**
* 将集合转换为新的 TreeSet 实例并指定比较器
*
* @param T 元素类型
* @param comparator 用于排序的比较器
* @param elements 输入集合
* @return 新创建的 TreeSet
*/
fun <T> newTreeSet(comparator: Comparator<T>, elements: Collection<T>): TreeSet<T> {
val set = newTreeSet(comparator)
set.addAll(elements)
return set
}
/**
* Iterable 转换为新的 TreeSet 实例并指定比较器
*
* @param T 元素类型
* @param comparator 用于排序的比较器
* @param elements 输入 Iterable
* @return 新创建的 TreeSet
*/
fun <T> newTreeSet(comparator: Comparator<T>, elements: Iterable<T>): TreeSet<T> {
val set = newTreeSet(comparator)
for (element in elements) {
set.add(element)
}
return set
}
/**
* Sequence 转换为新的 TreeSet 实例并指定比较器
*
* @param T 元素类型
* @param comparator 用于排序的比较器
* @param elements 输入 Sequence
* @return 新创建的 TreeSet
*/
fun <T> newTreeSet(comparator: Comparator<T>, elements: Sequence<T>): TreeSet<T> {
return newTreeSet(comparator, elements.toSet())
}
/**
* 将当前集合转换为新的 CopyOnWriteArrayList 实例
*
* @param T 元素类型
* @return 新创建的 CopyOnWriteArrayList
*/
fun <T> Collection<T>.newCopyOnWriteArrayLists(): java.util.concurrent.CopyOnWriteArrayList<T> {
return java.util.concurrent.CopyOnWriteArrayList(this)
}
/**
* 将当前集合转换为新的 Stack 实例
*
* @param T 元素类型
* @return 新创建的 Stack
*/
fun <T> Collection<T>.newStacks(): Stack<T> {
val stack = Stack<T>()
stack.addAll(this)
return stack
}
/**
* 将当前集合转换为新的 TreeSet 实例
*
* @param T 元素类型必须实现 Comparable 接口
* @return 新创建的 TreeSet
*/
fun <T> Collection<T>.newTreeSets(): TreeSet<T> where T : Comparable<T> {
val set = TreeSet<T>()
set.addAll(this)
return set
}
/**
* 将当前集合转换为新的 TreeSet 实例并指定比较器
*
* @param T 元素类型
* @param comparator 用于排序的比较器
* @return 新创建的 TreeSet
*/
fun <T> Collection<T>.newTreeSets(comparator: Comparator<T>): TreeSet<T> {
val set = TreeSet(comparator)
set.addAll(this)
return set
}
/**
* Byte 类型的 List 转换为字节数组
*
* @param list 输入的 Byte 列表
* @return 转换后的字节数组
*/
fun toArray(list: List<Byte>): ByteArray {
val arr = ByteArray(list.size)
for (i in list.indices) {
arr[i] = list[i]
}
return arr
}
/**
* Short 类型的 List 转换为短整型数组
*
* @param list 输入的 Short 列表
* @return 转换后的短整型数组
*/
fun toArray(list: List<Short>): ShortArray {
val arr = ShortArray(list.size)
for (i in list.indices) {
arr[i] = list[i]
}
return arr
}
/**
* Int 类型的 List 转换为整型数组
*
* @param list 输入的 Int 列表
* @return 转换后的整型数组
*/
fun toArray(list: List<Int>): IntArray {
val arr = IntArray(list.size)
for (i in list.indices) {
arr[i] = list[i]
}
return arr
}
/**
* Long 类型的 List 转换为长整型数组
*
* @param list 输入的 Long 列表
* @return 转换后的长整型数组
*/
fun toArray(list: List<Long>): LongArray {
val arr = LongArray(list.size)
for (i in list.indices) {
arr[i] = list[i]
}
return arr
}
/**
* Float 类型的 List 转换为浮点数组
*
* @param list 输入的 Float 列表
* @return 转换后的浮点数组
*/
fun toArray(list: List<Float>): FloatArray {
val arr = FloatArray(list.size)
for (i in list.indices) {
arr[i] = list[i]
}
return arr
}
/**
* Double 类型的 List 转换为双精度浮点数组
*
* @param list 输入的 Double 列表
* @return 转换后的双精度浮点数组
*/
fun toArray(list: List<Double>): DoubleArray {
val arr = DoubleArray(list.size)
for (i in list.indices) {
arr[i] = list[i]
}
return arr
}
/**
* Boolean 类型的 List 转换为布尔数组
*
* @param list 输入的 Boolean 列表
* @return 转换后的布尔数组
*/
fun toArray(list: List<Boolean>): BooleanArray {
val arr = BooleanArray(list.size)
for (i in list.indices) {
arr[i] = list[i]
}
return arr
}
/**
* Char 类型的 List 转换为字符数组
*
* @param list 输入的 Char 列表
* @return 转换后的字符数组
*/
fun toArray(list: List<Char>): CharArray {
val arr = CharArray(list.size)
for (i in list.indices) {
arr[i] = list[i]
}
return arr
}
/**
* 将任意类型的 List 转换为数组
*
* @param T 元素类型
* @param list 输入的 List
* @return 转换后的数组
*/
inline fun <reified T> toArray(list: List<T>): Array<T> {
if (list.isEmpty())
return arrayOf<T>()
return SuperStream.of<T>(list)
.toArray(T::class.java)
}
fun <T> toArray(list: List<T>, clazz: Class<T>): Array<T> {
return SuperStream.of<T>(list)
.toArray(clazz)
}

Some files were not shown because too many files have changed in this diff Show More