在我们的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/

10-10 22:28