igr
igr

Reputation: 10604

Adapt `Callable` to `Supplier` in Java8

I have the following code blocks on several places in one class:

    final Key key = ...;
    return CompletableFuture.supplyAsync(
            () -> FooDelegate.call(key, () -> {
                return doSomething();
            }
    }...

I want to adapt TO Supplier (needed for supplyAsync()) FROM custom Callable code block. Method FooDelegate.call() wraps the real code-block (here it is just doSomething(), provided as lambda) - and we need to pass more then one arguments, like the key (i.e. FooDelegate is not going to be a functional interface).

Code for FooDelegate, a separate class, since it needs to be reused:

public class FooDelegate {
    public static <T> T call(Key key, Callable<T> callable) {
        try {
            return callable.call();
        }
        catch (ExecutionException e) {
            ...
        }
        ... handle exceptions etc.
    }
}

My questions:

  1. Is there better way to do this: ...() -> FooDelegate.call(key, () -> {...

  2. FooDelegate is just a dummy class with single static method. Not sure if I like that. Anything better?

Upvotes: 0

Views: 2149

Answers (1)

Holger
Holger

Reputation: 298123

There is nothing wrong with classes providing static methods (or even a single static method). I’m not sure what you actually want to do, especially as the need for additional parameters is not clear but let’s suppose you are using it somewhere in the exception handling code and treating everything else as you have written, I guess what you actually want to do is:

public class FooDelegate {
    public static <T> Supplier<T> call(Key key, Callable<T> callable) {
        return () -> {
            try {
                return callable.call();
            }
            catch(ExecutionException e) {
                //...
                throw new RuntimeException(); // or return fall-back
            }
            catch(Exception ex) {
                //... handle exceptions etc.
                throw new RuntimeException(); // or return fall-back
            }
        };
    }
}

with the use case:

final Key key = null;//...;
return CompletableFuture.supplyAsync(FooDelegate.call( key, () -> doSomething() ));

which can be simplified to

final Key key = null;//...;
return CompletableFuture.supplyAsync(FooDelegate.call(key, MyClass::doSomething ));

or

final Key key = null;//...;
return CompletableFuture.supplyAsync(FooDelegate.call(key, this::doSomething ));

depending on whether doSomething is a static or an instance method…


If you need your original method for other use cases you may consider providing two methods:

public class FooDelegate {
    public static <T> Supplier<T> supplier(Key key, Callable<T> callable) {
        return () -> call(key, callable);
    }
    public static <T> T call(Key key, Callable<T> callable) {
        try {
            return callable.call();
        }
        catch(ExecutionException e) {
            //...
            throw new RuntimeException(); // or return fall-back
        }
        catch(Exception ex) {
            //... handle exceptions etc.
            throw new RuntimeException(); // or return fall-back
        }
    }
}

and change the use site to

final Key key = null;//...;
return CompletableFuture.supplyAsync(FooDelegate.supplier(key, () -> doSomething() ));

etc.

Upvotes: 1

Related Questions