Java 什么';确保函数参数可序列化的最佳方法是什么?

Java 什么';确保函数参数可序列化的最佳方法是什么?,java,lambda,java-8,serializable,Java,Lambda,Java 8,Serializable,我正在编写一个可序列化的类,它接受多个参数,包括一个函数: public class Cls implements Serializable { private final Collection<String> _coll; private final Function<String, ?> _func; public Cls(Collection<String> coll, Function<String, ?> fun

我正在编写一个可序列化的类,它接受多个参数,包括一个
函数

public class Cls implements Serializable {
    private final Collection<String> _coll;
    private final Function<String, ?> _func;

    public Cls(Collection<String> coll, Function<String, ?> func) {
        _coll = coll;
        _func = func;        
    }
}
问题:

  • 现在,
    coll
    func
    参数之间不匹配,因为
    func
    在签名中声明为可序列化,但
    coll
    不是,但两者都需要可序列化才能工作
  • 它不允许其他可序列化的
    函数
    实现
  • 在构造函数上使用类型参数:

    public <F extends Function<String, ?> & Serializable>
    Cls(Collection<String> coll, F func) {...}
    

    Cls c=new-Cls(strList,(函数和可序列化)Foo::processStr);
    
    在我看来,这很难看,使用lambda的初始天真实现肯定会失败,而不可能像使用
    coll
    那样工作(因为大多数集合都是可以序列化的)。这还将类的实现细节推送到调用方

  • 目前我倾向于选择2,因为它对呼叫方的负担最小,但我认为这里没有理想的解决方案。对于如何正确地做到这一点,还有其他建议吗


    编辑:可能需要一些背景知识。这是一个在内部以螺栓形式运行的类,该类被序列化以传输到remove集群执行。在集群上运行时,该函数正在对已处理的元组执行操作。因此,它是可序列化的,并且函数参数是可序列化的,这在很大程度上是类用途的一部分。如果不是,则该类根本不可用。

    在大多数情况下,答案是:不要

    您可能会注意到,JRE的大多数类甚至不在其签名中强制执行
    Serializable
    。有太多的API不是专门针对序列化的,其中关于实现
    Serializable
    的对象的编译时信息丢失,如果后者将其输入强制为
    Serializable
    ,则将它们与序列化一起使用将需要大量类型转换

    由于其中一个参数是
    集合
    ,因此您可以从该API获得示例:

    :

    如果指定的列表可序列化,则返回的列表将可序列化

    您将发现更多这样的操作,它们注意保留序列化功能,而不保留结果上的
    Serializable
    编译时类型

    这也适用于所有非
    public
    类型,例如
    Collections.emptyList()
    数组.asList(…)
    Comparator.reverseOrder()的结果。它们都是
    可序列化的
    ,无需声明


    此外,每一个用例多于序列化的类都应该避免强制总是
    可序列化
    。这将妨碍不涉及序列化的使用

    关于<代码>集合< /C>参数,您可以考虑删除可串行化约束。通常情况下,您可以保护您的类不受稍后对所接收集合的更改的影响。一个简单的解决方案是复制集合,在执行此操作时,可以使用支持序列化的类型

    即使您希望避免复制,序列化本身也是一个复制过程,因此您可以简单地创建自定义的
    readObject
    writeObject
    方法来存储
    集合的内容
    ,无需使用
    可序列化的
    集合



    总而言之,通常的策略是,如果您的类的用户打算序列化它的实例,那么用户的责任是放入其中的所有组件本身都是可序列化的,为什么要删除第二个选项?只需将
    public
    修饰符放置在正确的位置,即类型参数声明之前
    public Cls(Collection coll,F func){…
    @thecoop:我猜,您是在谈论传递lambda表达式的尝试,因为它与实现两个接口的具体类型一起工作。因此,如果编译器无法推断lambda表达式的类型参数,则必须插入显式类型转换(或提供类型参数)。然后,它并不比选项3更简洁,但它仍然强制执行约束,这正是您的问题所在。Java泛型在变得复杂和难看之前已经走了这么远。如果您想要FP质量(用代码表示),请使用更具功能的JVM语言,如Scala。尽管Scala也有自己的问题。暂时的Java泛型+laMDA是一个很容易就开始使用的C++模板:非常好,不稳定,而且使用得很好。过度开发它不会有效率地发展。我的意思是:最好不要指定最大值。使用java的一个主要原因是类型安全。en暗示您的设计存在一些根本性的错误。也就是说,不要尝试序列化函数,而只是序列化数据并使用类存储函数。不幸的是,序列化将所有规则都抛到了窗外。这是一种语言功能,它被称为库功能。它是一种动态类型伪装成静态类型特性的ng特性。它违反了OO的所有规则(对象不再是由构造函数专门创建的)。因此,就像@bhspencer这样的人会对你指手画脚一样,一旦你使用序列化,你已经处于一个严重妥协的世界,你只能选择面前最不坏的替代方案。添加了一些关于为什么需要序列化的更多信息
    public <F extends Function<String, ?> & Serializable>
    Cls(Collection<String> coll, F func) {...}
    
    Cls c = new Cls(strList, (Function<String, ?> & Serializable)s -> ...);
    
    Cls c = new Cls(strList, (Function<String, ?> & Serializable)Foo::processStr);