From c804cbd1dc13ef84482e017fc80c864c3b77f44a Mon Sep 17 00:00:00 2001 From: Toint <599818663@qq.com> Date: Fri, 24 Oct 2025 12:32:23 +0800 Subject: [PATCH 1/3] =?UTF-8?q?fix=20#4112=20=E9=82=AE=E4=BB=B6=E5=86=85?= =?UTF-8?q?=E5=AE=B9=E4=B8=A2=E5=A4=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hutool/v7/core/thread/ScopeValueUtil.java | 240 ++++++++++++++++++ .../cn/hutool/v7/extra/mail/SMTPMessage.java | 37 +-- 2 files changed, 260 insertions(+), 17 deletions(-) create mode 100644 hutool-core/src/main/java/cn/hutool/v7/core/thread/ScopeValueUtil.java diff --git a/hutool-core/src/main/java/cn/hutool/v7/core/thread/ScopeValueUtil.java b/hutool-core/src/main/java/cn/hutool/v7/core/thread/ScopeValueUtil.java new file mode 100644 index 0000000000..ede4ca5ea6 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/v7/core/thread/ScopeValueUtil.java @@ -0,0 +1,240 @@ +//package cn.hutool.v7.core.thread; +// +//import java.util.*; +//import java.util.concurrent.CompletableFuture; +//import java.util.concurrent.ExecutorService; +//import java.util.concurrent.Executors; +//import java.util.function.Supplier; +// +///** +// * ScopedValue 异步传播工具类 +// *

+// * 用于在异步任务(CompletableFuture)中传播 JDK 25+ 的 ScopedValue, +// * 解决 ScopedValue 在跨线程时值丢失的问题。 +// *

+// * +// *

使用示例:

