How to define a function using Serializable lambda parameter as parameter
Is it possible to declare a method taking a Serializable lambda as a parameter without declaring a dedicated interface or asking the client to cast a lambda ?
Let's use this toy example to illustrate my question:
static <T, R> void serialize(Function<T, R> f) throws IOException {
try (ObjectOutputStream oos = new ObjectOutputStream(new ByteArrayOutputStream())) {
oos.writeObject(f);
}
}
public static void main(String[] args) throws IOException {
serialize(e -> e);
}
Lambdas are not Serializable by default and expected is NotSerializableException
selected.
To make it work, we can use lambda to add an additional Serializable binding.
static <T, R> void serialize(Function<T, R> f) throws IOException {
try (ObjectOutputStream oos = new ObjectOutputStream(new ByteArrayOutputStream())) {
oos.writeObject(f);
}
}
public static void main(String[] args) throws IOException {
serialize((Function<Object, Object> & Serializable) e -> e);
}
However, this solution is frustrating as it forces each caller to use a different lambda and the method signature indicates that it f
should be serializable. It is verbose and error prone.
To remove the template and make it safe, we can define a dedicated interface:
interface SerFunction<T, R> extends Function<T, R>, Serializable { }
static <T, R> void serialize(SerFunction<T, R> f) throws IOException {
try (ObjectOutputStream oos = new ObjectOutputStream(new ByteArrayOutputStream())) {
oos.writeObject(f);
}
}
public static void main(String[] args) throws IOException {
serialize(e -> e);
}
It does the job and almost satisfies my needs. The only downside to this pattern is that I have to create a dedicated interface on top of each functional interface, which is a bit cumbersome. Is it possible to get an additional interface and declare multiple bounds directly in the method signature?
source to share
I know this question is quite old, but since it has no answer, I will try to try it.
However, this solution is frustrating as it forces every caller to cast their lambda and the method signature shows that f should be serialized. It is verbose and error prone.
Although this solution still requires you to declare that your lambda expression also implements the Serializable interface, this requires require .
So it gives an error when not implemented. It also allows the use of Children functions if they do not implement SerFunction.
public static <T, R, F extends Function<T, R> & Serializable> void serialize(F f) throws IOException
{
try (ObjectOutputStream oos = new ObjectOutputStream(new ByteArrayOutputStream()))
{
oos.writeObject(f);
}
}
public static void main(String[] args) throws IOException
{
serialize((Function<Object, Object> & Serializable) e -> e);
// all happy
serialize((Function<Object, Object>) e -> e);
// compiler error "no instance(s) of type variable(s) exist so that Function<Object, Object> conforms to Serializable
// inference variable F has incompatible bounds:
// lower bounds: Function<Object, Object>
// upper bounds: Function<T, R>, Serializable"
}
source to share