如何将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。
答案 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>
。