相关疑难解决方法(0)

如何序列化lambda?

我怎样才能优雅地序列化lambda?

例如,下面的代码抛出一个NotSerializableException.如何在不创建SerializableRunnable"虚拟"界面的情况下修复它?

public static void main(String[] args) throws Exception {
    File file = Files.createTempFile("lambda", "ser").toFile();
    try (ObjectOutput oo = new ObjectOutputStream(new FileOutputStream(file))) {
        Runnable r = () -> System.out.println("Can I be serialized?");
        oo.writeObject(r);
    }

    try (ObjectInput oi = new ObjectInputStream(new FileInputStream(file))) {
        Runnable  r = (Runnable) oi.readObject();
        r.run();
    }
}
Run Code Online (Sandbox Code Playgroud)

java lambda serialization java-8

152
推荐指数
4
解决办法
4万
查看次数

有没有办法比较lambdas?

假设我有一个使用lambda表达式(闭包)定义的对象列表.有没有办法检查它们,以便可以进行比较?

我最感兴趣的代码是

    List<Strategy> strategies = getStrategies();
    Strategy a = (Strategy) this::a;
    if (strategies.contains(a)) { // ...
Run Code Online (Sandbox Code Playgroud)

完整的代码是

import java.util.Arrays;
import java.util.List;

public class ClosureEqualsMain {
    interface Strategy {
        void invoke(/*args*/);
        default boolean equals(Object o) { // doesn't compile
            return Closures.equals(this, o);
        }
    }

    public void a() { }
    public void b() { }
    public void c() { }

    public List<Strategy> getStrategies() {
        return Arrays.asList(this::a, this::b, this::c);
    }

    private void testStrategies() {
        List<Strategy> strategies = getStrategies();
        System.out.println(strategies);
        Strategy a = (Strategy) …
Run Code Online (Sandbox Code Playgroud)

java lambda java-8

76
推荐指数
3
解决办法
1万
查看次数

为什么Arrays.fill()不再用于HashMap.clear()了?

我注意到在执行中有些奇怪HashMap.clear().这就是它在OpenJDK 7u40中的表现:

public void clear() {
    modCount++;
    Arrays.fill(table, null);
    size = 0;
}
Run Code Online (Sandbox Code Playgroud)

这就是OpenJDK 8u40的外观:

public void clear() {
    Node<K,V>[] tab;
    modCount++;
    if ((tab = table) != null && size > 0) {
        size = 0;
        for (int i = 0; i < tab.length; ++i)
            tab[i] = null;
    }
}
Run Code Online (Sandbox Code Playgroud)

我知道现在table为空地图可以为null,因此需要在局部变量中进​​行额外的检查和缓存.但为什么被Arrays.fill()for-loop取代?

似乎在此提交中引入了更改.不幸的是,我没有找到解释为什么普通for循环可能比更好Arrays.fill().它更快吗?还是更安全?

java arrays hashmap java-8

70
推荐指数
1
解决办法
4627
查看次数

lambda创建后的序列化

我可以使用以下语法序列化lambda:

Runnable r = (Runnable & Serializable) () -> System.out.println("");
try (ObjectOutput oo = new ObjectOutputStream(new ByteArrayOutputStream())) {
  oo.writeObject(r);
}
Run Code Online (Sandbox Code Playgroud)

但是,如果我从客户端代码收到lambda并且它没有被正确转换,我就无法序列化它.

如何r在不更改其定义的情况下序列化以下内容:

Runnable r = () -> System.out.println("");
Run Code Online (Sandbox Code Playgroud)

我试图序列化"派生"对象:

Runnable r1 = (Runnable & Serializable) r::run;
Runnable r2 = (Runnable & Serializable) () -> r.run();
Run Code Online (Sandbox Code Playgroud)

但在每种情况下,都oo.writeObject(rxxx);失败了NotSerializableException.

java lambda serialization java-8

13
推荐指数
1
解决办法
1605
查看次数

无法反序列化lambda

就像一个小项目一样,我一直试图做一个小东西,读取序列化的lambdas(本地或从FTP)并调用它们的运行函数作为测试的一部分来试验Windows中的文件关联(即打开某些文件类型)用某个程序打开它们等等,但无论我尝试什么,它似乎都没有正确地反序列化.

lambda被宣布为这样

Runnable r = (Runnable & Serializable) () -> {
    // blah blah
    // made sure not to capture anything
};
Run Code Online (Sandbox Code Playgroud)

并使用由ObjectOutputStream包装的[n optional] BufferedOutputStream包装的FileOutputStream进行序列化,没有问题.但是,当[在不同的项目中]反序列化时,它会失败,说它无法找到包含序列化代码的封闭类.我已经尝试过各种各样的东西,比如将它们包装在一个可序列化的类中(用于测试目的的是用serialVersionUID = 0L)或者定义一个扩展Runnable和Serializable的接口,但无济于事.

是的,我知道序列化lambda不是很好的做法(或者我们被告知),但我不知道如何将函数和子程序转换成我可以存储为文件或FTP的东西.如果这根本不是正确的方法,请告诉我们.

哦,我正在使用最新版本的Eclipse Luna.

编辑:

像这样反序列化

File f = new File(somePath);
FileInputStream fish = new FileInputStream(f);
BufferedInputStream bos = new BufferedInputStream(fish); // not really necessary
ObjectInputStream ois = new ObjectInputStream(bos);
Runnable r = (Runnable) ois.readObject();
ois.close();
r.run();
Run Code Online (Sandbox Code Playgroud)

java lambda serialization java-8

8
推荐指数
1
解决办法
2982
查看次数

如何安全地序列化lambda?

尽管可以在Java 8中序列化lambda,但强烈建议不要这样做.甚至不鼓励对内部类进行序列化.给出的原因是lambdas可能不会在另一个JRE上正确地反序列化.然而,这并不意味着这有一个办法可以安全的序列化拉姆达?

例如,假设我将类定义为:

public class MyClass {
    private String value;
    private Predicate<String> validateValue;

    public MyClass(String value, Predicate<String> validate) {
        this.value = value;
        this.validateValue = validate;
    }

    public void setValue(String value) {
        if (!validateValue(value)) throw new IllegalArgumentException();
        this.value = value;
    }

    public void setValidation(Predicate<String> validate) {
        this.validateValue = validate;
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我像这样声明了类的实例,我不应该序列化它:

MyClass obj = new MyClass("some value", (s) -> !s.isEmpty());
Run Code Online (Sandbox Code Playgroud)

但是如果我像这样创建了一个类的实例呢:

// Could even be a static nested class
public class IsNonEmpty …
Run Code Online (Sandbox Code Playgroud)

java lambda serialization java-8

8
推荐指数
1
解决办法
4287
查看次数

lambda表达式序列化的安全风险是什么?

刚刚介绍Streams和Java 8 Lambda功能,以及对其他不言自明的Oracle doc Lambda Expressions的最后评论:

如果lambda表达式的目标类型及其捕获的参数是可序列化的,则可以序列化它.但是,与内部类一样,强烈建议不要对lambda表达式进行序列化.

检查这一点我发现了SO问题

如何序列化lambda?

OP处理来自客户端代码的序列化lambda表达式.

如果我有一个互联网服务和参数之一是一个lambda表达式,现在看来,这可能包含恶意代码,可以做这样的事情的文件系统访问权限,或导致堆栈溢出 - 所以这将是非常愚蠢的信任它.

我是否过度夸大了安全风险,或者序列化表达式可以包含什么限制?

java lambda serialization java-8

8
推荐指数
1
解决办法
469
查看次数

序列化的lambda和没有serialVersionUID?

我正在尝试学习序列化如何与Java及其最新版本一起使用.我正在尝试序列化这样的lambda:

Runnable r = (Runnable & Serializable)() -> {System.out.println("This is a test");};
Run Code Online (Sandbox Code Playgroud)

但我注意到我没有关于缺少serialVersionUID变量的警告.这是正常的吗?

我知道它将在运行时生成,但强烈建议您定义它:https://docs.oracle.com/javase/8/docs/api/java/io/Serializable.html

如果可序列化类未显式声明serialVersionUID,则序列化运行时将基于类的各个方面计算该类的默认serialVersionUID值,如Java(TM)对象序列化规范中所述.但是,强烈建议所有可序列化类显式声明serialVersionUID值,因为默认的serialVersionUID计算对类细节高度敏感,这些细节可能因编译器实现而异,因此在反序列化期间可能导致意外的InvalidClassExceptions.因此,为了保证跨不同java编译器实现的一致的serialVersionUID值,可序列化类必须声明显式的serialVersionUID值.强烈建议显式serialVersionUID声明尽可能使用private修饰符,因为此类声明仅适用于立即声明的类 - serialVersionUID字段作为继承成员无用.数组类不能声明显式的serialVersionUID,因此它们始终具有默认的计算值,但是对于数组类,不需要匹配serialVersionUID值.

我该怎么办 ?如何在Lambda中定义它?

谢谢

java lambda serialization serialversionuid java-8

6
推荐指数
1
解决办法
764
查看次数