I`m trying to implement a java callable with multiple methods and my situation is like this:
interface FsHandler {
boolean existDirectory();
boolean existFile(File);
...
}
interface FileHandler {
void write(byte[]);
void read(byte[]);
...
}
All these methods are implemented by different storage backends like local file system, aws s3, etc
While search for a way to parallelise this code, I tried to use callable but if I understood correctly, I would need to to break my interface in many small abstract classes that implements callable - one for each method and then use callable, not to mention that I would still need to find a way to add the call to the blocking queue (which is using an executor)
So, my doubts are:
e.g.:
interface WriteStrategy implements Callable<Void> {
Void call();
void write(byte[]);
static WriteStrategy localFSStrategy(){...}
static WriteStrategy S3Strategy() {...}
class FileHandler {
private WriteStrategy strategy;
public FileHandler(WriteStrategy strategy) {...}
public void write(byte[]) { strategy.call(); }
}
I`m still not sure how to approach it :'(
You don't even need to declare any of the classes with implements Callable
.
Instead you could use method references or lambda declarations which have the correct signature for the Callable
interface with the appropriate auto-boxing for the return types. This allows one class to provide multiple Callable
implementations.
Here are some examples of different styles:
class Impl {
public Impl() {};
public void write(byte[] bytes) {
throw new RuntimeException("not implemented yet");
}
public int doSomeOp() {
return 0;
}
public byte[] read() {
throw new RuntimeException("not implemented yet");
}
}
public static void main(String[] args)
{
Impl impl = new Impl();
byte[] ba = {65, 66, 67};
// Method references with different return types
Callable<Integer> callable1 = impl::doSomeOp;
Callable<byte[]> callable2 = impl::read;
// lambda for void method, or methods needing extra arguments
Callable<Void> callable3 = () -> { impl.write(ba); return null; };
// Then you can use with ExecutorService:
ExecutorService executor = Executors.newCachedThreadPool();
Future<Integer> task1 = executor.submit(callable1);
// You don't even need to declare the local variable "callable1"
Future<Integer> task2 = executor.submit(impl::doSomeOp);
}