From 9ebd09a8105c899d1779d00248a2598baaea1ada Mon Sep 17 00:00:00 2001 From: minglipro Date: Tue, 2 Sep 2025 16:15:35 +0800 Subject: [PATCH] =?UTF-8?q?feat(utils):=20=E6=B7=BB=E5=8A=A0=E9=AB=98?= =?UTF-8?q?=E7=B2=BE=E5=BA=A6=E6=97=B6=E9=97=B4=E8=8E=B7=E5=8F=96=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E5=B9=B6=E4=BC=98=E5=8C=96=E7=9B=B8=E5=85=B3=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 AutoConfiguration 类,用于 Spring Boot 自动配置 - 添加高精度时间获取功能,兼容 Java1.8 及以上版本- 优化 DateTime 类,增加 fileTimeToLocalDateTime 方法 - 更新 ForEach 类,增加对基本类型数组的遍历支持 -调整 Factory 类,使用 BEANS 和 TYPE_BEANS 替代原变量名 - 更新 ByteUtil 类,添加常用字节常量- 修改 HashUtils 类,优化文件读取缓冲区大小 --- build.gradle.kts | 44 +- gradle.properties | 2 +- resources/META-INF/meta-data | 7 + ...ot.autoconfigure.AutoConfiguration.imports | 1 + src/com/mingliqiye/utils/bean/Factory.java | 34 +- .../utils/bean/annotation/ComponentBean.java | 3 + .../utils/bean/annotation/InjectBean.java | 3 + .../utils/bean/springboot/SpringBeanUtil.java | 3 + src/com/mingliqiye/utils/bytes/ByteUtil.java | 10 + .../mingliqiye/utils/collection/ForEach.java | 186 +++ src/com/mingliqiye/utils/hash/HashUtils.java | 2 +- .../mingliqiye/utils/jna/FieldStructure.java | 37 + .../utils/jna/time/WinKernel32.java | 15 + .../mingliqiye/utils/random/RandomBytes.java | 31 + .../mingliqiye/utils/random/RandomInt.java | 37 + .../mingliqiye/utils/random/RandomString.java | 24 + .../autoconfigure/AutoConfiguration.java | 74 + .../mingliqiye/utils/stream/ListStream.java | 1318 +++++++++++++++++ .../mingliqiye/utils/stream/MapStream.java | 313 ++++ src/com/mingliqiye/utils/time/DateTime.java | 75 +- .../utils/time/serialization/Jackson.java | 1 - .../utils/uuid/serialization/Jackson.java | 15 +- 22 files changed, 2189 insertions(+), 46 deletions(-) create mode 100644 resources/META-INF/meta-data create mode 100644 resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 src/com/mingliqiye/utils/jna/FieldStructure.java create mode 100644 src/com/mingliqiye/utils/jna/time/WinKernel32.java create mode 100644 src/com/mingliqiye/utils/random/RandomBytes.java create mode 100644 src/com/mingliqiye/utils/random/RandomInt.java create mode 100644 src/com/mingliqiye/utils/random/RandomString.java create mode 100644 src/com/mingliqiye/utils/springboot/autoconfigure/AutoConfiguration.java create mode 100644 src/com/mingliqiye/utils/stream/ListStream.java create mode 100644 src/com/mingliqiye/utils/stream/MapStream.java diff --git a/build.gradle.kts b/build.gradle.kts index a924a0d..5352275 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,3 +1,6 @@ +import java.time.LocalDateTime +import java.time.format.DateTimeFormatter + plugins { idea id("java-library") @@ -22,18 +25,17 @@ java { } dependencies { + annotationProcessor("org.jetbrains:annotations:24.0.0") + annotationProcessor("org.projectlombok:lombok:1.18.38") compileOnly("org.springframework.boot:spring-boot-starter:2.7.14") compileOnly("com.fasterxml.jackson.core:jackson-databind:2.19.2") compileOnly("org.mybatis:mybatis:3.5.19") - + 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("org.projectlombok:lombok:1.18.38") - - annotationProcessor("org.jetbrains:annotations:24.0.0") - annotationProcessor("org.projectlombok:lombok:1.18.38") + implementation("net.java.dev.jna:jna:5.17.0") } @@ -59,6 +61,22 @@ tasks.withType { options.encoding = "UTF-8" } +tasks.withType { + manifest { + attributes( + mapOf( + "Implementation-Title" to ARTIFACTID, + "Implementation-Version" to VERSIONS, + "Implementation-Package" to GROUPSID, + "Implementation-Vendor" to "minglipro", + "Implementation-Build-Time" to LocalDateTime.now() + .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSS")) + + ) + ) + } +} + repositories { mavenCentral() } @@ -79,3 +97,19 @@ publishing { } } } + +tasks.processResources { + filesMatching("META-INF/meta-data") { + expand( + mapOf( + "buildTime" to LocalDateTime.now() + .format( + DateTimeFormatter.ofPattern( + "yyyy-MM-dd HH:mm:ss.SSSSSSS" + ) + ) + ) + project.properties + ) + } +} + diff --git a/gradle.properties b/gradle.properties index a2bc37a..7ac874f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ JDKVERSIONS=1.8 GROUPSID=com.mingliqiye.utils ARTIFACTID=mingli-utils -VERSIONS=1.1.4 +VERSIONS=2.0.0 diff --git a/resources/META-INF/meta-data b/resources/META-INF/meta-data new file mode 100644 index 0000000..ed435d7 --- /dev/null +++ b/resources/META-INF/meta-data @@ -0,0 +1,7 @@ +buildTime=$buildTime +groupId=$GROUPSID +artifactId=$ARTIFACTID +version=$VERSIONS +buildJdkVersion=$JDKVERSIONS +author=MingLiPro +website=mingliqiye.com diff --git a/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..00b11b1 --- /dev/null +++ b/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +com.mingliqiye.utils.springboot.autoconfigure.AutoConfiguration diff --git a/src/com/mingliqiye/utils/bean/Factory.java b/src/com/mingliqiye/utils/bean/Factory.java index d9a76cd..24c2673 100644 --- a/src/com/mingliqiye/utils/bean/Factory.java +++ b/src/com/mingliqiye/utils/bean/Factory.java @@ -19,13 +19,13 @@ public class Factory { /** * 存储所有已注册的Bean实例,键为Bean名称,值为Bean实例 */ - public static final ConcurrentMap beans = + public static final ConcurrentMap BEANS = new ConcurrentHashMap<>(); /** * 存储按类型查找的Bean实例,键为Bean的Class对象,值为Bean实例 */ - private static final ConcurrentMap, Object> typeBeans = + private static final ConcurrentMap, Object> TYPE_BEANS = new ConcurrentHashMap<>(); /** @@ -114,11 +114,11 @@ public class Factory { ? clazz.getName() : component.value(); Object instance = clazz.getDeclaredConstructor().newInstance(); - beans.put(name, instance); - typeBeans.put(clazz, instance); + BEANS.put(name, instance); + TYPE_BEANS.put(clazz, instance); for (Class interfaceClass : clazz.getInterfaces()) { - typeBeans.putIfAbsent(interfaceClass, instance); + TYPE_BEANS.putIfAbsent(interfaceClass, instance); } } } @@ -129,7 +129,7 @@ public class Factory { * @throws Exception 如果在注入过程中发生异常 */ private static void injectDependencies() throws Exception { - for (Object bean : beans.values()) { + for (Object bean : BEANS.values()) { for (Field field : bean.getClass().getDeclaredFields()) { if (field.isAnnotationPresent(InjectBean.class)) { InjectBean inject = field.getAnnotation(InjectBean.class); @@ -161,17 +161,17 @@ public class Factory { */ private static Object findDependency(Class type, String name) { if (!name.isEmpty()) { - return beans.get(name); + return BEANS.get(name); } - Object dependency = typeBeans.get(type); + Object dependency = TYPE_BEANS.get(type); if (dependency != null) { return dependency; } - for (Class interfaceType : typeBeans.keySet()) { + for (Class interfaceType : TYPE_BEANS.keySet()) { if (type.isAssignableFrom(interfaceType)) { - return typeBeans.get(interfaceType); + return TYPE_BEANS.get(interfaceType); } } @@ -187,8 +187,8 @@ public class Factory { public static void add(Object object) { Class clazz = object.getClass(); String name = clazz.getName(); - beans.put(name, object); - typeBeans.put(clazz, object); + BEANS.put(name, object); + TYPE_BEANS.put(clazz, object); try { injectDependencies(); } catch (Exception e) { @@ -204,8 +204,8 @@ public class Factory { * @throws RuntimeException 如果在注入依赖时发生异常 */ public static void add(String name, Object object) { - beans.put(name, object); - typeBeans.put(object.getClass(), object); + BEANS.put(name, object); + TYPE_BEANS.put(object.getClass(), object); try { injectDependencies(); } catch (Exception e) { @@ -221,7 +221,7 @@ public class Factory { * @return 对应类型的Bean实例,未找到则返回null */ public static T get(Class objclass) { - return objclass.cast(typeBeans.get(objclass)); + return objclass.cast(TYPE_BEANS.get(objclass)); } /** @@ -233,7 +233,7 @@ public class Factory { * @return 对应名称和类型的Bean实例,未找到则返回null */ public static T get(String name, Class objclass) { - return objclass.cast(beans.get(name)); + return objclass.cast(BEANS.get(name)); } /** @@ -243,6 +243,6 @@ public class Factory { * @return 对应名称的Bean实例,未找到则返回null */ public static Object get(String name) { - return beans.get(name); + return BEANS.get(name); } } diff --git a/src/com/mingliqiye/utils/bean/annotation/ComponentBean.java b/src/com/mingliqiye/utils/bean/annotation/ComponentBean.java index fd38118..82de6fc 100644 --- a/src/com/mingliqiye/utils/bean/annotation/ComponentBean.java +++ b/src/com/mingliqiye/utils/bean/annotation/ComponentBean.java @@ -5,6 +5,9 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * @author MingLiPro + */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface ComponentBean { diff --git a/src/com/mingliqiye/utils/bean/annotation/InjectBean.java b/src/com/mingliqiye/utils/bean/annotation/InjectBean.java index 87ab334..9920e61 100644 --- a/src/com/mingliqiye/utils/bean/annotation/InjectBean.java +++ b/src/com/mingliqiye/utils/bean/annotation/InjectBean.java @@ -5,6 +5,9 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * @author MingLiPro + */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface InjectBean { diff --git a/src/com/mingliqiye/utils/bean/springboot/SpringBeanUtil.java b/src/com/mingliqiye/utils/bean/springboot/SpringBeanUtil.java index 0deb223..57aaeed 100644 --- a/src/com/mingliqiye/utils/bean/springboot/SpringBeanUtil.java +++ b/src/com/mingliqiye/utils/bean/springboot/SpringBeanUtil.java @@ -19,6 +19,9 @@ import org.springframework.stereotype.Component; @Component public class SpringBeanUtil implements ApplicationContextAware { + public static final String PACKAGE_NAME = + SpringBeanUtil.class.getPackage().getName(); + /** * 获取applicationContext */ diff --git a/src/com/mingliqiye/utils/bytes/ByteUtil.java b/src/com/mingliqiye/utils/bytes/ByteUtil.java index 2af4d42..31b75ff 100644 --- a/src/com/mingliqiye/utils/bytes/ByteUtil.java +++ b/src/com/mingliqiye/utils/bytes/ByteUtil.java @@ -11,6 +11,16 @@ import java.util.stream.Collectors; */ public class ByteUtil { + public static final byte ESC_ASC = 0x1A; + public static final byte ESC_DESC = 0x1B; + public static final byte ESC_NONE = 0x00; + public static final byte ESC_START = 0x01; + public static final byte ESC_END = 0x02; + public static final byte ESC_ESC = 0x03; + public static final byte ESC_CONTROL = 0x04; + public static final byte ESC_DATA = 0x05; + public static final byte ESC_RESERVED = 0x06; + /** * 将字节数组转换为十六进制字符串列表 *

diff --git a/src/com/mingliqiye/utils/collection/ForEach.java b/src/com/mingliqiye/utils/collection/ForEach.java index 1fc5763..03f4dde 100644 --- a/src/com/mingliqiye/utils/collection/ForEach.java +++ b/src/com/mingliqiye/utils/collection/ForEach.java @@ -7,6 +7,7 @@ import java.util.concurrent.ConcurrentMap; /** * ListsAMaps 工具类提供对集合和映射的增强遍历功能。 * 包含多个重载的 forEach 方法,支持带索引的遍历操作。 + * @author MingLiPro */ public class ForEach { @@ -165,6 +166,191 @@ public class ForEach { } } + public static void forEach(Consumer action, T... objects) { + int i = 0; + while (i < objects.length) { + T object = objects[i]; + action.call(object, i); + i++; + } + } + + public static void forEach(T[] objects, Consumer action) { + forEach(action, objects); + } + + public static void forEach( + T[] objects, + java.util.function.Consumer action + ) { + forEach(action, objects); + } + + public static void forEach( + java.util.function.Consumer action, + T... objects + ) { + forEach((t, i) -> action.accept(t), objects); + } + + public static void forEach(int[] objects, Consumer action) { + forEach(action, objects); + } + + private static void forEach(Consumer action, int... objects) { + for (int i = 0; i < objects.length; i++) { + action.call(objects[i], i); + } + } + + private static void forEach( + java.util.function.Consumer action, + int... objects + ) { + for (Integer object : objects) { + action.accept(object); + } + } + + public static void forEach(byte[] objects, Consumer action) { + forEach(action, objects); + } + + private static void forEach(Consumer action, byte... objects) { + for (int i = 0; i < objects.length; i++) { + action.call(objects[i], i); + } + } + + private static void forEach( + java.util.function.Consumer action, + byte... objects + ) { + for (Byte object : objects) { + action.accept(object); + } + } + + // short类型 + public static void forEach(short[] objects, Consumer action) { + forEach(action, objects); + } + + private static void forEach(Consumer action, short... objects) { + for (int i = 0; i < objects.length; i++) { + action.call(objects[i], i); + } + } + + private static void forEach( + java.util.function.Consumer action, + short... objects + ) { + for (short object : objects) { + action.accept(object); + } + } + + // long类型 + public static void forEach(long[] objects, Consumer action) { + forEach(action, objects); + } + + private static void forEach(Consumer action, long... objects) { + for (int i = 0; i < objects.length; i++) { + action.call(objects[i], i); + } + } + + private static void forEach( + java.util.function.Consumer action, + long... objects + ) { + for (long object : objects) { + action.accept(object); + } + } + + // float类型 + public static void forEach(float[] objects, Consumer action) { + forEach(action, objects); + } + + private static void forEach(Consumer action, float... objects) { + for (int i = 0; i < objects.length; i++) { + action.call(objects[i], i); + } + } + + private static void forEach( + java.util.function.Consumer action, + float... objects + ) { + for (float object : objects) { + action.accept(object); + } + } + + // double类型 + public static void forEach(double[] objects, Consumer action) { + forEach(action, objects); + } + + private static void forEach(Consumer action, double... objects) { + for (int i = 0; i < objects.length; i++) { + action.call(objects[i], i); + } + } + + private static void forEach( + java.util.function.Consumer action, + double... objects + ) { + for (double object : objects) { + action.accept(object); + } + } + + // char类型 + public static void forEach(char[] objects, Consumer action) { + forEach(action, objects); + } + + private static void forEach(Consumer action, char... objects) { + for (int i = 0; i < objects.length; i++) { + action.call(objects[i], i); + } + } + + private static void forEach( + java.util.function.Consumer action, + char... objects + ) { + for (char object : objects) { + action.accept(object); + } + } + + // boolean类型 + public static void forEach(boolean[] objects, Consumer action) { + forEach(action, objects); + } + + private static void forEach(Consumer action, boolean... objects) { + for (int i = 0; i < objects.length; i++) { + action.call(objects[i], i); + } + } + + private static void forEach( + java.util.function.Consumer action, + boolean... objects + ) { + for (boolean object : objects) { + action.accept(object); + } + } + /** * 自定义消费者接口,用于接收元素值和索引。 * diff --git a/src/com/mingliqiye/utils/hash/HashUtils.java b/src/com/mingliqiye/utils/hash/HashUtils.java index 3a7195b..b16073e 100644 --- a/src/com/mingliqiye/utils/hash/HashUtils.java +++ b/src/com/mingliqiye/utils/hash/HashUtils.java @@ -39,7 +39,7 @@ public class HashUtils { MessageDigest digest = MessageDigest.getInstance(algorithm); try (FileInputStream fis = new FileInputStream(file)) { - byte[] buffer = new byte[8192]; // 8KB 缓冲区 + byte[] buffer = new byte[8192]; int bytesRead; // 分块读取文件内容并更新摘要 diff --git a/src/com/mingliqiye/utils/jna/FieldStructure.java b/src/com/mingliqiye/utils/jna/FieldStructure.java new file mode 100644 index 0000000..44a3a45 --- /dev/null +++ b/src/com/mingliqiye/utils/jna/FieldStructure.java @@ -0,0 +1,37 @@ +package com.mingliqiye.utils.jna; + +import com.sun.jna.Structure; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.List; + +/** + * @author MingLiPro + */ +public class FieldStructure extends Structure { + + @Override + protected List getFieldOrder() { + List fieldOrderList = new ArrayList(); + for ( + Class cls = getClass(); + !cls.equals(FieldStructure.class); + cls = cls.getSuperclass() + ) { + Field[] fields = cls.getDeclaredFields(); + int modifiers; + for (Field field : fields) { + modifiers = field.getModifiers(); + if ( + Modifier.isStatic(modifiers) || + !Modifier.isPublic(modifiers) + ) { + continue; + } + fieldOrderList.add(field.getName()); + } + } + return fieldOrderList; + } +} diff --git a/src/com/mingliqiye/utils/jna/time/WinKernel32.java b/src/com/mingliqiye/utils/jna/time/WinKernel32.java new file mode 100644 index 0000000..b20de88 --- /dev/null +++ b/src/com/mingliqiye/utils/jna/time/WinKernel32.java @@ -0,0 +1,15 @@ +package com.mingliqiye.utils.jna.time; + +import com.sun.jna.Library; +import com.sun.jna.Native; +import com.sun.jna.ptr.LongByReference; + +public interface WinKernel32 extends Library { + static WinKernel32 load() { + return Native.load("kernel32", WinKernel32.class); + } + + boolean QueryPerformanceCounter(LongByReference lpPerformanceCount); + boolean QueryPerformanceFrequency(LongByReference lpFrequency); + void GetSystemTimePreciseAsFileTime(byte[] lpSystemTimeAsFileTime); +} diff --git a/src/com/mingliqiye/utils/random/RandomBytes.java b/src/com/mingliqiye/utils/random/RandomBytes.java new file mode 100644 index 0000000..13700c4 --- /dev/null +++ b/src/com/mingliqiye/utils/random/RandomBytes.java @@ -0,0 +1,31 @@ +package com.mingliqiye.utils.random; + +import com.mingliqiye.utils.collection.ForEach; + +/** + * @author MingLiPro + */ +public class RandomBytes { + + public static byte[] randomBytes(int length) { + byte[] bytes = new byte[length]; + ForEach.forEach(bytes, (b, i) -> + bytes[i] = randomByte((byte) 0x00, (byte) 0xff) + ); + return bytes; + } + + public static byte randomByte(byte from, byte to) { + int fromInt = from & 0xFF; + int toInt = to & 0xFF; + int randomValue = RandomInt.randomInt(fromInt, toInt); + return (byte) (randomValue & 0xFF); + } + + public static byte randomByteNoHave(byte from, byte to) { + int fromInt = from & 0xFF; + int toInt = to & 0xFF; + int randomValue = RandomInt.randomIntNoHave(fromInt, toInt); + return (byte) (randomValue & 0xFF); + } +} diff --git a/src/com/mingliqiye/utils/random/RandomInt.java b/src/com/mingliqiye/utils/random/RandomInt.java new file mode 100644 index 0000000..ed7245a --- /dev/null +++ b/src/com/mingliqiye/utils/random/RandomInt.java @@ -0,0 +1,37 @@ +package com.mingliqiye.utils.random; + +import java.util.concurrent.ThreadLocalRandom; + +/** + * @author MingLiPro + */ +public class RandomInt { + + /** + * 生成指定范围内的随机整数 + * @param min 最小值(包含) + * @param max 最大值(不包含) + * @return 随机整数 + */ + public static int randomIntNoHave(int min, int max) { + if (min > max) { + int t = min; + min = max; + max = t; + } + if (min == max) { + return min; + } + return ThreadLocalRandom.current().nextInt(min, max); + } + + /** + * 生成指定范围内的随机整数 + * @param min 最小值(包含) + * @param max 最大值(包含) + * @return 随机整数 + */ + public static int randomInt(int min, int max) { + return randomIntNoHave(min, ++max); + } +} diff --git a/src/com/mingliqiye/utils/random/RandomString.java b/src/com/mingliqiye/utils/random/RandomString.java new file mode 100644 index 0000000..71ce35b --- /dev/null +++ b/src/com/mingliqiye/utils/random/RandomString.java @@ -0,0 +1,24 @@ +package com.mingliqiye.utils.random; + +/** + * @author MingLiPro + */ +public class RandomString { + + public static String randomString(int length, String chars) { + String[] charsd = chars.split(""); + StringBuilder sb = new StringBuilder(length); + for (int i = 0; i < length; i++) { + int index = RandomInt.randomInt(0, charsd.length - 1); + sb.append(charsd[index]); + } + return sb.toString(); + } + + public static String randomString(int length) { + return randomString( + length, + "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + ); + } +} diff --git a/src/com/mingliqiye/utils/springboot/autoconfigure/AutoConfiguration.java b/src/com/mingliqiye/utils/springboot/autoconfigure/AutoConfiguration.java new file mode 100644 index 0000000..906a2d9 --- /dev/null +++ b/src/com/mingliqiye/utils/springboot/autoconfigure/AutoConfiguration.java @@ -0,0 +1,74 @@ +package com.mingliqiye.utils.springboot.autoconfigure; + +import com.mingliqiye.utils.collection.ForEach; +import com.mingliqiye.utils.time.DateTime; +import com.mingliqiye.utils.time.Formatter; +import java.io.IOException; +import java.io.InputStream; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * @author MingLiPro + */ +@Configuration +@EnableConfigurationProperties(AutoConfiguration.class) +public class AutoConfiguration { + + private static String banner = + "---------------------------------------------------------\n" + + "| $$\\ $$\\ $$\\ $$\\ $$\\ $$$$$$$$\\ $$$$$$\\ |\n" + + "| $$$\\ $$$ |$$ | $$ | $$ |\\__$$ __|$$ __$$\\ |\n" + + "| $$$$\\ $$$$ |$$ | $$ | $$ | $$ | $$ / \\__| |\n" + + "| $$\\$$\\$$ $$ |$$ | $$ | $$ | $$ | \\$$$$$$\\ |\n" + + "| $$ \\$$$ $$ |$$ | $$ | $$ | $$ | \\____$$\\ |\n" + + "| $$ |\\$ /$$ |$$ | $$ | $$ | $$ | $$\\ $$ | |\n" + + "| $$ | \\_/ $$ |$$$$$$$$\\\\$$$$$$ | $$ | \\$$$$$$ | |\n" + + "| \\__| \\__|\\________|\\______/ \\__| \\______/ |\n"; + + public AutoConfiguration() throws IOException { + print(); + } + + public static void main(String[] args) throws IOException { + new AutoConfiguration(); + } + + public void print() throws IOException { + InputStream inputStream = AutoConfiguration.class.getResourceAsStream( + "/META-INF/meta-data" + ); + int readlen; + byte[] buffer = new byte[1024]; + StringBuilder metaData = new StringBuilder(); + while ((readlen = inputStream.read(buffer)) != -1) { + metaData.append(new String(buffer, 0, readlen)); + } + ForEach.forEach(metaData.toString().split("\n"), (s, i) -> { + String[] d = s.trim().split("=", 2); + if (d.length >= 2) { + String content = "| " + d[0] + ": " + d[1]; + // 直接计算需要的空格数来对齐 + int targetLength = 56; // 为右侧的 | 留出空间 + if (content.length() < targetLength) { + int spacesNeeded = targetLength - content.length(); + StringBuilder da = new StringBuilder(content); + for (int ia = 0; ia < spacesNeeded; ia++) { + da.append(" "); + } + banner += da + "|\n"; + } else { + banner += content.substring(0, targetLength) + "|\n"; + } + } + }); + + System.out.printf( + banner, + DateTime.now().format(Formatter.STANDARD_DATETIME_MILLISECOUND7) + ); + System.out.println( + "---------------------------------------------------------" + ); + } +} diff --git a/src/com/mingliqiye/utils/stream/ListStream.java b/src/com/mingliqiye/utils/stream/ListStream.java new file mode 100644 index 0000000..7c39de4 --- /dev/null +++ b/src/com/mingliqiye/utils/stream/ListStream.java @@ -0,0 +1,1318 @@ +package com.mingliqiye.utils.stream; + +import com.mingliqiye.utils.collection.ForEach; +import com.mingliqiye.utils.collection.Lists; +import com.mingliqiye.utils.random.RandomInt; +import java.util.*; +import java.util.concurrent.ConcurrentMap; +import java.util.function.*; +import java.util.stream.*; +import org.jetbrains.annotations.NotNull; + +/** + * 自定义的 ListStream 实现类,用于对集合进行流式操作。 + * 该类实现了 Java 标准库中的 ListStream 接口,并基于 List 数据结构提供了一系列流式处理方法。 + * + * @author MingLiPro + * @param 流中元素的类型 + */ +public class ListStream implements java.util.stream.Stream { + + private final List list; + + /** + * 构造方法,初始化 ListStream 实例。 + * + * @param list 用于构造 ListStream 的列表数据,如果为 null 则使用空列表 + */ + private ListStream(List list) { + this.list = list != null ? list : Lists.newArrayList(); + } + + /** + * 创建一个收集器,将元素收集到指定类型的集合中。 + * + * @param collectionFactory 用于创建目标集合的工厂函数 + * @param 元素类型 + * @param 目标集合类型 + * @return 收集器实例 + */ + public static > Collector toCollection( + @NotNull Supplier collectionFactory + ) { + return Collectors.toCollection(collectionFactory); + } + + /** + * 创建一个收集器,将元素收集到 List 中。 + * + * @param 元素类型 + * @return 收集器实例 + */ + public static Collector> toList() { + return Collectors.toList(); + } + + /** + * 创建一个收集器,将元素收集到 Set 中。 + * + * @param 元素类型 + * @return 收集器实例 + */ + public static Collector> toSet() { + return Collectors.toSet(); + } + + /** + * 创建一个收集器,将字符序列连接为字符串。 + * + * @return 收集器实例 + */ + public static Collector joining() { + return Collectors.joining(); + } + + /** + * 创建一个收集器,将字符序列使用指定分隔符连接为字符串。 + * + * @param delimiter 分隔符 + * @return 收集器实例 + */ + public static Collector joining( + @NotNull CharSequence delimiter + ) { + return Collectors.joining(delimiter); + } + + /** + * 创建一个收集器,将字符序列使用指定分隔符、前缀和后缀连接为字符串。 + * + * @param delimiter 分隔符 + * @param prefix 前缀 + * @param suffix 后缀 + * @return 收集器实例 + */ + public static Collector joining( + @NotNull CharSequence delimiter, + @NotNull CharSequence prefix, + @NotNull CharSequence suffix + ) { + return Collectors.joining(delimiter, prefix, suffix); + } + + /** + * 创建一个收集器,先对元素进行映射,再使用下游收集器收集。 + * + * @param mapper 映射函数 + * @param downstream 下游收集器 + * @param 输入元素类型 + * @param 映射后元素类型 + * @param 下游收集器中间类型 + * @param 结果类型 + * @return 收集器实例 + */ + public static Collector mapping( + @NotNull Function mapper, + @NotNull Collector downstream + ) { + return Collectors.mapping(mapper, downstream); + } + + /** + * 创建一个收集器,在下游收集完成后应用 finisher 函数。 + * + * @param downstream 下游收集器 + * @param finisher 完成后应用的函数 + * @param 输入元素类型 + * @param 下游收集器中间类型 + * @param 下游收集器结果类型 + * @param 最终结果类型 + * @return 收集器实例 + */ + public static Collector collectingAndThen( + @NotNull Collector downstream, + @NotNull Function finisher + ) { + return Collectors.collectingAndThen(downstream, finisher); + } + + /** + * 创建一个收集器,统计元素数量。 + * + * @param 元素类型 + * @return 收集器实例 + */ + public static Collector counting() { + return Collectors.counting(); + } + + /** + * 创建一个收集器,找出最小元素。 + * + * @param comparator 比较器 + * @param 元素类型 + * @return 收集器实例 + */ + public static Collector> minBy( + @NotNull Comparator comparator + ) { + return Collectors.minBy(comparator); + } + + /** + * 创建一个收集器,找出最大元素。 + * + * @param comparator 比较器 + * @param 元素类型 + * @return 收集器实例 + */ + public static Collector> maxBy( + @NotNull Comparator comparator + ) { + return Collectors.maxBy(comparator); + } + + /** + * 创建一个收集器,对元素映射为 int 后求和。 + * + * @param mapper 映射函数 + * @param 元素类型 + * @return 收集器实例 + */ + public static Collector summingInt( + @NotNull ToIntFunction mapper + ) { + return Collectors.summingInt(mapper); + } + + /** + * 创建一个收集器,对元素映射为 long 后求和。 + * + * @param mapper 映射函数 + * @param 元素类型 + * @return 收集器实例 + */ + public static Collector summingLong( + @NotNull ToLongFunction mapper + ) { + return Collectors.summingLong(mapper); + } + + /** + * 创建一个收集器,对元素映射为 double 后求和。 + * + * @param mapper 映射函数 + * @param 元素类型 + * @return 收集器实例 + */ + public static Collector summingDouble( + @NotNull ToDoubleFunction mapper + ) { + return Collectors.summingDouble(mapper); + } + + /** + * 创建一个收集器,对元素映射为 int 后计算平均值。 + * + * @param mapper 映射函数 + * @param 元素类型 + * @return 收集器实例 + */ + public static Collector averagingInt( + @NotNull ToIntFunction mapper + ) { + return Collectors.averagingInt(mapper); + } + + /** + * 创建一个收集器,对元素映射为 long 后计算平均值。 + * + * @param mapper 映射函数 + * @param 元素类型 + * @return 收集器实例 + */ + public static Collector averagingLong( + @NotNull ToLongFunction mapper + ) { + return Collectors.averagingLong(mapper); + } + + /** + * 创建一个收集器,对元素映射为 double 后计算平均值。 + * + * @param mapper 映射函数 + * @param 元素类型 + * @return 收集器实例 + */ + public static Collector averagingDouble( + @NotNull ToDoubleFunction mapper + ) { + return Collectors.averagingDouble(mapper); + } + + /** + * 创建一个收集器,使用指定初始值和操作符对元素进行归约。 + * + * @param identity 初始值 + * @param op 操作符 + * @param 元素类型 + * @return 收集器实例 + */ + public static Collector reducing( + T identity, + @NotNull BinaryOperator op + ) { + return Collectors.reducing(identity, op); + } + + /** + * 创建一个收集器,使用指定操作符对元素进行归约。 + * + * @param op 操作符 + * @param 元素类型 + * @return 收集器实例 + */ + public static Collector> reducing( + @NotNull BinaryOperator op + ) { + return Collectors.reducing(op); + } + + /** + * 创建一个收集器,先对元素进行映射,再使用指定初始值和操作符进行归约。 + * + * @param identity 初始值 + * @param mapper 映射函数 + * @param op 操作符 + * @param 输入元素类型 + * @param 映射后元素类型 + * @return 收集器实例 + */ + public static Collector reducing( + U identity, + @NotNull Function mapper, + @NotNull BinaryOperator op + ) { + return Collectors.reducing(identity, mapper, op); + } + + /** + * 创建一个收集器,根据分类器对元素进行分组。 + * + * @param classifier 分类器函数 + * @param 元素类型 + * @param 分类键类型 + * @return 收集器实例 + */ + public static Collector< + T, + ?, + @NotNull Map> + > groupingBy(@NotNull Function classifier) { + return Collectors.groupingBy(classifier); + } + + /** + * 创建一个收集器,根据分类器对元素进行分组,并使用下游收集器处理每组元素。 + * + * @param classifier 分类器函数 + * @param downstream 下游收集器 + * @param 元素类型 + * @param 分类键类型 + * @param 下游收集器中间类型 + * @param 下游收集器结果类型 + * @return 收集器实例 + */ + public static Collector> groupingBy( + @NotNull Function classifier, + @NotNull Collector downstream + ) { + return Collectors.groupingBy(classifier, downstream); + } + + /** + * 创建一个收集器,根据分类器对元素进行分组,使用指定的 Map 工厂和下游收集器。 + * + * @param classifier 分类器函数 + * @param mapFactory Map 工厂函数 + * @param downstream 下游收集器 + * @param 元素类型 + * @param 分类键类型 + * @param 下游收集器结果类型 + * @param 下游收集器中间类型 + * @param 目标 Map 类型 + * @return 收集器实例 + */ + public static > Collector< + T, + ?, + M + > groupingBy( + @NotNull Function classifier, + @NotNull Supplier mapFactory, + @NotNull Collector downstream + ) { + return Collectors.groupingBy(classifier, mapFactory, downstream); + } + + /** + * 创建一个并发收集器,根据分类器对元素进行分组。 + * + * @param classifier 分类器函数 + * @param 元素类型 + * @param 分类键类型 + * @return 收集器实例 + */ + public static Collector< + T, + ?, + @NotNull ConcurrentMap> + > groupingByConcurrent( + @NotNull Function classifier + ) { + return Collectors.groupingByConcurrent(classifier); + } + + /** + * 创建一个并发收集器,根据分类器对元素进行分组,并使用下游收集器处理每组元素。 + * + * @param classifier 分类器函数 + * @param downstream 下游收集器 + * @param 元素类型 + * @param 分类键类型 + * @param 下游收集器中间类型 + * @param 下游收集器结果类型 + * @return 收集器实例 + */ + public static Collector< + T, + ?, + @NotNull ConcurrentMap + > groupingByConcurrent( + @NotNull Function classifier, + @NotNull Collector downstream + ) { + return Collectors.groupingByConcurrent(classifier, downstream); + } + + /** + * 创建一个并发收集器,根据分类器对元素进行分组,使用指定的 Map 工厂和下游收集器。 + * + * @param classifier 分类器函数 + * @param mapFactory Map 工厂函数 + * @param downstream 下游收集器 + * @param 元素类型 + * @param 分类键类型 + * @param 下游收集器结果类型 + * @param 下游收集器中间类型 + * @param 目标 Map 类型 + * @return 收集器实例 + */ + public static > Collector< + T, + ?, + M + > groupingByConcurrent( + @NotNull Function classifier, + @NotNull Supplier mapFactory, + @NotNull Collector downstream + ) { + return Collectors.groupingByConcurrent( + classifier, + mapFactory, + downstream + ); + } + + /** + * 创建一个收集器,根据谓词条件对元素进行分区。 + * + * @param predicate 谓词函数 + * @param 元素类型 + * @return 收集器实例 + */ + public static Collector< + T, + ?, + @NotNull Map<@NotNull Boolean, @NotNull List> + > partitioningBy(@NotNull Predicate predicate) { + return Collectors.partitioningBy(predicate); + } + + /** + * 创建一个收集器,根据谓词条件对元素进行分区,并使用下游收集器处理每组元素。 + * + * @param predicate 谓词函数 + * @param downstream 下游收集器 + * @param 元素类型 + * @param 下游收集器结果类型 + * @param 下游收集器中间类型 + * @return 收集器实例 + */ + public static Collector< + T, + ?, + @NotNull Map<@NotNull Boolean, D> + > partitioningBy( + @NotNull Predicate predicate, + @NotNull Collector downstream + ) { + return Collectors.partitioningBy(predicate, downstream); + } + + /** + * 创建一个收集器,将元素转换为 Map。 + * + * @param keyMapper 键映射函数 + * @param valueMapper 值映射函数 + * @param 元素类型 + * @param 键类型 + * @param 值类型 + * @return 收集器实例 + */ + public static Collector> toMap( + @NotNull Function keyMapper, + @NotNull Function valueMapper + ) { + return Collectors.toMap(keyMapper, valueMapper); + } + + /** + * 创建一个收集器,将元素转换为 Map,并指定键冲突时的合并函数。 + * + * @param keyMapper 键映射函数 + * @param valueMapper 值映射函数 + * @param mergeFunction 键冲突合并函数 + * @param 元素类型 + * @param 键类型 + * @param 值类型 + * @return 收集器实例 + */ + public static Collector> toMap( + @NotNull Function keyMapper, + @NotNull Function valueMapper, + @NotNull BinaryOperator mergeFunction + ) { + return Collectors.toMap(keyMapper, valueMapper, mergeFunction); + } + + /** + * 创建一个收集器,将元素转换为 Map,指定键冲突合并函数和 Map 工厂。 + * + * @param keyMapper 键映射函数 + * @param valueMapper 值映射函数 + * @param mergeFunction 键冲突合并函数 + * @param mapSupplier Map 工厂函数 + * @param 元素类型 + * @param 键类型 + * @param 值类型 + * @param 目标 Map 类型 + * @return 收集器实例 + */ + public static > Collector toMap( + @NotNull Function keyMapper, + @NotNull Function valueMapper, + @NotNull BinaryOperator mergeFunction, + @NotNull Supplier mapSupplier + ) { + return Collectors.toMap( + keyMapper, + valueMapper, + mergeFunction, + mapSupplier + ); + } + + /** + * 创建一个并发收集器,将元素转换为 ConcurrentMap。 + * + * @param keyMapper 键映射函数 + * @param valueMapper 值映射函数 + * @param 元素类型 + * @param 键类型 + * @param 值类型 + * @return 收集器实例 + */ + public static Collector< + T, + ?, + @NotNull ConcurrentMap + > toConcurrentMap( + @NotNull Function keyMapper, + @NotNull Function valueMapper + ) { + return Collectors.toConcurrentMap(keyMapper, valueMapper); + } + + /** + * 创建一个并发收集器,将元素转换为 ConcurrentMap,并指定键冲突时的合并函数。 + * + * @param keyMapper 键映射函数 + * @param valueMapper 值映射函数 + * @param mergeFunction 键冲突合并函数 + * @param 元素类型 + * @param 键类型 + * @param 值类型 + * @return 收集器实例 + */ + public static Collector< + T, + ?, + @NotNull ConcurrentMap + > toConcurrentMap( + @NotNull Function keyMapper, + @NotNull Function valueMapper, + @NotNull BinaryOperator mergeFunction + ) { + return Collectors.toConcurrentMap( + keyMapper, + valueMapper, + mergeFunction + ); + } + + /** + * 创建一个并发收集器,将元素转换为 ConcurrentMap,指定键冲突合并函数和 Map 工厂。 + * + * @param keyMapper 键映射函数 + * @param valueMapper 值映射函数 + * @param mergeFunction 键冲突合并函数 + * @param mapSupplier Map 工厂函数 + * @param 元素类型 + * @param 键类型 + * @param 值类型 + * @param 目标 Map 类型 + * @return 收集器实例 + */ + public static > Collector< + T, + ?, + M + > toConcurrentMap( + @NotNull Function keyMapper, + @NotNull Function valueMapper, + @NotNull BinaryOperator mergeFunction, + @NotNull Supplier mapSupplier + ) { + return Collectors.toConcurrentMap( + keyMapper, + valueMapper, + mergeFunction, + mapSupplier + ); + } + + /** + * 创建一个收集器,对元素映射为 int 后生成统计信息。 + * + * @param mapper 映射函数 + * @param 元素类型 + * @return 收集器实例 + */ + public static Collector< + T, + ?, + @NotNull IntSummaryStatistics + > summarizingInt(@NotNull ToIntFunction mapper) { + return Collectors.summarizingInt(mapper); + } + + /** + * 创建一个收集器,对元素映射为 long 后生成统计信息。 + * + * @param mapper 映射函数 + * @param 元素类型 + * @return 收集器实例 + */ + public static Collector< + T, + ?, + @NotNull LongSummaryStatistics + > summarizingLong(@NotNull ToLongFunction mapper) { + return Collectors.summarizingLong(mapper); + } + + /** + * 创建一个收集器,对元素映射为 double 后生成统计信息。 + * + * @param mapper 映射函数 + * @param 元素类型 + * @return 收集器实例 + */ + public static Collector< + T, + ?, + @NotNull DoubleSummaryStatistics + > summarizingDouble(@NotNull ToDoubleFunction mapper) { + return Collectors.summarizingDouble(mapper); + } + + /** + * 创建一个包含指定元素的 ListStream。 + * + * @param ts 可变参数,表示要包含在 ListStream 中的元素 + * @param 元素类型 + * @return 包含指定元素的新 ListStream 实例 + */ + @SafeVarargs + public static ListStream of(T... ts) { + return new ListStream<>(Lists.newArrayList(ts)); + } + + /** + * 创建一个包含指定列表元素的 ListStream。 + * + * @param ts 列表,表示要包含在 ListStream 中的元素 + * @param 元素类型 + * @return 包含指定元素的新 ListStream 实例 + */ + public static ListStream of(List ts) { + return new ListStream<>(Lists.newArrayList(ts)); + } + + /** + * 根据给定的谓词条件过滤流中的元素。 + * + * @param predicate 用于测试元素是否应保留的谓词函数 + * @return 包含满足条件元素的新 ListStream 实例 + */ + @Override + public ListStream filter(Predicate predicate) { + List result = Lists.newArrayList(); + for (T item : list) { + if (predicate.test(item)) { + result.add(item); + } + } + return new ListStream<>(result); + } + + /** + * 根据属性提取器和目标值过滤流中的元素。 + * + * @param propertyExtractor 属性提取函数 + * @param targetValue 目标值 + * @return 包含满足条件元素的新 ListStream 实例 + */ + public ListStream filter( + Function propertyExtractor, + Object targetValue + ) { + List result = Lists.newArrayList(); + for (T item : list) { + if (Objects.equals(propertyExtractor.apply(item), targetValue)) { + result.add(item); + } + } + return new ListStream<>(result); + } + + /** + * 将流中的每个元素通过映射函数转换为另一种类型。 + * + * @param mapper 映射函数,将元素从类型 T 转换为类型 R + * @param 映射后元素的类型 + * @return 包含转换后元素的新 ListStream 实例 + */ + @Override + public ListStream map(Function mapper) { + List result = Lists.newArrayList(); + for (T item : list) { + result.add(mapper.apply(item)); + } + return new ListStream<>(result); + } + + /** + * 将流中的元素转换为数组。 + * + * @return 包含流中所有元素的数组 + */ + public T[] array() { + return (T[]) list.toArray(); + } + + /** + * 获取流中的元素列表。 + * + * @return 包含流中所有元素的列表 + */ + public List list() { + return list; + } + + /** + * 将流中的每个元素通过映射函数转换为 int 类型。 + * + * @param mapper 映射函数,将元素从类型 T 转换为 int + * @return 转换后的 IntStream 实例 + */ + @Override + public IntStream mapToInt(ToIntFunction mapper) { + return list.stream().mapToInt(mapper); + } + + /** + * 将流中的每个元素通过映射函数转换为 long 类型。 + * + * @param mapper 映射函数,将元素从类型 T 转换为 long + * @return 转换后的 LongStream 实例 + */ + @Override + public LongStream mapToLong(ToLongFunction mapper) { + return list.stream().mapToLong(mapper); + } + + /** + * 将流中的每个元素通过映射函数转换为 double 类型。 + * + * @param mapper 映射函数,将元素从类型 T 转换为 double + * @return 转换后的 DoubleStream 实例 + */ + @Override + public DoubleStream mapToDouble(ToDoubleFunction mapper) { + return list.stream().mapToDouble(mapper); + } + + /** + * 将流中的每个元素通过映射函数转换为另一个流,并将所有结果流合并为一个流。 + * + * @param mapper 映射函数,将元素从类型 T 转换为另一个 ListStream + * @param 映射后流中元素的类型 + * @return 合并后的 ListStream 实例 + */ + @Override + public ListStream flatMap( + Function< + ? super T, + ? extends java.util.stream.Stream + > mapper + ) { + List result = Lists.newArrayList(); + for (T item : list) { + java.util.stream.Stream stream = mapper.apply(item); + if (stream != null) { + stream.forEach(result::add); + } + } + return new ListStream<>(result); + } + + /** + * 将流中的每个元素通过映射函数转换为 IntStream,并将所有结果流合并为一个流。 + * + * @param mapper 映射函数,将元素从类型 T 转换为 IntStream + * @return 合并后的 IntStream 实例 + */ + @Override + public IntStream flatMapToInt( + Function mapper + ) { + return list.stream().flatMapToInt(mapper); + } + + /** + * 将流中的每个元素通过映射函数转换为 LongStream,并将所有结果流合并为一个流。 + * + * @param mapper 映射函数,将元素从类型 T 转换为 LongStream + * @return 合并后的 LongStream 实例 + */ + @Override + public LongStream flatMapToLong( + Function mapper + ) { + return list.stream().flatMapToLong(mapper); + } + + /** + * 将流中的每个元素通过映射函数转换为 DoubleStream,并将所有结果流合并为一个流。 + * + * @param mapper 映射函数,将元素从类型 T 转换为 DoubleStream + * @return 合并后的 DoubleStream 实例 + */ + @Override + public DoubleStream flatMapToDouble( + Function mapper + ) { + return list.stream().flatMapToDouble(mapper); + } + + /** + * 去除流中重复的元素,保持原有顺序。 + * + * @return 包含去重后元素的新 ListStream 实例 + */ + @Override + public ListStream distinct() { + Set seen = new LinkedHashSet<>(list); + return new ListStream<>(new ArrayList<>(seen)); + } + + /** + * 对流中的元素进行自然排序。 + * + * @return 排序后的新 ListStream 实例 + */ + @Override + public ListStream sorted() { + List sortedList = Lists.newArrayList(list); + Collections.sort((List) sortedList); + return new ListStream<>(sortedList); + } + + /** + * 根据给定的比较器对流中的元素进行排序。 + * + * @param comparator 用于比较元素的比较器 + * @return 排序后的新 ListStream 实例 + */ + @Override + public ListStream sorted(Comparator comparator) { + List sortedList = Lists.newArrayList(list); + sortedList.sort(comparator); + return new ListStream<>(sortedList); + } + + /** + * 对流中的每个元素执行指定的操作,但不改变流本身。 + * + * @param action 要对每个元素执行的操作 + * @return 当前 ListStream 实例 + */ + @Override + public ListStream peek(Consumer action) { + for (T item : list) { + action.accept(item); + } + return this; + } + + /** + * 截取流中前 maxSize 个元素组成新的流。 + * + * @param maxSize 要截取的最大元素数量 + * @return 截取后的新 ListStream 实例 + * @throws IllegalArgumentException 如果 maxSize 为负数 + */ + @Override + public ListStream limit(long maxSize) { + if (maxSize < 0) { + throw new IllegalArgumentException("maxSize must be non-negative"); + } + if (maxSize == 0) { + return new ListStream<>(Lists.newArrayList()); + } + + List limitedList = Lists.newArrayList(); + long count = 0; + for (T item : list) { + if (count >= maxSize) { + break; + } + limitedList.add(item); + count++; + } + return new ListStream<>(limitedList); + } + + /** + * 跳过流中前 n 个元素,返回剩余元素组成的新流。 + * + * @param n 要跳过的元素数量 + * @return 跳过后的新 ListStream 实例 + * @throws IllegalArgumentException 如果 n 为负数 + */ + @Override + public ListStream skip(long n) { + if (n < 0) { + throw new IllegalArgumentException("n must be non-negative"); + } + if (n == 0) { + return new ListStream<>(Lists.newArrayList(list)); + } + + List skippedList = Lists.newArrayList(); + long count = 0; + for (T item : list) { + if (count >= n) { + skippedList.add(item); + } + count++; + } + return new ListStream<>(skippedList); + } + + /** + * 对流中的每个元素执行指定的操作。 + * + * @param action 要对每个元素执行的操作 + */ + @Override + public void forEach(Consumer action) { + ForEach.forEach(list, action); + } + + public void forEach( + com.mingliqiye.utils.collection.ForEach.Consumer action + ) { + ForEach.forEach(list, action); + } + + /** + * 按照元素出现的顺序对流中的每个元素执行指定的操作。 + * + * @param action 要对每个元素执行的操作 + */ + @Override + public void forEachOrdered(Consumer action) { + forEach(action); + } + + /** + * 将流中的元素转换为数组。 + * + * @return 包含流中所有元素的数组 + */ + @Override + public @NotNull Object@NotNull [] toArray() { + return list.toArray(); + } + + /** + * 使用指定的生成器函数将流中的元素转换为数组。 + * + * @param generator 用于生成目标数组的函数 + * @param 数组元素的类型 + * @return 包含流中所有元素的数组 + */ + @Override + public @NotNull A[] toArray(IntFunction generator) { + return list.toArray(generator.apply(list.size())); + } + + /** + * 使用指定的初始值和累积函数对流中的元素进行归约操作。 + * + * @param identity 初始值 + * @param accumulator 累积函数,用于将两个元素合并为一个 + * @return 归约后的结果 + */ + @Override + public T reduce(T identity, BinaryOperator accumulator) { + T result = identity; + for (T item : list) { + result = accumulator.apply(result, item); + } + return result; + } + + /** + * 使用指定的累积函数对流中的元素进行归约操作。 + * + * @param accumulator 累积函数,用于将两个元素合并为一个 + * @return 归约后的结果,如果流为空则返回空 Optional + */ + @Override + public @NotNull Optional reduce(BinaryOperator accumulator) { + if (list.isEmpty()) { + return Optional.empty(); + } + T result = list.get(0); + for (int i = 1; i < list.size(); i++) { + result = accumulator.apply(result, list.get(i)); + } + return Optional.of(result); + } + + /** + * 使用指定的初始值、累积函数和组合函数对流中的元素进行归约操作。 + * + * @param identity 初始值 + * @param accumulator 累积函数,用于将元素与累积值合并 + * @param combiner 组合函数,用于合并两个累积值 + * @param 累积值的类型 + * @return 归约后的结果 + */ + @Override + public U reduce( + U identity, + BiFunction accumulator, + BinaryOperator combiner + ) { + U result = identity; + for (T item : list) { + result = accumulator.apply(result, item); + } + return result; + } + + /** + * 使用指定的收集器将流中的元素收集到容器中。 + * + * @param supplier 用于创建容器的函数 + * @param accumulator 用于将元素添加到容器的函数 + * @param combiner 用于合并两个容器的函数 + * @param 容器的类型 + * @return 收集后的结果 + */ + @Override + public R collect( + Supplier supplier, + BiConsumer accumulator, + BiConsumer combiner + ) { + R result = supplier.get(); + for (T item : list) { + accumulator.accept(result, item); + } + return result; + } + + @Override + public String toString() { + if (list.isEmpty()) { + return "ListStream()"; + } + StringBuilder sb = new StringBuilder(); + sb.append("ListStream("); + forEach((item, index) -> { + sb.append(item); + if (index != list.size() - 1) { + sb.append(", "); + } else { + sb.append(")"); + } + }); + return sb.toString(); + } + + /** + * 使用指定的收集器将流中的元素收集到容器中。 + * + * @param collector 收集器,定义了如何收集元素 + * @param 收集结果的类型 + * @param 容器中元素的类型 + * @return 收集后的结果 + */ + @Override + public R collect(Collector collector) { + A container = collector.supplier().get(); + for (T item : list) { + collector.accumulator().accept(container, item); + } + return collector.finisher().apply(container); + } + + /** + * 根据给定的比较器找出流中的最小元素。 + * + * @param comparator 用于比较元素的比较器 + * @return 包含最小元素的 Optional,如果流为空则返回空 Optional + */ + @Override + public @NotNull Optional min(Comparator comparator) { + if (list.isEmpty()) { + return Optional.empty(); + } + T min = list.get(0); + for (int i = 1; i < list.size(); i++) { + T current = list.get(i); + if (comparator.compare(current, min) < 0) { + min = current; + } + } + return Optional.of(min); + } + + /** + * 根据给定的比较器找出流中的最大元素。 + * + * @param comparator 用于比较元素的比较器 + * @return 包含最大元素的 Optional,如果流为空则返回空 Optional + */ + @Override + public @NotNull Optional max(Comparator comparator) { + if (list.isEmpty()) { + return Optional.empty(); + } + T max = list.get(0); + for (int i = 1; i < list.size(); i++) { + T current = list.get(i); + if (comparator.compare(current, max) > 0) { + max = current; + } + } + return Optional.of(max); + } + + /** + * 返回流中元素的数量。 + * + * @return 元素数量 + */ + @Override + public long count() { + return list.size(); + } + + /** + * 检查流中是否有至少一个元素满足给定的谓词条件。 + * + * @param predicate 用于测试元素的谓词函数 + * @return 如果有至少一个元素满足条件则返回 true,否则返回 false + */ + @Override + public boolean anyMatch(Predicate predicate) { + for (T item : list) { + if (predicate.test(item)) { + return true; + } + } + return false; + } + + /** + * 检查流中是否所有元素都满足给定的谓词条件。 + * + * @param predicate 用于测试元素的谓词函数 + * @return 如果所有元素都满足条件则返回 true,否则返回 false + */ + @Override + public boolean allMatch(Predicate predicate) { + for (T item : list) { + if (!predicate.test(item)) { + return false; + } + } + return true; + } + + /** + * 检查流中是否没有任何元素满足给定的谓词条件。 + * + * @param predicate 用于测试元素的谓词函数 + * @return 如果没有任何元素满足条件则返回 true,否则返回 false + */ + @Override + public boolean noneMatch(Predicate predicate) { + return !anyMatch(predicate); + } + + /** + * 获取流中的第一个元素。 + * + * @return 包含第一个元素的 Optional,如果流为空则返回空 Optional + */ + @Override + public @NotNull Optional findFirst() { + return list.isEmpty() ? Optional.empty() : Optional.of(list.get(0)); + } + + /** + * 获取流中的最后一个元素。 + * + * @return 包含最后一个元素的 Optional,如果流为空则返回空 Optional + */ + public @NotNull Optional findEnd() { + return list.isEmpty() + ? Optional.empty() + : Optional.of(list.get(list.size() - 1)); + } + + /** + * 获取流中的任意一个元素。 + * + * @return 包含任意一个元素的 Optional,如果流为空则返回空 Optional + */ + @Override + public @NotNull Optional findAny() { + if (list.size() == 1) { + return Optional.of(list.get(0)); + } else { + return list.isEmpty() + ? Optional.empty() + : Optional.of( + list.get(RandomInt.randomInt(0, list.size() - 1)) + ); + } + } + + /** + * 返回流中元素的迭代器。 + * + * @return 元素迭代器 + */ + @Override + public @NotNull Iterator iterator() { + return list.iterator(); + } + + /** + * 返回流中元素的 Spliterator。 + * + * @return 元素 Spliterator + */ + @Override + public @NotNull Spliterator spliterator() { + return list.spliterator(); + } + + /** + * 检查当前流是否为并行流。 + * + * @return 如果是并行流则返回 true,否则返回 false + */ + @Override + public boolean isParallel() { + return false; + } + + /** + * 返回当前流的顺序版本。 + * + * @return 当前流的顺序版本 + */ + @Override + public @NotNull ListStream sequential() { + return this; + } + + /** + * 返回当前流的并行版本。 + * + * @return 当前流的并行版本 + */ + @Override + public @NotNull ListStream parallel() { + return new ListStream<>(list); + } + + /** + * 返回当前流的无序版本。 + * + * @return 当前流的无序版本 + */ + @Override + public @NotNull ListStream unordered() { + return this; + } + + /** + * 注册一个关闭处理器,在流关闭时执行。 + * + * @param closeHandler 关闭处理器 + * @return 当前 ListStream 实例 + */ + @Override + public @NotNull ListStream onClose(@NotNull Runnable closeHandler) { + return this; + } + + /** + * 关闭流。 + */ + @Override + public void close() { + list.clear(); + } +} diff --git a/src/com/mingliqiye/utils/stream/MapStream.java b/src/com/mingliqiye/utils/stream/MapStream.java new file mode 100644 index 0000000..04c53b2 --- /dev/null +++ b/src/com/mingliqiye/utils/stream/MapStream.java @@ -0,0 +1,313 @@ +package com.mingliqiye.utils.stream; + +import com.mingliqiye.utils.collection.Lists; + +import java.util.*; +import java.util.function.*; + +/** + * 用于处理键值对的流实现 + * + * @author MingLiPro + * @param 键类型 + * @param 值类型 + */ +public class MapStream { + + private final List> entries; + + /** + * 构造方法 + * + * @param entries 包含键值对的列表 + */ + private MapStream(List> entries) { + this.entries = entries != null ? entries : Lists.newArrayList(); + } + + /** + * 从Map创建MapStream + * + * @param map 输入Map + * @param 键类型 + * @param 值类型 + * @return MapStream实例 + */ + public static MapStream of(Map map) { + return new MapStream<>(new ArrayList<>(map.entrySet())); + } + + /** + * 从键值对数组创建MapStream + * + * @param entries 键值对数组 + * @param 键类型 + * @param 值类型 + * @return MapStream实例 + */ + @SafeVarargs + public static MapStream of(Map.Entry... entries) { + return new MapStream<>(Lists.newArrayList(entries)); + } + + /** + * 根据键过滤MapStream + * + * @param keyPredicate 键的谓词条件 + * @return 过滤后的MapStream + */ + public MapStream filterByKey(Predicate keyPredicate) { + List> result = Lists.newArrayList(); + for (Map.Entry entry : entries) { + if (keyPredicate.test(entry.getKey())) { + result.add(entry); + } + } + return new MapStream<>(result); + } + + /** + * 根据值过滤MapStream + * + * @param valuePredicate 值的谓词条件 + * @return 过滤后的MapStream + */ + public MapStream filterByValue(Predicate valuePredicate) { + List> result = Lists.newArrayList(); + for (Map.Entry entry : entries) { + if (valuePredicate.test(entry.getValue())) { + result.add(entry); + } + } + return new MapStream<>(result); + } + + /** + * 过滤MapStream + * + * @param predicate 键值对的谓词条件 + * @return 过滤后的MapStream + */ + public MapStream filter(Predicate> predicate) { + List> result = Lists.newArrayList(); + for (Map.Entry entry : entries) { + if (predicate.test(entry)) { + result.add(entry); + } + } + return new MapStream<>(result); + } + + /** + * 转换键 + * + * @param keyMapper 键映射函数 + * @param 新的键类型 + * @return 转换后的MapStream + */ + public MapStream mapKey( + Function keyMapper + ) { + List> result = Lists.newArrayList(); + for (Map.Entry entry : entries) { + R newKey = keyMapper.apply(entry.getKey()); + result.add(new AbstractMap.SimpleEntry<>(newKey, entry.getValue())); + } + return new MapStream<>(result); + } + + /** + * 转换值 + * + * @param valueMapper 值映射函数 + * @param 新的值类型 + * @return 转换后的MapStream + */ + public MapStream mapValue( + Function valueMapper + ) { + List> result = Lists.newArrayList(); + for (Map.Entry entry : entries) { + R newValue = valueMapper.apply(entry.getValue()); + result.add(new AbstractMap.SimpleEntry<>(entry.getKey(), newValue)); + } + return new MapStream<>(result); + } + + /** + * 转换键值对 + * + * @param entryMapper 键值对映射函数 + * @param 新的键类型 + * @param 新的值类型 + * @return 转换后的MapStream + */ + public MapStream map( + Function, Map.Entry> entryMapper + ) { + List> result = Lists.newArrayList(); + for (Map.Entry entry : entries) { + result.add(entryMapper.apply(entry)); + } + return new MapStream<>(result); + } + + /** + * 将键值对流转换为Map + * + * @return 包含所有键值对的Map + */ + public Map toMap() { + Map map = new HashMap<>(); + for (Map.Entry entry : entries) { + map.put(entry.getKey(), entry.getValue()); + } + return map; + } + + /** + * 将键值对流转换为Map,指定Map类型和键冲突时的合并函数 + * + * @param mapSupplier Map工厂函数 + * @param mergeFunction 键冲突合并函数 + * @param Map类型 + * @return 包含所有键值对的Map + */ + public > M toMap( + Supplier mapSupplier, + BinaryOperator mergeFunction + ) { + M map = mapSupplier.get(); + for (Map.Entry entry : entries) { + map.merge(entry.getKey(), entry.getValue(), mergeFunction); + } + return map; + } + + /** + * 对每个键值对执行操作 + * + * @param action 要执行的操作 + */ + public void forEach(BiConsumer action) { + for (Map.Entry entry : entries) { + action.accept(entry.getKey(), entry.getValue()); + } + } + + /** + * 计算键值对数量 + * + * @return 键值对数量 + */ + public long count() { + return entries.size(); + } + + /** + * 获取键的流 + * + * @return 键的流 + */ + public ListStream keys() { + List keys = Lists.newArrayList(); + for (Map.Entry entry : entries) { + keys.add(entry.getKey()); + } + return ListStream.of(keys); + } + + /** + * 获取值的流 + * + * @return 值的流 + */ + public ListStream values() { + List values = Lists.newArrayList(); + for (Map.Entry entry : entries) { + values.add(entry.getValue()); + } + return ListStream.of(values); + } + + /** + * 对键值对进行排序 + * + * @param comparator 比较器 + * @return 排序后的MapStream + */ + public MapStream sorted(Comparator> comparator) { + List> sortedEntries = Lists.newArrayList(entries); + sortedEntries.sort(comparator); + return new MapStream<>(sortedEntries); + } + + /** + * 限制键值对数量 + * + * @param maxSize 最大数量 + * @return 限制后的MapStream + */ + public MapStream limit(long maxSize) { + if (maxSize < 0) { + throw new IllegalArgumentException("maxSize must be non-negative"); + } + if (maxSize == 0) { + return new MapStream<>(Lists.newArrayList()); + } + + List> limitedEntries = Lists.newArrayList(); + long count = 0; + for (Map.Entry entry : entries) { + if (count >= maxSize) { + break; + } + limitedEntries.add(entry); + count++; + } + return new MapStream<>(limitedEntries); + } + + /** + * 跳过指定数量的键值对 + * + * @param n 要跳过的数量 + * @return 跳过后的MapStream + */ + public MapStream skip(long n) { + if (n < 0) { + throw new IllegalArgumentException("n must be non-negative"); + } + if (n == 0) { + return new MapStream<>(Lists.newArrayList(entries)); + } + + List> skippedEntries = Lists.newArrayList(); + long count = 0; + for (Map.Entry entry : entries) { + if (count >= n) { + skippedEntries.add(entry); + } + count++; + } + return new MapStream<>(skippedEntries); + } + + @Override + public String toString() { + if (entries.isEmpty()) { + return "MapStream()"; + } + StringBuilder sb = new StringBuilder(); + sb.append("MapStream("); + for (int i = 0; i < entries.size(); i++) { + Map.Entry entry = entries.get(i); + sb.append(entry.getKey()).append("=").append(entry.getValue()); + if (i != entries.size() - 1) { + sb.append(", "); + } + } + sb.append(")"); + return sb.toString(); + } +} diff --git a/src/com/mingliqiye/utils/time/DateTime.java b/src/com/mingliqiye/utils/time/DateTime.java index 88badce..8757f9e 100644 --- a/src/com/mingliqiye/utils/time/DateTime.java +++ b/src/com/mingliqiye/utils/time/DateTime.java @@ -1,5 +1,6 @@ package com.mingliqiye.utils.time; +import com.mingliqiye.utils.jna.time.WinKernel32; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; @@ -24,11 +25,23 @@ import org.jetbrains.annotations.NotNull; * @see ZoneId * @see Instant */ - +@Setter public final class DateTime { + private static final String version = System.getProperty("java.version"); + private static final WinKernel32 WIN_KERNEL_32; + private static final long FILETIME_EPOCH_OFFSET = -116444736000000000L; + private static final long NANOS_PER_100NS = 100; + + static { + if (version.startsWith("1.8")) { + WIN_KERNEL_32 = WinKernel32.load(); + } else { + WIN_KERNEL_32 = null; + } + } + @Getter - @Setter private ZoneId zoneId = ZoneId.systemDefault(); @Getter @@ -52,13 +65,40 @@ public final class DateTime { /** * 获取当前时间的 DateTime 实例。 + * 如果运行在 Java 1.8 环境下,则通过 WinKernel32 获取高精度时间。 * * @return 返回当前时间的 DateTime 实例 */ public static DateTime now() { + if (WIN_KERNEL_32 != null) { + byte[] fileTimeBuffer = new byte[8]; + WIN_KERNEL_32.GetSystemTimePreciseAsFileTime(fileTimeBuffer); + long fileTime = + (long) (fileTimeBuffer[0] & 0xFF) | + ((long) (fileTimeBuffer[1] & 0xFF) << 8) | + ((long) (fileTimeBuffer[2] & 0xFF) << 16) | + ((long) (fileTimeBuffer[3] & 0xFF) << 24) | + ((long) (fileTimeBuffer[4] & 0xFF) << 32) | + ((long) (fileTimeBuffer[5] & 0xFF) << 40) | + ((long) (fileTimeBuffer[6] & 0xFF) << 48) | + ((long) (fileTimeBuffer[7] & 0xFF) << 56); + long unixNanos = + (fileTime + FILETIME_EPOCH_OFFSET) * NANOS_PER_100NS; + Instant instant = Instant.ofEpochSecond( + unixNanos / 1_000_000_000L, + unixNanos % 1_000_000_000L + ); + return DateTime.of( + instant.atZone(ZoneId.systemDefault()).toLocalDateTime() + ); + } return new DateTime(); } + public static void main(String[] args) { + System.out.println(DateTime.now()); + } + /** * 将 Date 对象转换为 DateTime 实例。 * @@ -215,6 +255,26 @@ public final class DateTime { 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 实例 * @@ -292,15 +352,6 @@ public final class DateTime { ); } - /** - * 设置 LocalDateTime 实例。 - * - * @param localDateTime LocalDateTime 对象 - */ - public void setLocalDateTime(LocalDateTime localDateTime) { - this.localDateTime = localDateTime; - } - /** * 将当前 DateTime 转换为 Date 对象。 * @@ -444,7 +495,6 @@ public final class DateTime { * @param dateTime 指定时间 * @return 如果当前时间在指定时间之后则返回 true,否则返回 false */ - public boolean isAfter(DateTime dateTime) { if (dateTime == null) { return false; @@ -458,7 +508,6 @@ public final class DateTime { * @param dateTime 指定时间 * @return 如果当前时间在指定时间之前则返回 true,否则返回 false */ - public boolean isBefore(DateTime dateTime) { if (dateTime == null) { return false; diff --git a/src/com/mingliqiye/utils/time/serialization/Jackson.java b/src/com/mingliqiye/utils/time/serialization/Jackson.java index f8b56dc..cb0717d 100644 --- a/src/com/mingliqiye/utils/time/serialization/Jackson.java +++ b/src/com/mingliqiye/utils/time/serialization/Jackson.java @@ -9,7 +9,6 @@ import com.fasterxml.jackson.databind.jsontype.TypeSerializer; import com.fasterxml.jackson.databind.module.SimpleModule; import com.mingliqiye.utils.time.DateTime; import com.mingliqiye.utils.time.Formatter; - import java.io.IOException; /** diff --git a/src/com/mingliqiye/utils/uuid/serialization/Jackson.java b/src/com/mingliqiye/utils/uuid/serialization/Jackson.java index 9bb2566..6099fef 100644 --- a/src/com/mingliqiye/utils/uuid/serialization/Jackson.java +++ b/src/com/mingliqiye/utils/uuid/serialization/Jackson.java @@ -9,7 +9,6 @@ import com.fasterxml.jackson.databind.jsontype.TypeSerializer; import com.fasterxml.jackson.databind.module.SimpleModule; import com.mingliqiye.utils.uuid.UUID; import com.mingliqiye.utils.uuid.UUIDException; - import java.io.IOException; /** @@ -24,13 +23,13 @@ public class Jackson { * * @param objectMapper ObjectMapper实例,用于注册自定义序列化模块 */ - public static void addSerializers(ObjectMapper objectMapper) { - // 创建SimpleModule并添加UUID的序列化器和反序列化器 - SimpleModule module = new SimpleModule() - .addSerializer(UUID.class, new UUIDJsonSerializer()) - .addDeserializer(UUID.class, new UUIDJsonDeserializer()); - objectMapper.registerModule(module); - } + public static void addSerializers(ObjectMapper objectMapper) { + // 创建SimpleModule并添加UUID的序列化器和反序列化器 + SimpleModule module = new SimpleModule() + .addSerializer(UUID.class, new UUIDJsonSerializer()) + .addDeserializer(UUID.class, new UUIDJsonDeserializer()); + objectMapper.registerModule(module); + } /** * UUID 反序列化器