Hogyan lehet hozzáférni egy iterációs számlálóhoz az egyes hurokokban

1. Áttekintés

Miközben a Java adatai között ismétlünk, érdemes elérnünk az aktuális elemet és annak helyét az adatforrásban.

Ezt nagyon könnyű elérni egy klasszikusban mert hurok, ahol a pozíció általában a ciklus számításainak középpontjában áll, de egy kicsit több munkát igényel, ha olyan konstrukciókat használunk, mint az egyes ciklusokhoz vagy folyamokhoz.

Ebben a rövid bemutatóban néhány módot megvizsgálunk mert minden művelet tartalmazhat számlálót.

2. Számláló megvalósítása

Kezdjük egy egyszerű példával. Vessünk egy rendezett listát a filmekről, és kiadjuk őket rangsorukkal.

Lista IMDB_TOP_MOVIES = Arrays.asList ("A Shawshank-megváltás", "A keresztapa", "A keresztapa II", "A sötét lovag");

2.1. mert Hurok

A mert A ciklus számlálóval hivatkozik az aktuális elemre, így egyszerűen kezelheti az adatokat és a listában szereplő indexet is:

Lista rangsora = new ArrayList (); for (int i = 0; i <filmek.méret (); i ++) {Karaktersorozat = (i + 1) + ":" + filmek.get (i); rangsor.add (rangsor); }

Mint ez Lista valószínűleg egy Tömb lista, a kap a működés hatékony, és a fenti kód egyszerű megoldás a problémánkra.

assertThat (getRankingsWithForLoop (IMDB_TOP_MOVIES)) .conconExactly ("1: A Shawshank megváltása", "2: A keresztapa", "3: A keresztapa II", "4: A sötét lovag");

A Java összes adatforrását azonban nem lehet iterálni ezen a módon. Néha kap időigényes művelet, vagy csak egy adatforrás következő elemét használhatjuk fel Folyam vagy Iterálható.

2.2. mert Minden hurok

Folytatjuk a filmek listájának használatát, de tegyük úgy, mintha csak az egyes konstrukciók Java-jait használhatnánk rajta:

for (Vonós film: IMDB_TOP_MOVIES) {// használja a film értékét}

Itt külön változót kell használnunk az aktuális index nyomon követésére. Felépíthetjük azt a hurkon kívülre, és növelhetjük belül:

int i = 0; for (Vonós film: filmek) {String ranking = (i + 1) + ":" + film; rangsor.add (rangsor); i ++; }

Meg kell jegyeznünk használat után meg kell növelnünk a számlálót a hurkon belül.

3. A funkcionális mert Minden egyes

A számláló kiterjesztés minden egyes alkalommal történő megírása kód duplikációt eredményezhet, és véletlen hibákat okozhat a számláló változó frissítésének időpontjában. Ezért a fentieket általánosíthatjuk a Java funkcionális felületeivel.

Először is gondolkodnunk kell a cikluson belüli viselkedésről, mint mind a gyűjteményben lévő tétel, mind az index fogyasztójáról. Ezt a segítségével modellezhetjük BiConsumer, amely meghatározza a elfogad funkció, amely két paramétert vesz fel

@FunctionalInterface nyilvános felület BiConsumer {void accept (T t, U u); }

Mivel a hurok belseje két értéket használ, írhatunk egy általános hurokműveletet. Eltarthat a Iterálható a forrásadatok közül, amelyeken keresztül az egyes ciklusok futni fognak, és a BiConsumer hogy az egyes tételek és azok indexe elvégezhető legyen. Ezt a típusparaméterrel készíthetjük általánosnak T:

static void forEachWithCounter (Iterálható forrás, BiConsumer fogyasztó) {int i = 0; for (T elem: forrás) {fogyasztó.fogad (i, tétel); i ++; }}

Ezt felhasználhatjuk a filmranglistánkra, ha biztosítjuk a BiConsumer mint lambda:

Lista rangsora = new ArrayList (); forEachWithCounter (filmek, (i, film) -> {String rangsor = (i + 1) + ":" + filmek.get (i); rangsor.add (rangsor);});

4. Számláló hozzáadása ehhez az egyes val vel Folyam

A Java Folyam Az API lehetővé teszi számunkra, hogy kifejezzük, hogyan haladnak át adataink a szűrőkön és az átalakításokon. Azt is biztosítja, hogy a az egyes funkció. Próbáljuk meg ezt átalakítani olyan műveletté, amely magában foglalja a számlálót is.

A Patak mindegyikhez függvény a Fogyasztó a következő elem feldolgozásához. Hozhatnánk azonban létre Fogyasztó nyomon követni a számlálót, és átadni az elemet a BiConsumer:

public static Consumer withCounter (BiConsumer consumer) {AtomicInteger számláló = új AtomicInteger (0); visszaküldendő tétel -> consumer.accept (counter.getAndIncrement (), item); }

Ez a függvény új lambdát ad vissza. Az a lambda használja a AtomicInteger objektum, hogy az iteráció során nyomon kövesse a számlálót. A getAndIncrement A függvény minden alkalommal meghívásra kerül, amikor új elem van.

Az e funkció által létrehozott lambda delegálja a BiConsumer átadta, hogy az algoritmus mind az elemet, mind annak indexét feldolgozni tudja.

Lássuk ezt a film rangsorolási példánk használatában az a-val szemben Folyam hívott filmeket:

Lista rangsora = new ArrayList (); movies.forEach (withCounter ((i, film) -> {String rangsor = (i + 1) + ":" + film; rangsor.add (rangsor);}));

Benne az egyes felhívás a withCounter függvény létrehoz egy objektumot, amely nyomon követi a számlálást és egyben Fogyasztó hogy a az egyes a művelet is átadja az értékeit.

5. Következtetés

Ebben a rövid cikkben három módszert vizsgáltunk, hogyan lehet számlálót csatolni a Java-hoz mert minden művelet.

Láttuk, hogyan lehet nyomon követni az aktuális elem indexét az egyes megvalósításoknál mert egy hurok. Ezután megvizsgáltuk, hogyan lehet általánosítani ezt a mintát, és hogyan lehet hozzáadni a streaming műveletekhez.

Mint mindig, a cikk példakódja elérhető a GitHubon.