将Runnable转换为供应商

时间:2019-02-10 15:39:31

标签: java java-8 functional-interface

如何将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);
}

在这里,我想为useSupplier重用方法useRunnable,例如,因为我不想重复代码。 useSupplier的行为与该问题无关,可以说它包装了抛出的异常,或在同步块中使用了供应商。


编辑:为明确起见,方法useSupplier不与提供的值交互,它仅返回它。 useSupplier的功能是在某种情况下从供应商那里获取价值,在我的情况下,它捕获(特定的)RuntimeException s,创建一个新的异常作为原因并抛出该异常:

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,该返回值可以是任意值:

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

有较小的解决方案吗?

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

3 个答案:

答案 0 :(得分:7)

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

请注意,供应商应提供价值,而Runnable仅代表一种行动。它们用于不同的目的。因此,您需要将Runnable转换为Supplier的原因可能是涉及的设计问题。

答案 1 :(得分:1)

查看您的设计,您可能只是在寻找接受类型的Consumer,而无需返回值就可以处理(消耗)该类型,并且可以用来适应可运行对象,而不是{{ 1}},另一方面,它有望返回(提供)后处理值。

您可以使用类似:

Supplier

如果要求确定使用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,但是方法runnable再次为useRunnable因此完全被忽略了。

答案 2 :(得分:0)

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

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

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