She*_*Wei 2 java lambda jvm java-8 apache-spark-sql
我有多年的 Java 8 及其 lambda 经验。但当我开发一个 hello-world 大小的 Spark 程序时,我遇到了一个疯狂的问题。
这里我有一个Java类,其中的Data注释来自Lombok:
@Data
public class Person implements Serializable {
private String name;
private Long age;
}
Run Code Online (Sandbox Code Playgroud)
然后我构建了一个包含Persion类对象的 java 列表:
Person p1 = new Person("sb", 1L);
Person p2 = new Person("sth", null);
List<Person> list = new ArrayList<>(2);
list.add(p1);
list.add(p2);
Run Code Online (Sandbox Code Playgroud)
到目前为止一切都很好。然后我尝试使用该列表生成 Spark 数据集:
SparkSession session = SparkSession.builder().master("local[1]").appName("SparkSqlApp").getOrCreate();
Encoder<Person> personEncoder = Encoders.bean(Person.class);
Dataset<Person> dataset1 = session.createDataset(list, personEncoder);
dataset1.foreach(new ForeachFunction<Person>() { // 1
@Override
public void call(Person person) throws Exception {
System.out.println(person);
}
});
dataset1.foreach((ForeachFunction<Person>) System.out::println); //2
Run Code Online (Sandbox Code Playgroud)
请注意,块 1 相当于 java 中的块 2,块 2 是 IntelliJ IDEA 对块 1 的简化。唯一的区别是块 2 使用 lambda 表达式。
然而,当我执行程序时,块 1 正常结束,而块 2 运行异常:

什么……大地球、大宇宙?为什么 JVM 或 Spark 引擎会做出这样的事情?!
正如什么是 System.out::println 的等效 lambda 表达式中所述,方法引用System.out::println与 lambda 表达式不同x -> System.out.println(x)。
方法引用捕获System.out,的当前值println,以便在每次调用函数时对其进行调用,而不是System.out像 lambda 表达式\xe2\x80\x99s 主体那样每次都重新求值。
正如前面所说,这很少会产生影响,但在这里,却会产生影响。当您尝试序列化该函数时,它将尝试序列化所有捕获的值,包括实例化期间PrintStream读取的实例System.out。它PrintStream是不可序列化的,并且实现PrintStream满足期望的可序列化将是相当具有挑战性的。
但重要的是要记住,当您序列化 lambda 表达式x -> System.out.println(x)或等效的类对象并在不同的环境中反序列化它时,它将System.out在那里读取的值将与PrintStream原始环境中的值不同。当分布式计算框架小心地将打印到标准输出的所有内容通过管道返回给发起者时,这并不重要。
但重要的是要记住,static不属于序列化数据的字段通常在不同环境中可能具有不同的内容。
| 归档时间: |
|
| 查看次数: |
225 次 |
| 最近记录: |