我正在编写一个带有多个参数的可序列化类,包括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创建的那么?
创建SerializableFunction
类型并使用:
public interface SerializableFunction<F, R> implements Function<F, R>, Serializable {}
....
public Cls(Collection<String> coll, SerializableFunction<String, ?> func) {...}
的问题:
coll
和func
参数之间存在不匹配,因为func
在签名中声明为可序列化,但coll
不是,但两者都需要序列化才能发挥作用。Function
实现。在构造函数上使用type参数:
public <F extends Function<String, ?> & Serializable>
Cls(Collection<String> coll, F func) {...}
的问题:
func
需要Serializable
参数,但只需要coll
是可序列化的以某种方式(尽管如果需要可以抛弃此要求)。编辑尝试使用lambda或方法引用进行调用时,此代码实际上并未编译。
将其留给来电者
这要求调用者知道(来自javadocs,或者试错)参数需要可序列化,并在适当时进行转换:
Cls c = new Cls(strList, (Function<String, ?> & Serializable)s -> ...);
或
Cls c = new Cls(strList, (Function<String, ?> & Serializable)Foo::processStr);
这是丑陋的IMO,使用lambda的初始天真实现是保证中断,而不是像coll
那样工作(因为大多数集合都是以某种方式可序列化的)。这也将类的实现细节推送到调用者。
目前我倾向于选择2,作为对呼叫者施加最小负担的选项,但我不认为这是一个理想的解决方案。有关如何正确执行此操作的任何其他建议吗?
编辑:也许需要一些背景知识。这是一个在storm内部运行的类,在一个bolt中,它被序列化以传输到一个删除集群来执行。该功能在群集上运行时对已处理的元组执行操作。因此,它可以序列化并且函数参数是可序列化的,这是该类的目的的很大一部分。如果不是,则该课程根本不可用。
答案 0 :(得分:7)
在大多数情况下,答案是:不。
您可能会注意到JRE的大多数类,甚至ObjectOutputStream.writeObject
都没有在其签名中强制执行Serializable
。有太多的API没有特别针对序列化,其中有关实现Serializable
的对象的编译时信息丢失,如果后者强制其输入为{{1,则需要大量的类型转换}}
由于您的某个参数是Serializable
,因此您可以从该API获取示例:
如果指定的列表是可序列化的,则返回的列表将是可序列化的。
您会发现更多这些操作需要保留序列化功能,而不会在结果上保留Collection
编译时类型。
这也适用于所有非Serializable
类型,例如public
,Collections.emptyList()
和Arrays.asList(…)
的结果。它们都是Comparator.reverseOrder()
而没有声明它。
此外,每个具有更多用例而不仅仅是序列化的类应该避免强制执行Serializable
。这会妨碍不涉及序列化的用途。
关于Serializable
参数,您可以考虑删除可序列化约束。通常情况下,您可以保护您的课程免受以后对您收到的集合的更改。一个简单的解决方案是复制集合,当您执行此操作时,您可以使用支持序列化的类型。
即使您想避免复制,序列化本身也是一个复制过程本身,因此您只需创建存储内容的自定义Collection
和readObject
方法 writeObject
,无需拥有Collection
集合。
总结一下,通常策略是如果你的类的用户打算序列化它的实例,那么用户有责任将所有组件放入其中{{1} }。