本文皆为Derek_Smart个人原创,请尊重创作,未经许可不得转载。
摘要
在开发中,异常处理和任务执行是两个关键的挑战。为了简化异常处理和任务执行,设计并实现了一个名为 SafeExecutor
的工具类。该工具类提供了一组方法,用于安全地执行同步和异步任务,并在发生异常时进行处理。本文详细介绍了 SafeExecutor
的设计与实现,以及与之配套的两个接口 VoidCallable
和 CallableWithParams
。
关键词
Java, 异常处理, 任务执行, 同步任务, 异步任务, 框架设计
1. 引言
开发中,异常处理和任务执行是两个重要的挑战。异常处理需要每个可能抛出异常的地方编写 try-catch 块,会导致代码变得冗长且难以维护。此外,异步任务的执行和管理也变得越来越重要,特别是在处理 I/O 操作或长时间运行的任务时。
为了简化这些问题,设计并实现了一个名为 SafeExecutor
的工具类。该工具类通过封装异常处理逻辑和提供统一的任务执行方法,使代码更加简洁和易读。本文将详细介绍 SafeExecutor
的设计与实现,以及与之配套的两个接口 VoidCallable
和 CallableWithParams
。
2. 设计目标
SafeExecutor
的设计目标包括:
- 简化异常处理:通过封装异常处理逻辑,减少代码中的 try-catch 块,使代码更加简洁和易读。
- 统一的异常处理策略:提供一种统一的方式来处理异常,允许指定自定义的异常处理器。
- 支持同步和异步任务:提供方法来执行同步和异步任务,并在发生异常时进行处理。
- 默认值返回:在任务执行失败时,允许返回一个默认值,以保证程序的稳定性和连续性。
- 支持多参数和返回值的任务:处理带多个参数和返回值的任务,提供更高的灵活性和强大功能。
3. 设计与实现
3.1 VoidCallable 接口
VoidCallable
是一个函数式接口,表示一个无参数且不返回值的任务。该接口可以抛出异常。
package com.dereksmart.crawling.util.fuction;
import java.io.Serializable;
/**
* VoidCallable 是一个函数式接口,表示一个无参数且不返回值的任务。
* 该接口可以抛出异常。
*
* @Author derek_smart
* @Date 2025/2/18 8:40
*/
public interface VoidCallable extends Serializable {
/**
* 执行任务。
*
* @throws Exception 如果任务执行过程中发生异常
*/
void call() throws Exception;
/**
* 执行函数,异常包装为RuntimeException
*/
default void callWithRuntimeException() {
try {
call();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 执行函数,不返回异常
*/
default void callWithoutException() {
try {
call();
} catch (Exception e) {
// call quietly
}
}
/**
* 空方法
*
* @return
*/
static VoidCallable empty() {
return () -> {
};
}
}
3.2 CallableWithParams 接口
CallableWithParams
是一个泛型函数式接口,表示一个带有多个参数并返回结果的任务。该接口可以抛出异常。
package com.dereksmart.crawling.util.fuction;
import java.io.Serializable;
/**
* CallableWithParams 是一个泛型接口,允许执行带有多个参数的任务并返回一个结果。
*
* @param <R> 返回值的类型
* @param <P> 参数的类型
* @Author derek_smart
* @Date 2025/2/18 8:45
*/
@FunctionalInterface
public interface CallableWithParams<R, P> extends Serializable {
/**
* 执行任务
*
* @param params 参数
* @return 任务的结果
* @throws Exception 自定义异常
*/
R call(P... params) throws Exception;
/**
* 执行任务,异常包装为RuntimeException
*
* @param params 参数
* @return 任务的结果
*/
default R callWithRuntimeException(P... params) {
try {
return call(params);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 执行任务,不返回异常
*
* @param params 参数
* @return 任务的结果
*/
default R callWithoutException(P... params) {
try {
return call(params);
} catch (Exception e) {
// call quietly
return null;
}
}
/**
* 空方法
* @return 一个空的 CallableWithParams 实例
*/
static <R, P> CallableWithParams<R, P> empty() {
return params -> null;
}
}
3.3 SafeExecutor 类
SafeExecutor
是一个实用类,提供了一组静态方法来安全地执行同步和异步任务,并在发生异常时进行处理。
package com.dereksmart.crawling.util.fuction;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.function.Supplier;
/**
* 提供了一组静态方法来安全地执行同步和异步任务。
* 这些方法在执行过程中捕获异常,并通过指定的异常处理器处理异常。
* 该类提供了无返回值和有返回值的任务执行方法,并支持默认值和异常处理器的自定义。
* @Author derek_smart
* @Date 2025/2/18 8:50
*/
public final class SafeExecutor {
/**
* 默认的异常处理器,忽略所有异常。
*/
public static final Consumer<Exception> IGNORE_EXCEPTION_HANDLER = e -> {
};
private SafeExecutor() {
// Private constructor to prevent instantiation
}
// 同步方法
/**
* 执行一个无返回值的任务,并忽略任何异常。
*
* @param callable 要执行的任务
*/
public static void executeWithoutException(VoidCallable callable) {
execute(callable, IGNORE_EXCEPTION_HANDLER);
}
/**
* 执行一个无返回值的任务,并使用指定的异常处理器处理异常。
*
* @param callable 要执行的任务
* @param exceptionHandler 异常处理器
*/
public static void execute(VoidCallable callable, Consumer<Exception> exceptionHandler) {
try {
callable.call();
} catch (Exception e) {
handleException(e, exceptionHandler);
}
}
/**
* 执行一个有返回值的任务,并忽略任何异常。如果发生异常,返回 null。
*
* @param supplier 要执行的任务
* @param <T> 返回值的类型
* @return 任务的返回值,如果发生异常则返回 null
*/
public static <T> T supplyWithoutException(Supplier<T> supplier) {
return supplyWithoutException(supplier, null, IGNORE_EXCEPTION_HANDLER);
}
/**
* 执行一个有返回值的任务,并忽略任何异常。如果发生异常,返回指定的默认值。
*
* @param supplier 要执行的任务
* @param defaultValue 默认返回值
* @param <T> 返回值的类型
* @return 任务的返回值,如果发生异常则返回默认值
*/
public static <T> T supplyWithoutException(Supplier<T> supplier, T defaultValue) {
return supplyWithoutException(supplier, defaultValue, IGNORE_EXCEPTION_HANDLER);
}
/**
* 执行一个有返回值的任务,并使用指定的异常处理器处理异常。如果发生异常,返回指定的默认值。
*
* @param supplier 要执行的任务
* @param defaultValue 默认返回值
* @param exceptionHandler 异常处理器
* @param <T> 返回值的类型
* @return 任务的返回值,如果发生异常则返回默认值
*/
public static <T> T supplyWithoutException(Supplier<T> supplier, T defaultValue, Consumer<Exception> exceptionHandler) {
try {
return supplier.get();
} catch (Exception e) {
handleException(e, exceptionHandler);
}
return defaultValue;
}
/**
* 异步执行一个无返回值的任务,并忽略任何异常。
*
* @param callable 要执行的任务
*/
public static void executeAsyncWithoutException(VoidCallable callable) {
executeAsync(callable, IGNORE_EXCEPTION_HANDLER);
}
/**
* 异步执行一个无返回值的任务,并使用指定的异常处理器处理异常。
*
* @param callable 要执行的任务
* @param exceptionHandler 异常处理器
*/
public static void executeAsync(VoidCallable callable, Consumer<Exception> exceptionHandler) {
CompletableFuture.runAsync(() -> {
try {
callable.call();
} catch (Exception e) {
handleException(e, exceptionHandler);
}
});
}
/**
* 异步执行一个有返回值的任务,并忽略任何异常。如果发生异常,返回 null。
*
* @param supplier 要执行的任务
* @param <T> 返回值的类型
* @return 一个 CompletableFuture,表示任务的返回值,如果发生异常则返回 null
*/
public static <T> CompletableFuture<T> supplyAsyncWithoutException(Supplier<T> supplier) {
return supplyAsyncWithoutException(supplier, null, IGNORE_EXCEPTION_HANDLER);
}
/**
* 异步执行一个有返回值的任务,并忽略任何异常。如果发生异常,返回指定的默认值。
*
* @param supplier 要执行的任务
* @param defaultValue 默认返回值
* @param <T> 返回值的类型
* @return 一个 CompletableFuture,表示任务的返回值,如果发生异常则返回默认值
*/
public static <T> CompletableFuture<T> supplyAsyncWithoutException(Supplier<T> supplier, T defaultValue) {
return supplyAsyncWithoutException(supplier, defaultValue, IGNORE_EXCEPTION_HANDLER);
}
/**
* 异步执行一个有返回值的任务,并使用指定的异常处理器处理异常。如果发生异常,返回指定的默认值。
*
* @param supplier 要执行的任务
* @param defaultValue 默认返回值
* @param exceptionHandler 异常处理器
* @param <T> 返回值的类型
* @return 一个 CompletableFuture,表示任务的返回值,如果发生异常则返回默认值
*/
public static <T> CompletableFuture<T> supplyAsyncWithoutException(Supplier<T> supplier, T defaultValue, Consumer<Exception> exceptionHandler) {
return CompletableFuture.supplyAsync(() -> {
try {
return supplier.get();
} catch (Exception e) {
handleException(e, exceptionHandler);
return defaultValue;
}
});
}
// 新增方法:处理带多个参数和返回值的任务
/**
* 执行一个带多个参数和返回值的任务,并忽略任何异常。
*
* @param callable 要执行的任务
* @param params 参数
* @param <R> 返回值的类型
* @param <P> 参数的类型
* @return 任务的返回值,如果发生异常则返回 null
*/
public static <R, P> R callWithoutException(CallableWithParams<R, P> callable, P... params) {
return callWithoutException(callable, null, IGNORE_EXCEPTION_HANDLER, params);
}
/**
* 执行一个带多个参数和返回值的任务,并使用指定的异常处理器处理异常。
*
* @param callable 要执行的任务
* @param defaultValue 默认返回值
* @param exceptionHandler 异常处理器
* @param params 参数
* @param <R> 返回值的类型
* @param <P> 参数的类型
* @return 任务的返回值,如果发生异常则返回默认值
*/
public static <R, P> R callWithoutException(CallableWithParams<R, P> callable, R defaultValue, Consumer<Exception> exceptionHandler, P... params) {
try {
return callable.call(params);
} catch (Exception e) {
handleException(e, exceptionHandler);
return defaultValue;
}
}
/**
* 异步执行一个带多个参数和返回值的任务,并忽略任何异常。
*
* @param callable 要执行的任务
* @param params 参数
* @param <R> 返回值的类型
* @param <P> 参数的类型
* @return 一个 CompletableFuture,表示任务的返回值,如果发生异常则返回 null
*/
public static <R, P> CompletableFuture<R> callAsyncWithoutException(CallableWithParams<R, P> callable, P... params) {
return callAsyncWithoutException(callable, null, IGNORE_EXCEPTION_HANDLER, params);
}
/**
* 异步执行一个带多个参数和返回值的任务,并使用指定的异常处理器处理异常。
*
* @param callable 要执行的任务
* @param defaultValue 默认返回值
* @param exceptionHandler 异常处理器
* @param params 参数
* @param <R> 返回值的类型
* @param <P> 参数的类型
* @return 一个 CompletableFuture,表示任务的返回值,如果发生异常则返回默认值
*/
public static <R, P> CompletableFuture<R> callAsyncWithoutException(CallableWithParams<R, P> callable, R defaultValue, Consumer<Exception> exceptionHandler, P... params) {
return CompletableFuture.supplyAsync(() -> {
try {
return callable.call(params);
} catch (Exception e) {
handleException(e, exceptionHandler);
return defaultValue;
}
});
}
/**
* 处理异常的方法。如果提供了异常处理器,则调用它来处理异常。
*
* @param e 异常
* @param exceptionHandler 异常处理器
*/
private static void handleException(Exception e, Consumer<Exception> exceptionHandler) {
if (Objects.nonNull(exceptionHandler)) {
exceptionHandler.accept(e);
}
}
}
SafeExecutor
的实现原理几个步骤:
1. 封装任务执行:通过 VoidCallable
和 CallableWithParams
接口,封装无返回值和有返回值的任务执行逻辑。任务执行过程中可能会抛出异常。
2. 捕获异常:在任务执行时,捕获所有可能的异常。
3. 处理异常:提供默认的异常处理器(忽略异常),并允许指定自定义的异常处理器来处理捕获的异常。
4. 返回默认值:在任务执行失败时,允许返回一个默认值,以保证程序的稳定性和连续性。
5. 支持异步执行:通过 CompletableFuture
支持异步任务的执行和异常处理,使得异步任务管理更加简洁和易读。
6. 多参数支持:通过 CallableWithParams
接口,支持带多个参数的任务执行,提供更高的灵活性和强大功能。
4. 使用示例
一个完整的代码示例,展示如何使用 SafeExecutor
工具类来执行不同类型的任务:
package com.dereksmart.crawling.util.fuction;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class Main {
public static void main(String[] args) {
// 同步示例
SafeExecutor.executeWithoutException(() -> {
System.out.println("Executing task synchronously...");
Thread.sleep(1000); // 模拟长时间运行的任务
});
String result = SafeExecutor.supplyWithoutException(() -> {
System.out.println("Supplying value synchronously...");
try {
Thread.sleep(1000); // 模拟长时间运行的任务
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Sync Result";
});
System.out.println("Sync Result: " + result);
// 异步示例
SafeExecutor.executeAsyncWithoutException(() -> {
System.out.println("Executing task asynchronously...");
Thread.sleep(1000); // 模拟长时间运行的任务
});
CompletableFuture<String> future = SafeExecutor.supplyAsyncWithoutException(() -> {
System.out.println("Supplying value asynchronously...");
try {
Thread.sleep(1000); // 模拟长时间运行的任务
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Async Result";
});
// 获取异步结果
try {
String asyncResult = future.get();
System.out.println("Async Result: " + asyncResult);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
// 使用 CallableWithParams 的同步示例
CallableWithParams<String, String> callable = (params) -> {
System.out.println("Executing task with params: " + params[0] + ", " + params[1]);
return "Result: " + params[0] + " " + params[1];
};
String syncCallResult = SafeExecutor.callWithoutException(callable, "Param1", "Param2");
System.out.println("Sync Call Result: " + syncCallResult);
// 使用 CallableWithParams 的异步示例
CompletableFuture<String> asyncCallFuture = SafeExecutor.callAsyncWithoutException(callable, "Param1", "Param2");
// 获取异步结果
try {
String asyncCallResult = asyncCallFuture.get();
System.out.println("Async Call Result: " + asyncCallResult);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
5. 结论
本文详细介绍了 SafeExecutor
框架的设计与实现,以及与之配套的两个接口 VoidCallable
和 CallableWithParams
。通过这些工具,可以显著提高代码的可读性、可维护性和灵活性。SafeExecutor
通过简化异常处理、提供统一的异常处理策略、支持异步任务执行和默认值返回、以及处理复杂的多参数任务。
本文皆为Derek_Smart个人原创,请尊重创作,未经许可不得转载。