+// *
{@code
+// * ScopedValue USER_ID = ScopedValue.newInstance();
+// *
+// * ScopedValue.where(USER_ID, "user123").run(() -> {
+// *     // 异步任务中自动传播 USER_ID
+// *     ScopeValueUtil.supplyAsync(USER_ID, () -> {
+// *         return "Processing for: " + USER_ID.get();
+// *     }).thenAccept(System.out::println);
+// * });
+// * }
+// * +// * @author Toint +// * @date 2025/10/21 +// */ +//public class ScopeValueUtil { +// +// /** +// * 虚拟线程执行器,用于执行异步任务 +// */ +// private static final ExecutorService executorService = Executors.newVirtualThreadPerTaskExecutor(); +// +// /** +// * 在异步任务中传播单个 ScopedValue(无返回值) +// *

+// * 捕获当前线程中指定 ScopedValue 的值,并在异步任务中恢复该值的绑定。 +// *

+// * +// * @param scopedValue 需要传播的 ScopedValue +// * @param runnable 异步执行的任务 +// * @param ScopedValue 的值类型 +// * @return CompletableFuture 异步任务的 Future 对象 +// */ +// public static CompletableFuture runAsync(ScopedValue scopedValue, Runnable runnable) { +// return runAsync(Collections.singletonList(scopedValue), runnable); +// } +// +// /** +// * 在异步任务中传播单个 ScopedValue(有返回值) +// *

+// * 捕获当前线程中指定 ScopedValue 的值,并在异步任务中恢复该值的绑定。 +// *

+// * +// * @param scopedValue 需要传播的 ScopedValue +// * @param supplier 异步执行的任务,返回结果 +// * @param ScopedValue 的值类型 +// * @param 异步任务的返回值类型 +// * @return CompletableFuture 异步任务的 Future 对象,包含任务执行结果 +// */ +// public static CompletableFuture supplyAsync(ScopedValue scopedValue, Supplier supplier) { +// return supplyAsync(Collections.singletonList(scopedValue), supplier); +// } +// +// /** +// * 在异步任务中传播多个 ScopedValue(无返回值) +// *

+// * 捕获当前线程中多个 ScopedValue 的值,并在异步任务中恢复这些值的绑定。 +// * 只有已绑定的 ScopedValue 会被传播,未绑定的会被忽略。 +// *

+// * +// * @param scopedValues 需要传播的 ScopedValue 列表 +// * @param runnable 异步执行的任务 +// * @param ScopedValue 的值类型 +// * @return CompletableFuture 异步任务的 Future 对象 +// */ +// public static CompletableFuture runAsync(List> scopedValues, Runnable runnable) { +// Map, V> scopedValueMap = captureContext(scopedValues); +// return runAsync(scopedValueMap, runnable); +// } +// +// /** +// * 在异步任务中传播多个 ScopedValue(有返回值) +// *

+// * 捕获当前线程中多个 ScopedValue 的值,并在异步任务中恢复这些值的绑定。 +// * 只有已绑定的 ScopedValue 会被传播,未绑定的会被忽略。 +// *

+// * +// * @param scopedValues 需要传播的 ScopedValue 列表 +// * @param supplier 异步执行的任务,返回结果 +// * @param ScopedValue 的值类型 +// * @param 异步任务的返回值类型 +// * @return CompletableFuture 异步任务的 Future 对象,包含任务执行结果 +// */ +// public static CompletableFuture supplyAsync(List> scopedValues, Supplier supplier) { +// Map, V> scopedValueMap = captureContext(scopedValues); +// return supplyAsync(scopedValueMap, supplier); +// } +// +// /** +// * 在异步任务中传播 ScopedValue 上下文(有返回值) +// *

+// * 根据提供的 ScopedValue 上下文映射,在异步任务中恢复这些值的绑定。 +// * 这是最底层的传播方法,其他 supplyAsync 方法最终都会调用此方法。 +// *

+// * +// * @param scopedValueMap ScopedValue 到其值的映射,表示需要传播的上下文 +// * @param supplier 异步执行的任务,返回结果 +// * @param ScopedValue 的值类型 +// * @param 异步任务的返回值类型 +// * @return CompletableFuture 异步任务的 Future 对象,包含任务执行结果 +// * @throws NullPointerException 如果 supplier 为 null +// */ +// public static CompletableFuture supplyAsync(Map, V> scopedValueMap, Supplier supplier) { +// Objects.requireNonNull(supplier, "supplier must not be null"); +// +// if (scopedValueMap == null || scopedValueMap.isEmpty()) { +// return CompletableFuture.supplyAsync(supplier, executorService); +// } +// +// return CompletableFuture.supplyAsync(() -> { +// ScopedValue.Carrier carrier = buildCarrier(scopedValueMap); +// return carrier.call(supplier::get); +// }, executorService); +// } +// +// /** +// * 在异步任务中传播 ScopedValue 上下文(无返回值) +// *

+// * 根据提供的 ScopedValue 上下文映射,在异步任务中恢复这些值的绑定。 +// * 这是最底层的传播方法,其他 runAsync 方法最终都会调用此方法。 +// *

+// * +// * @param scopedValueMap ScopedValue 到其值的映射,表示需要传播的上下文 +// * @param runnable 异步执行的任务 +// * @param ScopedValue 的值类型 +// * @return CompletableFuture 异步任务的 Future 对象 +// * @throws NullPointerException 如果 runnable 为 null +// */ +// public static CompletableFuture runAsync(Map, V> scopedValueMap, Runnable runnable) { +// Objects.requireNonNull(runnable, "runnable must not be null"); +// +// return supplyAsync(scopedValueMap, () -> { +// runnable.run(); +// return null; +// }); +// } +// +// /** +// * 构建 ScopedValue.Carrier 对象 +// *

+// * Carrier 用于在新的执行上下文中批量绑定多个 ScopedValue。 +// * 通过链式调用 where() 方法构建包含所有绑定的 Carrier。 +// *

+// * +// * @param scopedValueVMap ScopedValue 到其值的映射 +// * @param ScopedValue 的值类型 +// * @return ScopedValue.Carrier 对象,如果映射为空则返回 null +// */ +// public static ScopedValue.Carrier buildCarrier(Map, V> scopedValueVMap) { +// if (scopedValueVMap == null || scopedValueVMap.isEmpty()) return null; +// +// ScopedValue.Carrier carrier = null; +// for (Map.Entry, V> entry : scopedValueVMap.entrySet()) { +// if (carrier == null) { +// carrier = ScopedValue.where(entry.getKey(), entry.getValue()); +// } else { +// carrier = carrier.where(entry.getKey(), entry.getValue()); +// } +// } +// return carrier; +// } +// +// /** +// * 捕获当前线程中已绑定的 ScopedValue +// *

+// * 遍历指定的 ScopedValue 列表,提取所有在当前线程中已绑定的值, +// * 构建成 Map 以便后续在异步线程中恢复。未绑定或为 null 的 ScopedValue 会被忽略。 +// *

+// * +// * @param scopedValues 需要捕获的 ScopedValue 列表 +// * @param ScopedValue 的值类型 +// * @return Map, V> 包含已绑定值的映射,如果没有绑定值则返回空 Map +// */ +// public static Map, V> captureContext(List> scopedValues) { +// Map, V> scopedValueMap = new HashMap<>(); +// if (scopedValues != null && !scopedValues.isEmpty()) { +// scopedValues.forEach(scopedValue -> { +// if (scopedValue != null && scopedValue.isBound()) { +// scopedValueMap.put(scopedValue, scopedValue.get()); +// } +// }); +// } +// return scopedValueMap; +// } +// +// /** +// * 安全获取 ScopedValue 的绑定值 +// *

+// * 与 {@link ScopedValue#get()} 不同,此方法在 ScopedValue 未绑定时返回 null, +// * 而不是抛出 {@link NoSuchElementException} 异常。适用于需要容错处理的场景。 +// *

+// * +// *

使用场景:

+// *
    +// *
  • 不确定 ScopedValue 是否已绑定时
  • +// *
  • 需要优雅处理未绑定情况,避免异常
  • +// *
  • 可选的上下文传递场景
  • +// *
+// * +// *

使用示例:

+// *
{@code
+//     * ScopedValue USER_ID = ScopedValue.newInstance();
+//     *
+//     * // 安全获取,不会抛异常
+//     * String userId = ScopeValueUtil.getOrNull(USER_ID);
+//     * if (userId != null) {
+//     *     System.out.println("User ID: " + userId);
+//     * }
+//     * }
+// * +// * @param scopedValue 需要获取值的 ScopedValue,允许为 null +// * @param ScopedValue 的值类型 +// * @return 已绑定的值,如果未绑定或 scopedValue 为 null 则返回 null +// * @see ScopedValue#get() +// * @see ScopedValue#isBound() +// */ +// public static V getOrNull(ScopedValue scopedValue) { +// if (scopedValue != null && scopedValue.isBound()) { +// return scopedValue.get(); +// } else { +// return null; +// } +// } +// +//} diff --git a/hutool-extra/src/main/java/cn/hutool/v7/extra/mail/SMTPMessage.java b/hutool-extra/src/main/java/cn/hutool/v7/extra/mail/SMTPMessage.java index 8f1c55b299..2346a2ca57 100644 --- a/hutool-extra/src/main/java/cn/hutool/v7/extra/mail/SMTPMessage.java +++ b/hutool-extra/src/main/java/cn/hutool/v7/extra/mail/SMTPMessage.java @@ -196,7 +196,7 @@ public class SMTPMessage extends MimeMessage { */ public SMTPMessage setContent(final String content, final boolean isHtml) { try { - super.setContent(buildContent(this.mailAccount.getCharset(), isHtml)); + super.setContent(buildContent(content, this.mailAccount.getCharset(), isHtml)); } catch (final MessagingException e) { throw new MailException(e); } @@ -339,22 +339,25 @@ public class SMTPMessage extends MimeMessage { } } - /** - * 构建邮件信息主体 - * - * @param charset 编码,{@code null}则使用{@link MimeUtility#getDefaultJavaCharset()} - * @param isHtml 是否为HTML - * @return 邮件信息主体 - * @throws MessagingException 消息异常 - */ - private Multipart buildContent(final Charset charset, final boolean isHtml) throws MessagingException { - final String charsetStr = null != charset ? charset.name() : MimeUtility.getDefaultJavaCharset(); - // 正文 - final MimeBodyPart body = new MimeBodyPart(); - body.setContent(content, StrUtil.format("text/{}; charset={}", isHtml ? "html" : "plain", charsetStr)); - addBodyPart( body, 0); - return this.multipart; - } + /** + * 构建邮件信息主体 + * + * @param content 内容, {@code null}则使用{@link StrUtil#EMPTY}替换 + * @param charset 编码,{@code null}则使用{@link MimeUtility#getDefaultJavaCharset()} + * @param isHtml 是否为HTML + * @return 邮件信息主体 + * @throws MessagingException 消息异常 + */ + private Multipart buildContent(final String content, final Charset charset, final boolean isHtml) throws MessagingException { + final String charsetStr = null != charset ? charset.name() : MimeUtility.getDefaultJavaCharset(); + // 内容如果是null会抛异常, 使用空字符串代替 + final String contentStr = content == null ? StrUtil.EMPTY : content; + // 正文 + final MimeBodyPart body = new MimeBodyPart(); + body.setContent(contentStr, StrUtil.format("text/{}; charset={}", isHtml ? "html" : "plain", charsetStr)); + addBodyPart(body, 0); + return this.multipart; + } /** * 执行发送 From fd4f3be568ddca4f28ea261f26d555f6bb8a3d3e Mon Sep 17 00:00:00 2001 From: Toint <599818663@qq.com> Date: Fri, 24 Oct 2025 12:37:53 +0800 Subject: [PATCH 2/3] =?UTF-8?q?fix=20#4112=20=E6=94=B6=E4=BB=B6=E4=BA=BA/?= =?UTF-8?q?=E6=8A=84=E9=80=81=E4=BA=BA/=E5=AF=86=E9=80=81=E4=BA=BA/?= =?UTF-8?q?=E5=9B=9E=E5=A4=8D=E5=9C=B0=E5=9D=80(reply-to)=E4=BB=BB?= =?UTF-8?q?=E4=BD=95=E4=B8=80=E4=B8=AA=E4=B8=BA=E7=A9=BA=E4=BC=9A=E7=A9=BA?= =?UTF-8?q?=E6=8C=87=E9=92=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/hutool/v7/extra/mail/InternalMailUtil.java | 1 + 1 file changed, 1 insertion(+) diff --git a/hutool-extra/src/main/java/cn/hutool/v7/extra/mail/InternalMailUtil.java b/hutool-extra/src/main/java/cn/hutool/v7/extra/mail/InternalMailUtil.java index 28a2932362..42d8db189a 100644 --- a/hutool-extra/src/main/java/cn/hutool/v7/extra/mail/InternalMailUtil.java +++ b/hutool-extra/src/main/java/cn/hutool/v7/extra/mail/InternalMailUtil.java @@ -44,6 +44,7 @@ public class InternalMailUtil { * @since 4.0.3 */ public static InternetAddress[] parseAddressFromStrs(final String[] addrStrs, final Charset charset) { + if (ArrayUtil.isEmpty(addrStrs)) return new InternetAddress[0]; final List resultList = new ArrayList<>(addrStrs.length); InternetAddress[] addrs; for (final String addrStr : addrStrs) { From 138c243d27e9c5ef488304591e14fef330329ef1 Mon Sep 17 00:00:00 2001 From: Toint <599818663@qq.com> Date: Fri, 24 Oct 2025 12:40:33 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=84=8F=E5=A4=96?= =?UTF-8?q?=E6=8F=90=E4=BA=A4=E7=9A=84ScopeValueUtil?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hutool/v7/core/thread/ScopeValueUtil.java | 240 ------------------ 1 file changed, 240 deletions(-) delete mode 100644 hutool-core/src/main/java/cn/hutool/v7/core/thread/ScopeValueUtil.java diff --git a/hutool-core/src/main/java/cn/hutool/v7/core/thread/ScopeValueUtil.java b/hutool-core/src/main/java/cn/hutool/v7/core/thread/ScopeValueUtil.java deleted file mode 100644 index ede4ca5ea6..0000000000 --- a/hutool-core/src/main/java/cn/hutool/v7/core/thread/ScopeValueUtil.java +++ /dev/null @@ -1,240 +0,0 @@ -//package cn.hutool.v7.core.thread; -// -//import java.util.*; -//import java.util.concurrent.CompletableFuture; -//import java.util.concurrent.ExecutorService; -//import java.util.concurrent.Executors; -//import java.util.function.Supplier; -// -///** -// * ScopedValue 异步传播工具类 -// *

-// * 用于在异步任务(CompletableFuture)中传播 JDK 25+ 的 ScopedValue, -// * 解决 ScopedValue 在跨线程时值丢失的问题。 -// *

-// * -// *

使用示例:

-// *
{@code
-// * ScopedValue USER_ID = ScopedValue.newInstance();
-// *
-// * ScopedValue.where(USER_ID, "user123").run(() -> {
-// *     // 异步任务中自动传播 USER_ID
-// *     ScopeValueUtil.supplyAsync(USER_ID, () -> {
-// *         return "Processing for: " + USER_ID.get();
-// *     }).thenAccept(System.out::println);
-// * });
-// * }
-// * -// * @author Toint -// * @date 2025/10/21 -// */ -//public class ScopeValueUtil { -// -// /** -// * 虚拟线程执行器,用于执行异步任务 -// */ -// private static final ExecutorService executorService = Executors.newVirtualThreadPerTaskExecutor(); -// -// /** -// * 在异步任务中传播单个 ScopedValue(无返回值) -// *

-// * 捕获当前线程中指定 ScopedValue 的值,并在异步任务中恢复该值的绑定。 -// *

-// * -// * @param scopedValue 需要传播的 ScopedValue -// * @param runnable 异步执行的任务 -// * @param ScopedValue 的值类型 -// * @return CompletableFuture 异步任务的 Future 对象 -// */ -// public static CompletableFuture runAsync(ScopedValue scopedValue, Runnable runnable) { -// return runAsync(Collections.singletonList(scopedValue), runnable); -// } -// -// /** -// * 在异步任务中传播单个 ScopedValue(有返回值) -// *

-// * 捕获当前线程中指定 ScopedValue 的值,并在异步任务中恢复该值的绑定。 -// *

-// * -// * @param scopedValue 需要传播的 ScopedValue -// * @param supplier 异步执行的任务,返回结果 -// * @param ScopedValue 的值类型 -// * @param 异步任务的返回值类型 -// * @return CompletableFuture 异步任务的 Future 对象,包含任务执行结果 -// */ -// public static CompletableFuture supplyAsync(ScopedValue scopedValue, Supplier supplier) { -// return supplyAsync(Collections.singletonList(scopedValue), supplier); -// } -// -// /** -// * 在异步任务中传播多个 ScopedValue(无返回值) -// *

-// * 捕获当前线程中多个 ScopedValue 的值,并在异步任务中恢复这些值的绑定。 -// * 只有已绑定的 ScopedValue 会被传播,未绑定的会被忽略。 -// *

-// * -// * @param scopedValues 需要传播的 ScopedValue 列表 -// * @param runnable 异步执行的任务 -// * @param ScopedValue 的值类型 -// * @return CompletableFuture 异步任务的 Future 对象 -// */ -// public static CompletableFuture runAsync(List> scopedValues, Runnable runnable) { -// Map, V> scopedValueMap = captureContext(scopedValues); -// return runAsync(scopedValueMap, runnable); -// } -// -// /** -// * 在异步任务中传播多个 ScopedValue(有返回值) -// *

-// * 捕获当前线程中多个 ScopedValue 的值,并在异步任务中恢复这些值的绑定。 -// * 只有已绑定的 ScopedValue 会被传播,未绑定的会被忽略。 -// *

-// * -// * @param scopedValues 需要传播的 ScopedValue 列表 -// * @param supplier 异步执行的任务,返回结果 -// * @param ScopedValue 的值类型 -// * @param 异步任务的返回值类型 -// * @return CompletableFuture 异步任务的 Future 对象,包含任务执行结果 -// */ -// public static CompletableFuture supplyAsync(List> scopedValues, Supplier supplier) { -// Map, V> scopedValueMap = captureContext(scopedValues); -// return supplyAsync(scopedValueMap, supplier); -// } -// -// /** -// * 在异步任务中传播 ScopedValue 上下文(有返回值) -// *

-// * 根据提供的 ScopedValue 上下文映射,在异步任务中恢复这些值的绑定。 -// * 这是最底层的传播方法,其他 supplyAsync 方法最终都会调用此方法。 -// *

-// * -// * @param scopedValueMap ScopedValue 到其值的映射,表示需要传播的上下文 -// * @param supplier 异步执行的任务,返回结果 -// * @param ScopedValue 的值类型 -// * @param 异步任务的返回值类型 -// * @return CompletableFuture 异步任务的 Future 对象,包含任务执行结果 -// * @throws NullPointerException 如果 supplier 为 null -// */ -// public static CompletableFuture supplyAsync(Map, V> scopedValueMap, Supplier supplier) { -// Objects.requireNonNull(supplier, "supplier must not be null"); -// -// if (scopedValueMap == null || scopedValueMap.isEmpty()) { -// return CompletableFuture.supplyAsync(supplier, executorService); -// } -// -// return CompletableFuture.supplyAsync(() -> { -// ScopedValue.Carrier carrier = buildCarrier(scopedValueMap); -// return carrier.call(supplier::get); -// }, executorService); -// } -// -// /** -// * 在异步任务中传播 ScopedValue 上下文(无返回值) -// *

-// * 根据提供的 ScopedValue 上下文映射,在异步任务中恢复这些值的绑定。 -// * 这是最底层的传播方法,其他 runAsync 方法最终都会调用此方法。 -// *

-// * -// * @param scopedValueMap ScopedValue 到其值的映射,表示需要传播的上下文 -// * @param runnable 异步执行的任务 -// * @param ScopedValue 的值类型 -// * @return CompletableFuture 异步任务的 Future 对象 -// * @throws NullPointerException 如果 runnable 为 null -// */ -// public static CompletableFuture runAsync(Map, V> scopedValueMap, Runnable runnable) { -// Objects.requireNonNull(runnable, "runnable must not be null"); -// -// return supplyAsync(scopedValueMap, () -> { -// runnable.run(); -// return null; -// }); -// } -// -// /** -// * 构建 ScopedValue.Carrier 对象 -// *

-// * Carrier 用于在新的执行上下文中批量绑定多个 ScopedValue。 -// * 通过链式调用 where() 方法构建包含所有绑定的 Carrier。 -// *

-// * -// * @param scopedValueVMap ScopedValue 到其值的映射 -// * @param ScopedValue 的值类型 -// * @return ScopedValue.Carrier 对象,如果映射为空则返回 null -// */ -// public static ScopedValue.Carrier buildCarrier(Map, V> scopedValueVMap) { -// if (scopedValueVMap == null || scopedValueVMap.isEmpty()) return null; -// -// ScopedValue.Carrier carrier = null; -// for (Map.Entry, V> entry : scopedValueVMap.entrySet()) { -// if (carrier == null) { -// carrier = ScopedValue.where(entry.getKey(), entry.getValue()); -// } else { -// carrier = carrier.where(entry.getKey(), entry.getValue()); -// } -// } -// return carrier; -// } -// -// /** -// * 捕获当前线程中已绑定的 ScopedValue -// *

-// * 遍历指定的 ScopedValue 列表,提取所有在当前线程中已绑定的值, -// * 构建成 Map 以便后续在异步线程中恢复。未绑定或为 null 的 ScopedValue 会被忽略。 -// *

-// * -// * @param scopedValues 需要捕获的 ScopedValue 列表 -// * @param ScopedValue 的值类型 -// * @return Map, V> 包含已绑定值的映射,如果没有绑定值则返回空 Map -// */ -// public static Map, V> captureContext(List> scopedValues) { -// Map, V> scopedValueMap = new HashMap<>(); -// if (scopedValues != null && !scopedValues.isEmpty()) { -// scopedValues.forEach(scopedValue -> { -// if (scopedValue != null && scopedValue.isBound()) { -// scopedValueMap.put(scopedValue, scopedValue.get()); -// } -// }); -// } -// return scopedValueMap; -// } -// -// /** -// * 安全获取 ScopedValue 的绑定值 -// *

-// * 与 {@link ScopedValue#get()} 不同,此方法在 ScopedValue 未绑定时返回 null, -// * 而不是抛出 {@link NoSuchElementException} 异常。适用于需要容错处理的场景。 -// *

-// * -// *

使用场景:

-// *
    -// *
  • 不确定 ScopedValue 是否已绑定时
  • -// *
  • 需要优雅处理未绑定情况,避免异常
  • -// *
  • 可选的上下文传递场景
  • -// *
-// * -// *

使用示例:

-// *
{@code
-//     * ScopedValue USER_ID = ScopedValue.newInstance();
-//     *
-//     * // 安全获取,不会抛异常
-//     * String userId = ScopeValueUtil.getOrNull(USER_ID);
-//     * if (userId != null) {
-//     *     System.out.println("User ID: " + userId);
-//     * }
-//     * }
-// * -// * @param scopedValue 需要获取值的 ScopedValue,允许为 null -// * @param ScopedValue 的值类型 -// * @return 已绑定的值,如果未绑定或 scopedValue 为 null 则返回 null -// * @see ScopedValue#get() -// * @see ScopedValue#isBound() -// */ -// public static V getOrNull(ScopedValue scopedValue) { -// if (scopedValue != null && scopedValue.isBound()) { -// return scopedValue.get(); -// } else { -// return null; -// } -// } -// -//}