Por que meu java expressão lambda não pode trabalhar enquanto seu imperativo estilo funciona corretamente?

0

Pergunta

Eu tenho anos de experiência em Java 8 e suas lambda. Mas eu conheci um louco problema quando eu desenvolvi um olá mundo, do tamanho de programa Spark.

Aqui eu tenho uma classe Java, em que a anotação de Dados é de Lombok:

@Data
public class Person implements Serializable {
  private String name;
  private Long age;
}

E aí, eu fiz um java lista contendo os objetos de Persion classe:

        Person p1 = new Person("sb", 1L);
        Person p2 = new Person("sth", null);
        List<Person> list = new ArrayList<>(2);
        list.add(p1);
        list.add(p2);

tão bom tão longe. E, então, eu tentei gerar uma Faísca conjunto de dados usando a lista:

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

Observe que, o bloco 1 é equivalente ao bloco 2, em java, e o bloco 2 é simplificado do bloco 1 por IntelliJ IDEA. A única diferença é o bloco 2 está usando expressão lambda.

No entanto, quando eu executar o programa, bloco 1 termina bem, enquanto bloco 2 executada na exceção de: enter image description here

O que a " grande terra e big universo? Por que a JVM ou de Ignição de um motor de coisas como essa?!

apache-spark-sql java java-8 jvm
2021-11-24 03:11:05
2

Melhor resposta

7

Como explicado em o Que é o equivalente da expressão lambda para o Sistema.out::println, o método de referência System.out::println não é idêntica à expressão lambda x -> System.out.println(x).

O método de referência captura o valor atual de System.outpara invocar println nele cada vez que a função é invocada, em vez de avaliar System.out novamente a cada vez que como a expressão lambda do corpo.

Como também disse, isso raramente faz uma diferença, mas aqui não dá. Quando você tenta serializar a função, ele vai tentar serializar todos os valores capturados, incluindo o PrintStream exemplo de leitura de System.out durante a instanciação. O PrintStream não é serializável, e seria muito difícil implementar serializable PrintStream cumprindo as expectativas.

Mas é importante ter em mente que quando você serializar a expressão lambda x -> System.out.println(x) ou equivalente, com o objecto de classe e desserializar-lo em um ambiente diferente, o System.out ele vai ler lá vai avaliar diferentes PrintStream que no seu ambiente original. Isso não importa quando a computação distribuída quadro tem o cuidado de tubo de tudo impresso na saída padrão de volta para a origem.

Mas é importante ter em mente que static os campos que não fazem parte dos dados serializados podem ter diferentes conteúdos em diferentes ambientes em geral.

2021-11-24 08:36:53

Soa como ele ocorre apenas com System.out?E eu substituí-lo com o Registo de quadro e bang! É bem sucedido. ForeachFunction<String> functionBody = log::info;
Sheldon Wei

Depende do registo quadro. Ele vai funcionar se log é serializável.
Holger

Parece que não se relacionam com o quadro. Eu uso java.util.logging.Logger o que não é serializável.
Sheldon Wei

Não para a instalação padrão: ideone.com/F5lQZF "NotSerializableException: java.util.o registo.Logger". No entanto, em um ambiente específico, um gerenciador de log pode retornar uma subclasse de Logger com a serialização (ou RMI) apoiar, ainda mais, o quadro poderia usar um longo de serialização que pode lidar com madeireiros de uma maneira especial.
Holger
1

A interface ForeachFunction se estende Serializable. Dataset.foreach(f) pode ser serializar o argumento f. No teste a seguir, testBlock1 êxito e testBlcok2 falha (NotSerializableException). Mas eu não sei por que.

public class AAA implements Serializable {

    @FunctionalInterface
    public interface ForeachFunction<T> extends Serializable {
        void call(T t) throws Exception;
    }

    @Test
    public void testBlock1() throws FileNotFoundException, IOException {
        ForeachFunction<String> functionBody = new ForeachFunction<String>() {
            public void call(String t) throws Exception {
                System.out.println(t);
            }
        };
        try (FileOutputStream fos = new FileOutputStream("data/block1.obj");
            ObjectOutputStream oos = new ObjectOutputStream(fos)) {
            oos.writeObject(functionBody);  // success
        }
    }

    @Test
    public void testBlock2() throws FileNotFoundException, IOException {
        ForeachFunction<String> functionBody = System.out::println;
        try (FileOutputStream fos = new FileOutputStream("data/block2.obj");
            ObjectOutputStream oos = new ObjectOutputStream(fos)) {
            oos.writeObject(functionBody);  // fail (NotSerializableException)
        }
    }
}
2021-11-24 06:44:55

Eu testei os seus casos e, de fato, o evento functionBody = t -> System.out.println(t) seria bem-sucedida. Assim, a origem do problema, suponho, é o método de referência. Você me deu uma enorme mão.
Sheldon Wei

Se a classe de teste AAA não implementar Serializable no meu código, testBlock1 também irá falhar. O functionBody no testBlock1 é um anônimo interior de classe da classe de teste AAA e deve ser serializado com uma instância da classe AAA que abrange. No entanto, o functionBody no testBlock2 não é uma classe interna de classe AAA e não parece implementar Serializable em substância.
英語は苦手

Em outros idiomas

Esta página está em outros idiomas

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................