【发布时间】:2015-09-15 21:02:13
【问题描述】:
我正在编写一个带有多个参数的可序列化类,包括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 lambda 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实现。
- 现在
-
在构造函数上使用类型参数:
public <F extends Function<String, ?> & Serializable> Cls(Collection<String> coll, F func) {...}问题:
- 比 1 更灵活,但更令人困惑。
- 两个参数之间仍然不匹配 -
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 中,它被序列化以转移到一个remove 集群来执行。该函数在集群上运行时正在对已处理的元组执行操作。因此,类的可序列化和函数参数可序列化是该类目的的很大一部分。如果不是,则该类根本不可用。
【问题讨论】:
-
为什么要删除第二个选项?您只需将
public修饰符放在正确的位置,即在类型参数的声明之前。public <F extends Function<String, ?> & Serializable> Cls(Collection<String> coll, F func) { … -
@thecoop:我猜,您是在谈论传递 lambda 表达式的尝试,因为它适用于实现两个接口的具体类型。因此,如果编译器无法推断 lambda 表达式的类型参数,则必须插入显式类型转换(或提供类型参数)。那么它并不比选项 3 更简洁,但它仍然执行约束,这就是你的问题的全部内容。
-
Java 泛型在变得复杂和丑陋之前已经走了这么远。如果您想要 FP 质量(以代码表示),请使用功能更强大的 JVM 语言,例如 Scala。尽管 Scala 有自己的问题。一开始,java 泛型 + lambdas 让人想起 C++ 模板:非常好,不稳定,并且要适度使用。过度使用它不会有效地发展。我的意思是:最好不要指定最大值。
-
使用 Java 的主要原因之一是类型安全。鉴于您正在做的事情将类型安全抛到了窗外,我认为这应该被视为您的设计存在根本性错误的暗示。也就是说,不要尝试序列化函数,而只是序列化数据并使用类来存储函数。
-
不幸的是,序列化将所有规则抛到了窗外。它是一种伪装成库功能的语言功能。它是一种伪装成静态类型特性的动态类型特性。它违反了 OO 的所有规则(对象不再由构造函数专门创建)。所以,尽管像@bhspencer 这样的人会想对你摇摆手指,一旦你使用序列化,你已经处于一个严重妥协的世界,你只能选择最不坏的替代方案在你面前。
标签: java lambda java-8 serializable