Kako pristupiti brojaču ponavljanja u svakoj petlji

1. Pregled

Tijekom iteracije podataka u Javi, možda bismo željeli pristupiti trenutnoj stavci i njezinu položaju u izvoru podataka.

To je vrlo lako postići u klasiku za petlja, gdje je položaj obično fokus izračuna petlje, ali zahtijeva malo više posla kada koristimo konstrukte kao za svaku petlju ili tok.

U ovom ćemo kratkom vodiču pogledati nekoliko načina za to za svaka operacija može sadržavati brojač.

2. Implementacija brojača

Počnimo s jednostavnim primjerom. Uzet ćemo poredani popis filmova i objaviti ih s njihovim rangiranjem.

Popis IMDB_TOP_MOVIES = Arrays.asList ("Iskupljenje Shawshanka", "Kum", "Kum II", "Mračni vitez");

2.1. za Petlja

A za petlja koristi brojač za referencu na trenutnu stavku, pa je to jednostavan način rada i nad podacima i nad njihovim indeksom na popisu:

Poredak popisa = novi ArrayList (); for (int i = 0; i <movies.size (); i ++) {Poredak niza = (i + 1) + ":" + movies.get (i); rankings.add (poredak); }

Kao ovo Popis vjerojatno je ArrayList, dobiti rad je učinkovit, a gornji kod jednostavno je rješenje našeg problema.

assertThat (getRankingsWithForLoop (IMDB_TOP_MOVIES)) .containsElectrely ("1: The Shawshank Redemption", "2: The Godfather", "3: The Godfather II", "4: The Dark Knight");

Međutim, svi izvori podataka u Javi ne mogu se ponoviti na ovaj način. Ponekad dobiti je vremenski intenzivna operacija ili možemo obraditi samo sljedeći element izvora podataka pomoću Stream ili Iterativ.

2.2. za Svaka petlja

Nastavit ćemo koristiti naš popis filmova, ali pretvarajmo se da ga možemo prevrtati samo koristeći Javu za svaku konstrukciju:

za (Niz film: IMDB_TOP_MOVIES) {// koristi vrijednost filma}

Ovdje trebamo koristiti zasebnu varijablu za praćenje trenutnog indeksa. Možemo to konstruirati izvan petlje i povećati unutar:

int i = 0; za (Filmski niz: filmovi) {Poredak niza = (i + 1) + ":" + film; rankings.add (poredak); i ++; }

To bismo trebali primijetiti moramo povećati brojač nakon što je upotrijebljen unutar petlje.

3. Funkcionalni za Svaki

Pisanje proširenja brojača svaki put kad nam zatreba moglo bi rezultirati dupliciranjem koda i riskirati slučajne pogreške u vezi s vremenom ažuriranja varijable brojača. Stoga gore navedeno možemo generalizirati koristeći Java funkcionalna sučelja.

Prvo, o ponašanju unutar petlje trebali bismo razmišljati kao o potrošaču i stavke u zbirci i indeksa. To se može modelirati pomoću BiConsumer, koji definira prihvatiti funkcija koja uzima dva parametra

@FunctionalInterface javno sučelje BiConsumer {void accept (T t, U u); }

Kako je unutar naše petlje nešto što koristi dvije vrijednosti, mogli bismo napisati opću operaciju petlje. Moglo bi potrajati Iterativ izvornih podataka, preko kojih će se izvoditi za svaku petlju, i BiConsumer za operaciju koja se izvodi za svaku stavku i njezin indeks. To možemo generički napraviti s parametrom tipa T:

statička praznina forEachWithCounter (Iterable izvor, potrošač BiConsumer-a) {int i = 0; for (T stavka: izvor) {consumer.accept (i, item); i ++; }}

To možemo koristiti na našem primjeru filmske ljestvice pružanjem implementacije za BiConsumer kao lambda:

Poredak popisa = novi ArrayList (); forEachWithCounter (filmovi, (i, film) -> {Poredak niza = (i + 1) + ":" + movies.get (i); rankings.add (poredak);});

4. Dodavanje brojača u za svakoga s Stream

Java Stream API nam omogućuje da izrazimo kako naši podaci prolaze kroz filtre i transformacije. Također pruža a za svakoga funkcija. Pokušajmo to pretvoriti u operaciju koja uključuje brojač.

The Stream forEach funkcija traje a Potrošač za obradu sljedeće stavke. Mogli bismo to, međutim, stvoriti Potrošač za praćenje brojača i predavanje predmeta na a BiConsumer:

javni statički Potrošač withCounter (BiConsumer potrošač) {AtomicInteger counter = new AtomicInteger (0); vrati stavku -> potrošač.prihvati (counter.getAndIncrement (), stavka); }

Ova funkcija vraća novu lambda. Ta lambda koristi AtomicInteger objekt za praćenje brojača tijekom iteracije. The getAndIncrement funkcija se poziva svaki put kad postoji nova stavka.

Lambda koju je stvorila ova funkcija delegira na BiConsumer proslijeđena tako da algoritam može obraditi i stavku i njezin indeks.

Pogledajmo kako to koristi naš primjer rangiranja filmova protiv a Stream pozvao filmovi:

Poredak popisa = novi ArrayList (); movies.forEach (withCounter ((i, film) -> {Poredak niza = (i + 1) + ":" + film; rankings.add (poredak);}));

Unutar za svakoga je poziv na withCounter funkcija za stvaranje objekta koji istovremeno prati brojanje i djeluje kao Potrošač da je za svakoga operacija prolazi i svoje vrijednosti.

5. Zaključak

U ovom smo kratkom članku pogledali tri načina za pridruživanje brojača Javi za svaka operacija.

Vidjeli smo kako pratiti indeks trenutne stavke na svakoj njihovoj implementaciji za petlja. Zatim smo pogledali kako generalizirati ovaj obrazac i kako ga dodati operacijama strujanja.

Kao i uvijek primjer koda za ovaj članak dostupan je na GitHubu.


$config[zx-auto] not found$config[zx-overlay] not found