在我们的Web应用程序项目中,我们使用Redis来管理 session 。为了支持它,我们正在序列化将存储在 session 中的任何对象。
例如,我们使用DTO来保存用于显示在屏幕上的bean数据。即使DTO在(合成)内部具有任何其他对象,我们也必须对其进行序列化,否则我们将获得NotSerializableException
。
创建匿名内部类以实现Comparator
时遇到问题,如下所示:
Collections.sort(people, new Comparator<Person>() {
public int compare(Person p1, Person p2) {
return p1.getLastName().compareTo(p2.getLastName());
}
});
上面的代码抛出了
NotSerializableException
,我通过创建一个实现了Comparator
以及Serializable
接口(interface)的类来解决了这个问题。问题是,它被扔在使用此DTO的JSP
页面中。我不得不进行大量调试才能找到实际的问题。但是现在,我想更改上面的代码以使用Lambda表达式,如下所示:
Collections.sort(people, (p1, p2) -> p1.getLastName().compareTo(p2.getLastName()));
但是,我担心可能会发生相同的异常。 Lambda表达式是否在内部创建对象?
最佳答案
您可以通过以下方式创建可序列化的lambda表达式
Collections.sort(people, (Comparator<Person>&Serializable)
(p1, p2) -> p1.getLastName().compareTo(p2.getLastName()));
但应注意的是,通过创建一个
Comparator
(p1, p2) -> p1.getLastName().compareTo(p2.getLastName())
不鼓励使用冗余。您要调用
getLastName()
两次,无论哪种情况,都必须注意在正确的参数变量上调用它。使用起来更简单Comparator.comparing(Person::getLastName)
反而。您还可以使此比较器可序列化,尽管这意味着失去了很多简洁性:
Collections.sort(people,
Comparator.comparing((Function<Person,String>&Serializable)Person::getLastName));
这也更加健壮。 lambda表达式的序列化形式包含对实现方法的引用,在第一个变体中,该方法是具有编译器生成名称的合成方法,当您在定义方法中使用另一个lambda表达式时,该名称可能会更改。相反,
Person::getLastName
将命名方法getLastName
指向实现方法(至少使用javac
)。但是通常,可序列化的lambda表达式可能包含令人惊讶的编译器依赖性,因此应谨慎使用。
由于它们只是用来描述行为而不是数据,因此长期存储它们是没有意义的。为了在具有相同代码库的JVM之间传输它们,它们就足够了。
关于java - 带有序列化的Java 8 Lambda表达式,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/41718021/