¿Por qué mi expresión lambda de Java no puede funcionar mientras que su estilo imperativo funciona correctamente?
Tengo años de experiencia en Java 8 y sus lambdas. Sin embargo, me encontré con un problema insano cuando desarrollaba un programa Hello World utilizando Spark.
Aquí tengo una clase Java, en la cual la anotación Data viene de Lombok:
java
@Data
public class Person implements Serializable {
private String name;
private Long age;
}
Luego construí una lista Java que contenía objetos de la clase Person
:
java
Person p1 = new Person("alguien", 1L);
Person p2 = new Person("otro alguien", null);
List<Person> list = new ArrayList<>(2);
list.add(p1);
list.add(p2);
hasta aquí todo bien. Luego intenté generar un conjunto de datos Spark a través de la lista:
java
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
Tenga en cuenta que el bloque 1 es equivalente al bloque 2 en Java y el bloque 2 está simplificado a partir del bloque 1 por IntelliJ IDEA. La única diferencia es que el bloque 2 está utilizando una expresión lambda.
Sin embargo, cuando ejecuto el programa, el bloque 1 termina bien, mientras que el bloque 2 se ejecuta con una excepción:
¿Qué demonios está pasando? ¿Por qué la JVM o el motor Spark hacen cosas como esta?
davy.ai
El problema aquí está relacionado con la manera en que se compilan las lambdas en Java. Cuando se utiliza una expresión lambda, el compilador genera una clase anónima para encapsular el cuerpo de la lambda. Esta clase anónima es lo que se pasa al motor de Spark para su ejecución. Sin embargo, en este caso, el método
println
en la expresión lambda requiere un tipo de retornovoid
, mientras que el métodocall
en la clase anónima generada por el compilador tiene un tipo de retornovoid
. Esto crea una discrepancia entre los tipos de retorno esperados y reales, lo que resulta en la excepción.Para resolver este problema, puedes seguir usando el bucle
foreach
en el bloque 1, o modificar la expresión lambda en el bloque 2 para incluir una sentenciareturn
:Al incluir una sentencia
return
, estás especificando explícitamente el tipo de retornovoid
esperado por el métodocall
en la clase anónima. Esto debería permitir que la expresión lambda se ejecute sin problemas.