Java1.8 关于Lambda表达式序列化问题

Lambda表达式是1.8特别重要的一个新增内容。

之前学习的时候,只注意了书上关于它的使用,语义等。直到前几天有个面试官问我:

问:Lambda表达式知道吗?

答:知道啊。(心里活动:问我问我,这个我前几天刚看过)

问:使用了Lambda表达式的对象可以序列化吗?为什么?

答:WTF???404 not find。您的问题超出了我的知识储备。

今天特地对这个问题进行了实验,顺便把Lambda和序列化进行再次复习。

关于Lambda和序列化的基础知识,咱们就不多说,随便一本java的书说的很清楚。推荐《Java核心技术》。

但是里面不会讲Lambda它能否序列化,以及为什么。

我百度了一下,很多答案是:默认不可以,但是用正确的方式,是可以进行序列化的

我自己写了一个实验代码。(借鉴几行了博主:诸相非相的代码)

// main运行代码
public class CreatingStreams {

    public static void main (String[] args){
        Comparator cmp=new ComparatorFactory().makeComparator();
        int i=10;
        int j =-5;
        System.out.println(cmp.compare(i, j));

        try {
            //写入字节流
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            ObjectOutputStream obs = new ObjectOutputStream(out);
            obs.writeObject(cmp);
            obs.close();
            System.out.println("a");
            //分配内存,写入原始对象,生成新对象
            ByteArrayInputStream ios = new ByteArrayInputStream(out.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(ios);
            //返回生成的新对象
            cmp = (Comparator)ois.readObject();
            ois.close();
            System.out.println("b");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("c");
        }
        System.out.println(cmp.compare(i, j));
    }

}
public class ComparatorFactory{
    public Comparator makeComparator(){
        return (x,y)->Integer.compareUnsigned((int)x,(int)y);
    }
}

代码较为简单,主要逻辑就是创建一个对象cmp(Comparator类型),使用Lambda表达式来实现该抽象函数。

看似没毛病,编译执行出错:

-1
c
-1
java.io.NotSerializableException: stream.ComparatorFactory$$Lambda$1/1791741888

可以看出,Lambda序列化出错。

我们仔细想一下,序列化对象是需要有实现序列化接口的。但这里我们并没有实现。implements Serializable

那么我们在哪里实现这个序列化接口呢?正常情况下,我们会在cmp对象的类定义时加上一句implements Serializable;

但是Comparator接口是没有这语句的...

那么我们怎么办?只能打开Comparator的代码,看看有没有什么发现。

发现里面有个默认方法,

default Comparator<T> thenComparing(Comparator<? super T> other) {
        Objects.requireNonNull(other);
        return (Comparator<T> & Serializable) (c1, c2) -> {
            int res = compare(c1, c2);
            return (res != 0) ? res : other.compare(c1, c2);
        };
    }

该方法的具体用途我们就不说了,只需要看到return (Comparator<T> & Serializable) (c1,c2)->{exp}

是不是很眼熟??!!返回值里面带有类型转换!!!给Comparator<T>加上了Serializable的标志!!!

神操作啊,没想到吧,接口也可以进行类型转化的。

根据这个启发,我们修改一下我们的代码为

public class ComparatorFactory {
    public Comparator makeComparator(){
        return (Comparator&Serializable)(x,y)->Integer.compareUnsigned((int)x,(int)y);
    }
}

再次运行,成功:

-1
a
b
-1

故而,Lambda是可以进行序列化的。

小白一枚,因为技术原因,写的一定有很多疏漏之处,还请大家批判性阅读。谢谢斧正。

(写博客初衷只是为了鞭策自己,好好学习)

猜你喜欢

转载自blog.csdn.net/m0_37128231/article/details/81811835