WebHU - Programozási kérdések és válaszok

Be lehet zárni a közbenső áramlási műveleteket a csővezeték megszakítása nélkül?

A Java 8 Streams segítségével beágyazható és újrafelhasználható a közbenső adatfolyam-műveletek valamilyen módon, amely nem szakítja meg az adatfolyam-folyamatot?

Tekintse meg ezt a példát a Java oktatóanyagból a streamekről:

double average = roster
    .stream()
    .filter(p -> p.getGender() == Person.Sex.MALE)
    .mapToInt(Person::getAge)
    .average()
    .getAsDouble();

Tegyük fel, hogy a szűrőt és a mapToInt műveleteket a kódom különböző helyein kell használnom. Lehet, hogy megpróbálnám beágyazni ezt a logikát, hogy újra felhasználható legyen, például:

IntStream maleAges(Stream<Person> stream) {
    return stream
        .filter(p -> p.getGender() == Person.Sex.MALE)
        .mapToInt(Person::getAge)
}

Ez szép, de ahhoz, hogy használhassam, előfordulhat, hogy rendetlenséget kell okoznom a folyami csővezetékben. Például, ha szeretném a Bob nevű férfiak átlagéletkorát:

double averageBob =
    maleAges(roster
        .stream()
        .filter(p -> "Bob".equals(p.getName()))
    )
    .average()
    .getAsDouble();

Van valami jobb módja ennek? Valami ilyesmire gondolok:

double averageBob = roster
    .stream()
    .filter(p -> "Bob".equals(p.getName()))
    .apply(this::maleAges) // Doesn't compile
    .average()
    .getAsDouble();
11.02.2016

  • Mi a helyzet a int maleAges(Person p) { return p.getAge(); }-vel, majd a .map(this::maleAges) használatával? 11.02.2016
  • @LuiggiMendoza Ez számít a „koroknak”, de nem a „férfiaknak” :) 11.02.2016
  • Lényegében arra keresek módot, hogy több különböző típusú műveletet beágyazzam, és úgy helyezzem be a folyamatba, mintha egyetlen művelet lennének. 11.02.2016
  • Ja bocs, akkor valami ilyesmi: return p.getGender() == Person.Sex.MALE ? p.getAge() : 0;. Ebben az esetben a várt módon fog működni. 11.02.2016
  • Azt javaslom, hogy ahelyett, hogy egyetlen módszert alkalmazna, amely egy csomó üzleti logikát tartalmaz, ossza fel kisebb darabokra, amint az ebben a példában látható. 11.02.2016
  • @LuiggiMendoza Ez nem egészen ugyanaz, például a {Bob (42), Sally (23), Jack (18)} a {42 0 18}-re lenne leképezve a példáddal, de a cél az, hogy {42 18}-ra leképezd. A szűrő fontos. 11.02.2016
  • mi a baj a metódushívással? 11.02.2016
  • Ó igaz. Megértve. Akkor van egy kis kutatásom :) 11.02.2016
  • @AdamSkywalker jól működik, csak úgy néz ki, hogy rendetlen. És ha lenne egy összetettebb példám több tokozással, amit össze akarok láncolni, az nagyon csúnya lehet a sietségben. 11.02.2016

Válaszok:


1

Az én StreamEx könyvtáram, amely többek között a szabványos Stream API-t is továbbfejleszti, a chain metódussal rendelkezik, amely pontosan úgy működik, mint az Ön által javasolt apply:

double averageBob = StreamEx.of(roster)
        .filter(p -> "Bob".equals(p.getName()))
        .chain(this::maleAges) // Compiles!
        .average()
        .getAsDouble();

Szintén egy lehetséges alternatíva az, hogy a maleAges függvényt visszaadja:

Function<Stream<Person>, IntStream> maleAges() {
    return stream -> stream
        .filter(p -> p.getGender() == Person.Sex.MALE)
        .mapToInt(Person::getAge);
}

És így használd:

double averageBob = StreamEx.of(roster)
        .filter(p -> "Bob".equals(p.getName()))
        .chain(maleAges()) // Compiles!
        .average()
        .getAsDouble();

Így könnyen paraméterezheti a tokozott működését. Például:

Function<Stream<Person>, IntStream> agesForSex(Person.Sex sex) {
    return stream -> stream
        .filter(p -> p.getGender() == sex)
        .mapToInt(Person::getAge);
}

