📜 ⬆️ ⬇️

Lambda expressions in Java, how and why to serialize them?



The lambda expression mechanism introduced in Java8 has become such a feature that clearly separated the code before and after (it seems the same can happen with Java9 and the modular system, but in a bad sense). Java8 has more functional tricks, various processing of large data arrays has become much easier and now takes up much less space. However, regarding the rational use of lambda expressions, there are many questions such as: how rational is it often to use them? Whether a significant loss of performance is lost when moving from a normal loop to `forEach ()` with a lambda expression, and so on. Most courses (even an Oracle course ) ignore these questions. This post will describe just one of the least popular questions, but no less interesting than the others:
How does lambda expression serialization work in Java and how can it be used?



How to make a lambda expression serialized?


First of all, it is important to understand that the lambda function in Java is still an object with one unrealized method (the rest can be declared as default methods in the interface (c) uthark ), and not a function . That is, all the same manipulations are available with it as with ordinary objects. In other words, a lambda function that implements a serializable interface will be serializable.
')
public interface SDoubleUnaryOperator extends DoubleUnaryOperator, Serializable { } public static void main(String[] args){ SDoubleUnaryOperator t = t->t*t; // - } 

However, with new features in Java8, a more simplified version became available, without creating an additional interface:

 public static void main(String[] args){ DoubleUnaryOperator t = (DoubleUnaryOperator & Serializable)t->t*t; // - } 

In both cases, instead of creating the usual lambda function, the compiler will create the lambda function in a special, serialized form. Then you can work with the lambda function as with any other object being serialized, if you do not forget about ...

How is the lambda function serialized?


To parse the process of serialization of lambda functions, the following class was created:

 import java.io.*; public class Main { public static void main(String[] args) throws Exception { //saveLambda(); loadLambda(); } public static void saveLambda() throws IOException { Factory factory = new Factory(3); ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream(new File("lambdas"))); output.writeObject(factory.createLambda(4,new SerializableData(3.3,4))); output.writeObject(factory.createLambda(5,new SerializableData(5.3,-4))); output.writeObject(factory.createLambda(3,new SerializableData(10.3,+80e-5))); output.close(); } public static void loadLambda() throws IOException, ClassNotFoundException { ObjectInputStream input = new ObjectInputStream(new FileInputStream(new File("lambdas"))); DoubleToString operator1 = (DoubleToString) input.readObject(); DoubleToString operator2 = (DoubleToString) input.readObject(); DoubleToString operator3 = (DoubleToString) input.readObject(); System.out.println(operator1.get(5)); System.out.println(operator2.get(5)); System.out.println(operator3.get(5)); } } 

The full code can be found here .

During serialization, the lambda function serializes all the variables that are used in it, and the external object in which it is implemented, if it uses the fields of this object. Accordingly, if at least one of the required components is not serializable, an error java.io.NotSerializableException will be received. The serialized lambda function knows nothing about what it should do with the data. It knows only the identifier of the corresponding special class for this function.

For me personally, this was a slight disappointment. In fact, during the serialization of the lambda function, it simply serializes the list of parameters that are used in it and its identifier. However, after some thought and experimentation, I found several useful features and one practical example of using lambda-serialization serialization.

Features serialization lambda functions



Practical use of lambda function serialization


The only useful way I found using lambda-serialization functions is to get lambda-functions from a class that is loaded during program execution. The fact is that I did not find standard methods for obtaining lambda functions that were implemented in this class. So serialization can help transfer lambda functions between programs or embed them in external modules.

To begin with, we implement some external class:

 public class RemoteLambdaClass{ public static void main(String[] args) throws Exception{ DoubleUnaryOperator t1 = (DoubleUnaryOperator & Serializable) t->t*t; DoubleUnaryOperator t2 = (DoubleUnaryOperator & Serializable) t->t*t*t; ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream(new File("lambdas"))); output.writeObject(t1); output.writeObject(t2); output.close(); } } 

After its launch, the file `lambdas` will be created, in which the serialized lambda functions will be located. Next, create a simple class for reading (it is assumed that the external class and the file are in the RemoteLambdaClass folder in the project root):

 public class Main { public static void main(String[] args) throws Exception { File f = new File("./RemoteLambdaClass/"); //       URLClassLoader mainLoader = (URLClassLoader) Main.class.getClassLoader(); Field classPathField = URLClassLoader.class.getDeclaredField("ucp"); classPathField.setAccessible(true); URLClassPath urlClassPath = (URLClassPath) classPathField.get(mainLoader); urlClassPath.addURL(f.toPath().toUri().toURL()); Class<?> clazz = mainLoader.loadClass("RemoteLambdaClass"); ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(new File(f,"lambdas"))); DoubleUnaryOperator o1 = (DoubleUnaryOperator) inputStream.readObject(); DoubleUnaryOperator o2 = (DoubleUnaryOperator) inputStream.readObject(); System.out.println(o1.applyAsDouble(2)); System.out.println(o2.applyAsDouble(2)); } } 

Results of performance:

 4.0 8.0 

Total

Serialization of lambda functions is a rather interesting, but practically useless mechanism. The reasons for making them serializable are hidden rather in avoiding problems with serialized interfaces. Nevertheless, I think this mechanism can come up with a few more applications that I missed.

Source: https://habr.com/ru/post/264003/


All Articles