Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 Lambda expression with Serialization

In our Web application project, we are using the Redis to manage the session. To support it, we are serializing any object which will be stored in the session.

For example, we use DTO's to hold the bean data which is used to display on the screen. Even if the DTO having any other object inside (Composition) we also have to serialize it otherwise, we get NotSerializableException.

I had a problem when I was creating an anonymous inner class to implement the Comparator like below:

Collections.sort(people, new Comparator<Person>() {
    public int compare(Person p1, Person p2) {
        return p1.getLastName().compareTo(p2.getLastName());
    }
});

The above code threw the NotSerializableException and I resolved it by creating a class that implements the Comparator as well as Serializable interface. The problem was, it was thrown inside the JSP page which was using this DTO. I had to do a lot of debugging to find the actual problem.

But now, I'm wondering to change the above code to use Lambda expression like below:

Collections.sort(people, (p1, p2) -> p1.getLastName().compareTo(p2.getLastName()));

However, I fear the same exception might occur. Does the Lambda expression create objects internally?

like image 623
VPK Avatar asked Jan 18 '17 11:01

VPK


People also ask

How do you serialize a lambda expression?

We can serialize a lambda expression if its target type and its captured arguments have serialized. However, like inner classes, the serialization of lambda expressions is strongly discouraged. As the lambda function is not serialized by default we simply have to cast our lambda to java. io.

Does Java 8 have serialization?

Serializable interface. Classes that do not implement this interface will not have any of their state serialized or deserialized. All subtypes of a serializable class are themselves serializable. The serialization interface has no methods or fields and serves only to identify the semantics of being serializable.

Which is correct about Java 8 lambda expression?

Explanation. Both of the above options are correct. Q 5 - Which of the following is correct about Java 8 lambda expression? A - Lambda expressions are used primarily to define inline implementation of a functional interface.

Is lambda expressions introduced in Java 8?

Lambda Expressions were added in Java 8. A lambda expression is a short block of code which takes in parameters and returns a value. Lambda expressions are similar to methods, but they do not need a name and they can be implemented right in the body of a method.


2 Answers

You can create a serializable lambda expression via

Collections.sort(people, (Comparator<Person>&Serializable)
    (p1, p2) -> p1.getLastName().compareTo(p2.getLastName()));

but it should be noted, that creating a Comparator via

(p1, p2) -> p1.getLastName().compareTo(p2.getLastName())

bears a discouraged redundancy. You are calling getLastName() twice and have to care to invoke it on the right parameter variable in either case. It is more straight-forward to use

Comparator.comparing(Person::getLastName)

instead. You can also make this comparator serializable, though that implies loosing much of the conciseness:

Collections.sort(people,
    Comparator.comparing((Function<Person,String>&Serializable)Person::getLastName));

This is also more robust. The serialized form of a lambda expression contains a reference to the implementation method, which is in the first variant a synthetic method with a compiler generated name that might change when you use another lambda expression within the defining method. In contrast, Person::getLastName points the the named method getLastName as implementation method (at least with javac).

But generally, serializable lambda expressions might contain surprising compiler dependencies and should be used with care.

Since they are meant to describe behavior rather than data, there is no point in long-term storage of them anyway. For transferring them between JVMs with the same code base, they are sufficient.

like image 52
Holger Avatar answered Oct 14 '22 11:10

Holger


lambda

Yes it does create an Object. The second parameter is of type Comparator, so that's what will be created implicitly.

See this: Does a lambda expression create an object on the heap every time it's executed?


Embedded Redis

On a side note, you'd benefit in allowing your application to run locally. To start an embedded Redis server, you may take a look at my personal project on github: https://github.com/alexbt/sample-spring-boot-data-redis-embedded.

It's using the following dependencies:

<dependency>
    <groupId>com.github.kstyrc</groupId>
    <artifactId>embedded-redis</artifactId>
    <version>0.6</version>
</dependency>

and mostly these 3 lines to handle it:

new RedisServer(redisPort);
redisServer.start();
redisServer.stop();

You could even do that in a side project, just to stop/start Redis on a specific port. It would be even better if you integrate it inside the application trigger with a specific a Spring Profile, but that will be more work in the short term.


The library's website: https://github.com/kstyrc/embedded-redis:

Running RedisServer is as simple as:

RedisServer redisServer = new RedisServer(6379);
redisServer.start();
// do some work
redisServer.stop();
like image 32
alexbt Avatar answered Oct 14 '22 12:10

alexbt