Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is reference to an instance method serializable in Java 8?

Tags:

java-8

I want to know if reference to an instance method of an arbitrary object of a particular type is serializable or not?

Example:

public class MyClass {
    public void foo() {
        System.out.println("Serializable");
    }
}

SerializableConsumer

@FunctionalInterface
public interface SerializableConsumer<T> extends Consumer<T>, Serializable {
}

and field is:

SerializableConsumer<MyClass> serializableMethod = MyClass::foo;

EDITED

like image 731
Saljack Avatar asked May 05 '17 12:05

Saljack


Video Answer


1 Answers

Assuming that SerializableFunction refers to a type that extends Serializable, the method reference will be serializable. There is nothing special about the particular type of method reference your are asking for.

Most notably, the “reference to an instance method of an arbitrary object” is not capturing any instance of MyClass, hence, the fact that MyClass isn’t Serializable is not important. It would be different if you were referring to an instance method of a particular instance like object::foo, as in that case, the object had to be serialized as well, which will fail at runtime, if its class doesn’t implement Serializable.

What will not work, is to refer to a void method as a Function of return type Void. I don’t know how your SerializableFunction<MyClass, Void> is defined, but if it is equivalent to Function<MyClass, Void>&Serializable, it will not work.

When you have an appropriate functional interface, serializing the method reference is no problem:

import java.io.*;
import java.util.function.Consumer;

public class MyClass {
    public void foo() {
        System.out.println("Serializable");
    }
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Consumer<MyClass> consumer = (Consumer<MyClass>&Serializable)MyClass::foo;

        byte[] serialized;
        try(ByteArrayOutputStream baos=new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos)) {
            oos.writeObject(consumer);
            oos.flush();
            serialized=baos.toByteArray();
        }

        Consumer<MyClass> deserialized;
        try(ByteArrayInputStream bais=new ByteArrayInputStream(serialized);
            ObjectInputStream ois=new ObjectInputStream(bais)) {
            deserialized = (Consumer<MyClass>)ois.readObject();
        }

        deserialized.accept(new MyClass());
    }
}

As said, references to a specific instance have to serialize the target instance, hence, depend on the serializability of that instance so

import java.io.*;
import java.util.function.Consumer;

public class MyClass {
    public void foo() {
        System.out.println("Serializable");
    }
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Runnable runnable = (Runnable&Serializable)new MyClass()::foo;

        byte[] serialized;
        try(ByteArrayOutputStream baos=new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos)) {
            oos.writeObject(runnable);
            oos.flush();
            serialized=baos.toByteArray();
        }

        Runnable deserialized;
        try(ByteArrayInputStream bais=new ByteArrayInputStream(serialized);
            ObjectInputStream ois=new ObjectInputStream(bais)) {
            deserialized = (Runnable)ois.readObject();
        }

        deserialized.run();
    }
}

will fail at runtime with a java.io.NotSerializableException: MyClass, unless you change MyClass to implement Serializable.

like image 66
Holger Avatar answered Nov 23 '22 07:11

Holger