double averageBob = StreamEx.of(roster)
        .filter(p -> "Bob".equals(p.getName()))
        .chain(agesForSex(Person.Sex.MALE)) // Compiles!
        .average()
        .getAsDouble();
12.02.2016
  • Nagyon jó, pont erre számítottam :) 15.02.2016

  • 2

    Ennek egyik módja az lenne, ha folyam helyett veszünk egy személyt, és egy IntStream-et bocsátunk ki, például:

     final Predicate<Person> isMale = p -> p.getGender() == Person.Sex.MALE;
     final Function<Person, IntStream> maleAges = person -> isMale.test(person)
                ? IntStream.of(person.age)
                : IntStream.empty();
     final double averageT = roster
                    .stream()
                    .flatMapToInt(maleAges)
                    .average()
                    .getAsDouble();
    

    Így bárhol újra felhasználhatod a maleAges funkciót!

    11.02.2016
  • Ez egy nagyszerű megoldás, az egyetlen hátránya azonban az, hogy a stream műveletek nem használhatók a beágyazott funkcióban. Tehát bár jól működik a példában, lehet, hogy egy kicsit túl nehézkes az általános használatban. 15.02.2016
  • Egyetértek, amikor megírtam, úgy éreztem, hogy egy személy megszerzése és az IntStream visszaküldése egy kicsit hibás volt. Kicsit költőibb (mert úgy gondolom, hogy a kód lehet igazi költészet) egy olyan funkció, amely egy „Stream” személy” alapján „IntStream”-et ad vissza, természetesebbnek és natívabbnak tűnik. Ma megbeszéltem a kollégámmal, aki elmagyarázta nekem, hogy a Jool nevű könyvtár többé-kevésbé ugyanazokat a szolgáltatásokat nyújtja, mint a StreamEx. Azt hiszem, az én válaszom lenne a legjobb azok számára, akik nem akarnak külső függőségekre hagyatkozni, és sima Java 8 funkciókat szeretnének! 15.02.2016
  • Szerintem erre gondolsz? github.com/jOOQ/jOOL Úgy tűnik, a Tagir's StreamEx életképes alternatívája, köszönjük a megosztást! 18.02.2016
  • Új anyagok

    A rádiógomb ellenőrzött eseményének használata a jQueryben
    Ebben a cikkben látni fogjuk, hogyan kell dolgozni a jquery választógombbal ellenőrzött eseményeivel. A választógombok HTML gombok, amelyek segítenek kiválasztani egyetlen értéket egy csoportból...

    Körkörös függőségek megoldása terraformban adatforrásokkal – lépésről lépésre
    Mi az a körkörös függőségek Dolgozzunk egy egyszerű eseten, amikor az SQS-sor és az S3-vödör közötti körkörös függőség problémája van egy egymástól függő címkeérték miatt. provider..

    Miért érdemes elkezdeni a kódolást 2023-ban?
    01100011 01101111 01100100 01100101 — beep boop beep boop Világunk folyamatosan fejlődik a technológia körül, és naponta fejlesztenek új technológiákat a valós problémák megoldására. Amint..

    🎙 Random Noise #2  – Örökbefogadás és hit
    az analitika íratlan világának gondozása Szeretné, hogy ezek a frissítések a postaládájába kerüljenek? Iratkozzon fel itt . "Ha önvezető autókat gyártanak, akkor mi miért ne..

    A legrosszabb politika és prediktív modellek májátültetésre jelöltek számára az Egyesült Államokban
    A máj (vagy óangolul lifer) az emberi test legnehezebb belső szervére utal, amely csendesen működik a nap 24 órájában. Mit csinál a máj? 500 feladatot hajt végre a szervezet egészségének..

    5 webhely, amely 2022-ben fejleszti front-end fejlesztői készségeit
    Frontendmentor.io A tényleges projektek létrehozásával a Frontendmentor.io segítséget nyújt a front-end kódolási képességeinek fejlesztésében. A kódolást azután kezdheti meg, hogy..

    Mikor kell használni a Type-t az interfészhez képest a TypeScriptben?
    A TypeScript a JavaScript gépelt szuperkészlete, amely statikus gépelést ad a nyelvhez. Ez megkönnyíti a robusztus és karbantartható kód írását azáltal, hogy a hibákat a fordítási időben..