Reputation: 6894
How can a Runnable
be converted to a 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);
}
Here I would like to reuse the method useSupplier
for useRunnable
, for example because I do not want to duplicate the code. The behavior of useSupplier
does not matter for this question, let's say it wraps thrown exceptions, or uses the supplier in a synchronized block.
Edit: To clarify, the method useSupplier
does not interact with the supplied value, it just returns it. The functionality of useSupplier
is to retrieve the value from the supplier in some context, in my case it catches (specific) RuntimeException
s, creates a new exception with it as cause and throws it:
public <T> T useSupplier(Supplier<T> supplier) {
try {
return supplier.get();
}
catch (RuntimeException runtimeException) {
throw new MyException("Supplier threw exception", runtimeException);
}
}
The following solutions do not work (in Java 8):
useSupplier(runnable);
useSupplier(runnable::run);
useSupplier((Supplier<Void>) runnable::run);
One solution I could come up with is creating a new Supplier
which returns an arbitrary value:
useSupplier(() -> {
runnable.run();
return null;
});
Is there a smaller solution?
Edit: As pointed out by Holger in the comments, using runnable::run
will also create new lambda instances since it is stateful, see also this answer.
Upvotes: 7
Views: 3940
Reputation: 21123
If you find yourself using this pattern a lot in your codebase, it might be worth creating a 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));
}
I've made this class generic since null
can be returned for suppliers of all generic types. This makes it possible to use in library methods that require Supplier
s of a specific type, so long as they allow null results. If you want to enforce that it's always a Supplier<Void>
, it's straightforward to make it non-generic and implement Supplier<Void>
instead of Supplier<T>
.
Upvotes: 0
Reputation: 31878
Looking at your design, you might just be looking for Consumer
which accepts a type and just processes(consumes) it without return a value and can be used to adapt a runnable as well, instead of a Supplier
which on the other hand is expected to return (supplies) a value post-processing.
You could use something like :
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);
}
If the requirement is to use the Supplier
for sure, then you can invoke that method as :
public static void useRunnable(Runnable runnable) {
useSupplier(() -> runnable); // the useSupplier returns the 'runnable' when this method is called
}
As mentioned in the comments, now when you invoke useRunnable
, the useSupplier
would return the same runnable
, but the method useRunnable
is void
again and hence its ignored altogether.
Upvotes: 0
Reputation: 549
In your case you cannot avoid creating new object. Even if there is a method somewhere that converts a Runnable to a Supplier, it will create an object there. So your solution is valid, you won't find any better.
Pay attention to that Supplier is expected to provide values and Runnable just represents an action. They are used for different purposes. So your need of converting Runnable to Supplier may be a result of a design problem involved.
Upvotes: 8