高效的Java任务执行:SafeExecutor工具类的设计理念与应用

286 阅读10分钟

本文皆为Derek_Smart个人原创,请尊重创作,未经许可不得转载。

摘要

在开发中,异常处理和任务执行是两个关键的挑战。为了简化异常处理和任务执行,设计并实现了一个名为 SafeExecutor 的工具类。该工具类提供了一组方法,用于安全地执行同步和异步任务,并在发生异常时进行处理。本文详细介绍了 SafeExecutor 的设计与实现,以及与之配套的两个接口 VoidCallableCallableWithParams

关键词

Java, 异常处理, 任务执行, 同步任务, 异步任务, 框架设计


1. 引言

开发中,异常处理和任务执行是两个重要的挑战。异常处理需要每个可能抛出异常的地方编写 try-catch 块,会导致代码变得冗长且难以维护。此外,异步任务的执行和管理也变得越来越重要,特别是在处理 I/O 操作或长时间运行的任务时。

为了简化这些问题,设计并实现了一个名为 SafeExecutor 的工具类。该工具类通过封装异常处理逻辑和提供统一的任务执行方法,使代码更加简洁和易读。本文将详细介绍 SafeExecutor 的设计与实现,以及与之配套的两个接口 VoidCallableCallableWithParams

2. 设计目标

SafeExecutor 的设计目标包括:

  1. 简化异常处理:通过封装异常处理逻辑,减少代码中的 try-catch 块,使代码更加简洁和易读。
  2. 统一的异常处理策略:提供一种统一的方式来处理异常,允许指定自定义的异常处理器。
  3. 支持同步和异步任务:提供方法来执行同步和异步任务,并在发生异常时进行处理。
  4. 默认值返回:在任务执行失败时,允许返回一个默认值,以保证程序的稳定性和连续性。
  5. 支持多参数和返回值的任务:处理带多个参数和返回值的任务,提供更高的灵活性和强大功能。

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 () -> {
        };
    }
}

企业微信截图_17398472313154.png

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;
    }
}

企业微信截图_17398471945068.png

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);
        }
    }
}

企业微信截图_17398471501827.png

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();
        }
    }
}

企业微信截图_17398471131884.png

5. 结论

本文详细介绍了 SafeExecutor 框架的设计与实现,以及与之配套的两个接口 VoidCallableCallableWithParams。通过这些工具,可以显著提高代码的可读性、可维护性和灵活性。SafeExecutor 通过简化异常处理、提供统一的异常处理策略、支持异步任务执行和默认值返回、以及处理复杂的多参数任务。

本文皆为Derek_Smart个人原创,请尊重创作,未经许可不得转载。