Perché la mia versione di java espressione lambda non funziona, mentre il suo imperativo stile funziona correttamente?

0

Domanda

Ho anni di esperienza di Java 8 e la sua lambda. Ma ho incontrato un pazzo problema quando ho sviluppato un ciao-mondo-dimensioni Scintilla programma.

Qui ho una classe Java, in cui i Dati di annotazione è da Lombok:

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

E poi ho costruito un java elenco contenente gli oggetti di 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);

così bene finora. E poi ho provato a generare una Scintilla set di dati utilizzando l'elenco:

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

Si noti che il blocco 1 è equivalente al blocco 2 in java e il blocco 2 è semplificato dal blocco 1 da IntelliJ IDEA. L'unica differenza è il blocco 2 utilizza espressione lambda.

Tuttavia, quando ho eseguito il programma, blocco 1 finisce bene, mentre il blocco 2, in deroga: enter image description here

Che... che grande terra e grande universo? Perché la JVM o Spark fa cose come questa?!

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

Migliore risposta

7

Come spiegato in che Cosa è l'equivalente espressione lambda per il Sistema.fuori::println, il metodo di riferimento System.out::println non è identico per l'espressione lambda x -> System.out.println(x).

Il metodo di riferimento acquisisce il valore corrente di System.outper invocare il println su di esso ogni volta che la funzione viene richiamata, piuttosto che valutare System.out ogni volta che l'espressione lambda del corpo.

Come diceva anche, raramente questo fa la differenza, ma qui, non. Quando si tenta di serializzare la funzione, si cercherà di serializzare tutte catturato valori, tra cui la PrintStream esempio di lettura da System.out durante la creazione di istanze. Il PrintStream non è serializzabile e sarebbe molto difficile da attuare un serializable PrintStream a soddisfare le aspettative.

Ma è importante tenere a mente che quando si serializzare l'espressione lambda x -> System.out.println(x) o un equivalente oggetto di classe e deserializzare in un ambiente diverso, il System.out si leggerà ci restituirà un diverso PrintStream che in un ambiente originale. Questo non importa quando il quadro di calcolo distribuito, si prende cura di tubo di tutto ciò che è stampato sullo standard output il mittente.

Ma è importante tenere a mente che static i campi che non sono di parte dei dati serializzati può avere contenuti diversi in ambienti diversi in generale.

2021-11-24 08:36:53

Suona come si verifica solo con System.out?Io e sostituirlo con Registro quadro e bang! E ' riuscito. ForeachFunction<String> functionBody = log::info;
Sheldon Wei

Dipende dalla registrazione del quadro. Funzionerà se log è serializzabile.
Holger

Sembra che non si riferisce con il framework. Io uso java.util.logging.Logger che non è serializzabile.
Sheldon Wei

Non per l'installazione standard: ideone.com/F5lQZF “NotSerializableException: java.util.registrazione.Logger”. Tuttavia, in un ambiente specifico, un gestore del registro può restituire una sottoclasse di Logger con la serializzazione (o RMI) di supporto, inoltre, il quadro potrebbe utilizzare un esteso serializzazione in grado di gestire logger in un modo speciale.
Holger
1

L'interfaccia ForeachFunction si estende Serializable. Dataset.foreach(f) potrebbe essere la serializzazione dell'argomento f. Il seguente test, testBlock1 riesce e testBlcok2 non riesce (NotSerializableException). Ma non so perché.

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

Ho provato il tuo casi e in effetti, evento functionBody = t -> System.out.println(t) sarebbe successo. Così la fonte del problema, suppongo che il metodo di riferimento. Mi hai dato una grossa mano.
Sheldon Wei

Se la classe di test AAA non implementare Serializable nel mio codice, testBlock1 inoltre non sarà possibile. Il functionBody in testBlock1 è un anonimo classe interna della classe di test AAA e dovrebbe essere serializzato con un'istanza della classe AAA che la racchiude. Tuttavia, l' functionBody in testBlock2 non è una classe interna di classe AAA e non sembra per implementare Serializable nella sostanza.
英語は苦手

In altre lingue

Questa pagina è in altre lingue

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