确保Function参数可序列化的最佳方法是什么?

时间:2015-06-29 11:53:25

标签: java lambda java-8 serializable

我正在编写一个带有多个参数的可序列化类,包括Function

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;        
    }
}

func存储在成员变量中,因此需要可序列化。 Java lambdas are serializable if the type they're being assigned to is serializable。确保在构造函数中传递Function的最佳方法是可序列化的,如果它是使用lambda创建的那么?

  1. 创建SerializableFunction类型并使用:

    public interface SerializableFunction<F, R> implements Function<F, R>, Serializable {}
    ....
    public Cls(Collection<String> coll, SerializableFunction<String, ?> func) {...}
    

    的问题:

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

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

    的问题:

    • 比1更灵活,但更令人困惑。
    • 两个参数之间仍然存在不匹配 - 在编译时类型层次结构中实现func需要Serializable参数,但只需要coll是可序列化的以某种方式(尽管如果需要可以抛弃此要求)。

    编辑尝试使用lambda或方法引用进行调用时,此代码实际上并未编译。

  3. 将其留给来电者

    这要求调用者知道(来自javadocs,或者试错)参数需要可序列化,并在适当时进行转换:

    Cls c = new Cls(strList, (Function<String, ?> & Serializable)s -> ...);
    

    Cls c = new Cls(strList, (Function<String, ?> & Serializable)Foo::processStr);
    

    这是丑陋的IMO,使用lambda的初始天真实现是保证中断,而不是像coll那样工作(因为大多数集合都是以某种方式可序列化的)。这也将类的实现细节推送到调用者。

  4. 目前我倾向于选择2,作为对呼叫者施加最小负担的选项,但我不认为这是一个理想的解决方案。有关如何正确执行此操作的任何其他建议吗?

    编辑:也许需要一些背景知识。这是一个在storm内部运行的类,在一个bolt中,它被序列化以传输到一个删除集群来执行。该功能在群集上运行时对已处理的元组执行操作。因此,它可以序列化并且函数参数是可序列化的,这是该类的目的的很大一部分。如果不是,则该课程根本不可用。

1 个答案:

答案 0 :(得分:7)

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

您可能会注意到JRE的大多数类,甚至ObjectOutputStream.writeObject都没有在其签名中强制执行Serializable。有太多的API没有特别针对序列化,其中有关实现Serializable的对象的编译时信息丢失,如果后者强制其输入为{{1,则需要大量的类型转换}}

由于您的某个参数是Serializable,因此您可以从该API获取示例:

Collections.unmodifiableList

  

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

您会发现更多这些操作需要保留序列化功能,而不会在结果上保留Collection编译时类型。

这也适用于所有非Serializable类型,例如publicCollections.emptyList()Arrays.asList(…)的结果。它们都是Comparator.reverseOrder()而没有声明它。

此外,每个具有更多用例而不仅仅是序列化的类应该避免强制执行Serializable。这会妨碍不涉及序列化的用途。

关于Serializable参数,您可以考虑删除可序列化约束。通常情况下,您可以保护您的课程免受以后对您收到的集合的更改。一个简单的解决方案是复制集合,当您执行此操作时,您可以使用支持序列化的类型。

即使您想避免复制,序列化本身也是一个复制过程本身,因此您只需创建存储内容的自定义CollectionreadObject方法 writeObject,无需拥有Collection集合。

总结一下,通常策略是如果你的类的用户打算序列化它的实例,那么用户有责任将所有组件放入其中{{1} }。