Proč můj java lambda výraz nemůže pracovat, zatímco jeho imperativ styl funguje správně?

0

Otázka

Mám dlouholeté zkušenosti z Java 8 a jeho lambda. Ale potkal jsem šílený problém, když jsem vyvinul hello-world-size Spark program.

Tady mám Java třídy, ve kterém Dat anotace je z Lombok:

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

A pak jsem se postavil java seznam obsahující objekty Persion třída:

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

zatím je to dobré. A pak jsem se snažil generovat Jiskru Dataset pomocí seznamu:

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

Všimněte si, že blok 1 je ekvivalentní bloku 2 v jazyce java a blok 2 je zjednodušený z bloku 1 do IntelliJ IDEA. Jediný rozdíl je, že blok 2 je pomocí lambda výrazu.

Nicméně, když jsem se spustit program, blok 1 končí dobře, zatímco blok 2 spustit v výjimkou: enter image description here

Co... na velkou zemi a velký vesmír? Proč JVM nebo Zapalovací motor dělá věci, jako je tento?!

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

Nejlepší odpověď

7

Jak vysvětlil, v Čem je ekvivalent lambda výraz pro Systém.::println, referenční metoda System.out::println není totožný s lambda výraz x -> System.out.println(x).

Metoda referenční zachycuje aktuální hodnota System.out, chcete-li vyvolat println na to pokaždé, když je vyvolána funkce, spíše než hodnocení System.out znovu pokaždé jako lambda výraz je tělo dělá.

Jak také řekl, to málokdy dělá rozdíl, ale tady, to dělá. Při pokusu o serializaci funkce, bude se snažit serializovat všechny zachycené hodnoty, včetně PrintStream například čtení z System.out během vytváření instance. Na PrintStream není serializovatelný a to by bylo docela náročné na implementaci serializable PrintStream splnění očekávání.

Ale je důležité mít na paměti, že při serializaci lambda výraz x -> System.out.println(x) nebo ekvivalentní třídy objektu a rekonstruovat je v jiném prostředí, System.out to bude číst bude hodnotit na různých PrintStream než ve svém původním prostředí. Nezáleží na tom, když distribuované výpočetní rámce, stará se, aby potrubí vše tisknout na standardní výstup zpět na původce.

Ale je důležité mít na paměti, že static pole, která nejsou součástí serializovaná data mohou mít různý obsah v různých prostředích obecně.

2021-11-24 08:36:53

Zní to jako to se vyskytuje pouze s System.out?A já jej nahradit Protokol rámce, a bang! To se mu podařilo. ForeachFunction<String> functionBody = log::info;
Sheldon Wei

Závisí na protokolování rámec. To bude fungovat, pokud log je serializable.
Holger

Zdá se, že nesouvisí s rámcem. Používám java.util.logging.Logger který není serializovatelný.
Sheldon Wei

Ne pro standardní nastavení: ideone.com/F5lQZF "NotSerializableException: java.util.protokolování.Logger". Nicméně, v konkrétním prostředí, log manager může vrátit podtřídy Logger s serializace (nebo RMI) podpory, další, rámec by mohl použít rozšířené serializace, která zvládne dřevorubci ve zvláštním způsobem.
Holger
1

Rozhraní ForeachFunction rozšiřuje Serializable. Dataset.foreach(f) může být serializace argument f. V následujícím testu, testBlock1 uspěje a testBlcok2 selže (NotSerializableException). Ale nevím, proč.

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

Testoval jsem své případy a skutečně, události functionBody = t -> System.out.println(t) by být úspěšný. Takže problém zdroj předpokládám, že je metoda referenční. Dali jste mi obrovské ruce.
Sheldon Wei

Pokud testovací třídy AAA neimplementuje Serializable v mém kódu, testBlock1 bude také nezdaří. Na functionBody v testBlock1 je anonymní vnitřní třídy zkoušky třídy AAA a by měla být serializován s instanci třídy AAA to uzavírá. Nicméně, functionBody v testBlock2 není vnitřní třídu třídy AAA a nezdá se, že realizaci Serializable v látce.
英語は苦手

V jiných jazycích

Tato stránka je v jiných jazycích

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