De ce mi java expresie lambda nu poate funcționa în timp ce imperativ stil funcționează în mod corespunzător?

0

Problema

Am ani de experienta de Java 8 și lambda. Dar am întâlnit un nebun problemă atunci când am dezvoltat un salut lume-dimensiune programul Spark.

Aici am o clasa Java, în care Datele de adnotare este din Lombok:

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

Și apoi am construit un java listă conținând obiecte de Persion clasa:

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

atât de bine până acum. Și apoi am încercat pentru a genera o Scânteie de Date folosind 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

Observați că, blocul 1 este echivalent cu bloc 2 în java și blocul 2 este simplificată din blocul 1 de IntelliJ IDEA. Singura diferență este blocul 2 este folosind expresie lambda.

Cu toate acestea, atunci când am executa programul, bloc 1 se termină cu bine, în timp ce blocul 2 a alerga într-excepție: enter image description here

Ce... mare de pământ și marele univers? De ce JVM sau Spark motor face lucruri de genul asta?!

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

Cel mai bun răspuns

7

Așa cum sa explicat în Ce este echivalent expresie lambda pentru Sistem.out::println, metoda de referință System.out::println nu este identic cu expresie lambda x -> System.out.println(x).

Metoda de referință surprinde valoarea curentă a System.out, pentru a invoca println pe ea de fiecare dată când funcția este invocată, mai degrabă decât evaluarea System.out din nou de fiecare dată ca expresie lambda e corpul.

Ca, de asemenea, a spus, acest lucru rareori face o diferenta, dar aici, nu. Atunci când încercați pentru a serializa funcția, acesta va încerca să serialize înregistrat valori, inclusiv PrintStream exemplu de citit System.out în timpul instanțierii. La PrintStream nu este serializable și ar fi destul de dificil să pună în aplicare o serializable PrintStream îndeplinirea așteptărilor.

Dar este important să păstrați în minte că, atunci când căreia îi dau expresie lambda x -> System.out.println(x) sau un echivalent obiect de clasă și deserialize într-un mediu diferit, de System.out se va citi acolo va evalua la un alt PrintStream decât în original mediului. Acest lucru nu contează atunci când distribuite de calcul cadru are grijă să teava totul tipărite la standard de ieșire înapoi la emitent.

Dar este important să păstrați în minte că static domenii care nu sunt parte a serializat de date pot avea conținuturi diferite în medii diferite, în general.

2021-11-24 08:36:53

Sună ca și cum acesta apare numai cu System.out?Și am înlocui-o cu Log-cadru și bang! Ea a reușit. ForeachFunction<String> functionBody = log::info;
Sheldon Wei

Depinde de logare cadru. Acesta va funcționa dacă log este serializable.
Holger

Se pare că nu are legătură cu cadru. Eu folosesc java.util.logging.Logger care nu este serializable.
Sheldon Wei

Nu pentru configurare standard: ideone.com/F5lQZF "NotSerializableException: java.util.logare.Logger". Cu toate acestea, într-un mediu specific, un log manager poate returna o subclasă de Logger cu serialization (sau RMI) de sprijin, în continuare, cadrul ar putea folosi un extins serialization care se pot ocupa furnizori de bustean într-un mod special.
Holger
1

Interfața ForeachFunction se extinde Serializable. Dataset.foreach(f) poate fi serializarea argumentul f. În următorul test, testBlock1 reușește să-și testBlcok2 nu (NotSerializableException). Dar nu știu de ce.

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

Am testat cazuri și într-adevăr, eveniment functionBody = t -> System.out.println(t) ar fi de succes. Deci problema sursa cred că este metoda de referință. Mi-ai dat o mână uriașă.
Sheldon Wei

Dacă clasa de test AAA nu pune în aplicare Serializable în codul meu, testBlock1 de asemenea, va eșua. La functionBody în testBlock1 este o clasă internă anonimă din clasa de test AAA și ar trebui să fie serializat cu o instanță a clasei AAA care cuprinde totul. Cu toate acestea, functionBody în testBlock2 nu este o clasă internă de clasa AAA și nu pare să pună în aplicare Serializable în fond.
英語は苦手

În alte limbi

Această pagină este în alte limbi

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