I want to have a method like this
<T> void callFuncOnObj(T obj, Runnable r) {
obj.r();
//or
r.runOnTheInstance(obj);
}
that may be used something like this (ignoring exceptions)
callFuncOnObj(System.in, InputStream::close);
Obviously, Runnable
doesn't support this. Apparently, the type of InputStream::close
is just Object, so how can it be used or even cast so that a generic instance may call it?
The most obvious alternative I can think of is accepting a Method
and dealing with IllegalArgumentException
if it doesn't apply,
void callFuncOnObj(Object obj, Method m) {
try{
m.invoke(obj);
}catch(IllegalArgumentException iae) {
...
}...
}
Is there a good way to do this with generic instances and generic functions on those instances?
There a couple of problems. First, InputStream.close()
throws an exception, so it can't be passed as a Runnable
. You can either convert the method reference to a lambda containing a try/catch block, or create a custom parallel interface that allows exceptions:
@FunctionalInterface
interface CustomRunnable {
void run() throws Exception;
}
The other issue is that Runnable
doesn't accept any arguments. You can pass an instance method reference instead of passing the object separately:
void callFuncOnObj(CustomRunnable r) {
r.run();
}
Called like this:
callFuncOnObj(System.in::close);
Or you can accept the object with a Consumer
(or in this case, a similar interface that allows exceptions) and combine them like this:
<T> void callFuncOnObj(T obj, CustomConsumer<T> c) {
c.accept(obj);
}
And then your original call would work:
callFuncOnObj(System.in, InputStream::close);