将 Runnable 转换为 Supplier

Convert Runnable to Supplier

如何将 Runnable 转换为 Supplier

public <T> T useSupplier(Supplier<T> supplier) {
    // Does something with supplier and returns supplied value
    ...
    return value;
}

public void useRunnable(Runnable runnable) {
    // Somehow convert runnable to Supplier
    ...
    useSupplier(supplier);
}

在这里我想为 useRunnable 重用方法 useSupplier,例如因为我不想重复代码。 useSupplier 的行为对于这个问题并不重要,假设它包装抛出的异常,或者在同步块中使用供应商。


编辑:澄清一下,方法 useSupplier 不与提供的值交互,它只是 returns 它。 useSupplier 的功能是在某些上下文中从供应商检索值,在我的例子中它捕获(特定的)RuntimeExceptions,创建一个新的异常作为原因并抛出它:

public <T> T useSupplier(Supplier<T> supplier) {
    try {
        return supplier.get();
    }
    catch (RuntimeException runtimeException) {
        throw new MyException("Supplier threw exception", runtimeException);
    }
}

以下解决方案 工作(在 Java 8 中):

useSupplier(runnable);
useSupplier(runnable::run);
useSupplier((Supplier<Void>) runnable::run);

我能想出的一个解决方案是创建一个新的 Supplier 其中 returns 一个任意值:

useSupplier(() -> {
    runnable.run();
    return null;
});

有没有更小的解决方案?

编辑:正如 Holger 在评论中指出的那样,使用 runnable::run 也将创建新的 lambda 实例,因为它是有状态的,另请参见 this answer

在您的情况下,您无法避免创建新对象。即使某处存在将 Runnable 转换为 Supplier 的方法,它也会在那里创建一个对象。 所以你的解决方案是有效的,你不会找到更好的。

注意Supplier需要提供值,而Runnable只是代表一个action。它们用于不同的目的。因此,您需要将 Runnable 转换为 Supplier 可能是涉及设计问题的结果。

看看你的设计,你可能只是在寻找 Consumer 它接受一个类型并且只处理(消耗)它而没有 return 一个值并且也可以用来适应一个可运行的,而不是 Supplier ,另一方面,它预期 return (提供)一个值 post-processing.

你可以使用类似的东西:

private static <T> void useConsumer(Consumer<T> consumer, T val) {
    // Does something with supplier and returns supplied value
    consumer.accept(val);
}

public static <T> void useRunnable(Runnable runnable) {
    useConsumer(Runnable::run, runnable);
}

如果要求肯定要使用 Supplier,那么您可以调用该方法:

public static void useRunnable(Runnable runnable) {
    useSupplier(() -> runnable); // the useSupplier returns the 'runnable' when this method is called
}

如评论中所述,现在当您调用 useRunnable 时,useSupplier 将 return 与 runnable 相同,但方法 useRunnablevoid 再次被忽略。

如果您发现自己在代码库中大量使用此模式,可能值得创建一个 RunnableSupplier class:

public class RunnableSupplier<T> implements Supplier<T> {
    private final Runnable runnable;

    public RunnableSupplier(Runnable runnable) {
        this.runnable = runnable;
    }

    @Override
    public T get() {
        runnable.run();
        return null;
    }
}
public void useRunnable(Runnable runnable) {
    useSupplier(new RunnableSupplier(runnable));
}

我已将此 class 设为通用,因为 null 可以为所有通用类型的供应商返回。这使得在需要特定类型的 Suppliers 的库方法中使用成为可能,只要它们允许空结果。如果你想强制它始终是 Supplier<Void>,可以直接将其设为非泛型并实现 Supplier<Void> 而不是 Supplier<T>.