Izazovi u Javi 8

1. Pregled

Java 8 predstavila je neke nove značajke koje su se uglavnom vrtjele oko upotrebe lambda izraza. U ovom ćemo kratkom članku pogledati nedostatke nekih od njih.

Iako ovo nije cjelovit popis, riječ je o subjektivnoj zbirci najčešćih i najpopularnijih prigovora u vezi s novim značajkama Java 8.

2. Java 8 Stream and Thread Pool

Prije svega, paralelni tokovi trebaju omogućiti laku paralelnu obradu sekvenci, a to sasvim u redu za jednostavne scenarije.

Stream koristi zadanu, uobičajenu ForkJoinPool - dijeli sekvence na manje dijelove i izvodi operacije koristeći više niti.

Međutim, postoji kvaka. Ne postoji dobar način za to navesti koji ForkJoinPool koristiti i stoga, ako jedna od niti zaglavi sve ostale, koristeći zajednički bazen, morat će pričekati da se dugotrajni zadaci dovrše.

Srećom, postoji zaobilazno rješenje za to:

ForkJoinPool forkJoinPool = novi ForkJoinPool (2); forkJoinPool.submit (() -> / * neki cjevovod paralelnog toka * /) .get ();

To će stvoriti novi, odvojeni ForkJoinPool i svi zadaci generirani paralelnim tokom koristit će navedeno spremište, a ne u zajedničkom, zadanom.

Vrijedno je napomenuti da postoji još jedan potencijalni ulov: "Ova tehnika predavanja zadatka u fork-join pool, za pokretanje paralelnog toka u tom spremištu je izvedbeni" trik "i nije zajamčeno da će raditi", prema Stuartu Marksu - Java i OpenJDK programer iz Oraclea. Važnu nijansu koju morate imati na umu prilikom korištenja ove tehnike.

3. Smanjena otklanjanje pogrešaka

Novi stil kodiranja ipak pojednostavljuje naš izvorni kodmože uzrokovati glavobolju tijekom uklanjanja pogrešaka.

Prije svega, pogledajmo ovaj jednostavan primjer:

public static int getLength (String input) {if (StringUtils.isEmpty (input) {throw new IllegalArgumentException ();} return input.length ();} List lengths = new ArrayList (); for (Naziv niza: Arrays.asList ( args)) {lengths.add (getLength (name));}

Ovo je standardni imperativni Java kôd koji sam sebe objašnjava.

Ako prođemo prazni Niz kao ulaz - kao rezultat - kôd će izbaciti iznimku, a u konzoli za otklanjanje pogrešaka možemo vidjeti:

na LmbdaMain.getLength (LmbdaMain.java:19) na LmbdaMain.main (LmbdaMain.java:34)

Hajde sada da ponovo napišemo isti kod pomoću Stream API-ja i vidimo što će se dogoditi kada se isprazni Niz dobiva:

Duljine toka = names.stream () .map (name -> getLength (name));

Skup poziva će izgledati ovako:

na LmbdaMain.getLength (LmbdaMain.java:19) na LmbdaMain.lambda $ 0 (LmbdaMain.java:37) na LmbdaMain $$ Lambda $ 1 / 821270929.apply (Nepoznati izvor) na java.util.stream.ReferencePipeline $ 3 $ 1.accept ( ReferencePipeline.java:193) na java.util.Spliterators $ ArraySpliterator.forEachRemaining (Spliterators.java:948) na java.util.stream.AbstractPipeline.copyInto (AbstractPipeline.java:512) na java.util.stream.AbstractPipeline.wrapAndrappyWindAndControl. (AbstractPipeline.java:502) na java.util.stream.ReduceOps $ ReduceOp.evaluateSequential (ReduceOps.java:708) na java.util.stream.AbstractPipeline.evaluate (AbstractPipeline.java:234) na java.util.stream. LongPipeline.reduce (LongPipeline.java:438) na java.util.stream.LongPipeline.sum (LongPipeline.java:396) na java.util.stream.ReferencePipeline.count (ReferencePipeline.java:526) na LmbdaMain.main (LmbdaMain .java: 39)

To je cijena koju plaćamo za korištenje više slojeva apstrakcije u našem kodu. Međutim, IDE-ovi su već razvili solidne alate za ispravljanje pogrešaka Java Streamova.

4. Metode povratka Nula ili Neobvezno

Neobvezno uveden je u Javi 8 kako bi pružio siguran način izražavanja neobaveznosti.

Neobvezno, izričito ukazuje da povratna vrijednost možda nije prisutna. Stoga pozivanje metode može vratiti vrijednost i Neobvezno koristi se za umotavanje te vrijednosti unutra - što se pokazalo zgodnim.

Nažalost, zbog Java kompatibilnosti unatrag, ponekad smo završili s Java API-jevima koji miješaju dvije različite konvencije. U istoj klasi možemo pronaći metode koje vraćaju nule, kao i metode koje vraćaju Opcionalni.

5. Previše funkcionalnih sučelja

U java.util.funkcija paket, imamo kolekciju ciljnih vrsta za lambda izraze. Možemo ih razlikovati i grupirati kao:

  • Potrošač - predstavlja operaciju koja uzima neke argumente i ne vraća rezultat
  • Funkcija - predstavlja funkciju koja uzima neke argumente i daje rezultat
  • Operater - predstavlja operaciju nad nekim argumentima tipa i vraća rezultat iste vrste kao i operandi
  • Predikat - predstavlja predikat (boolean-valjana funkcija) nekih argumenata
  • Dobavljač - predstavlja dobavljača koji ne uzima argumente i vraća rezultate

Uz to, imamo i dodatne vrste za rad s primitivima:

  • IntConsumer
  • IntFunction
  • Nepredvidljivo
  • IntSupplier
  • IntToDoubleFunction
  • IntToLongFunction
  • ... i iste alternative za Čezne i Parovi

Nadalje, posebne vrste za funkcije s arititetom 2:

  • BiConsumer
  • BiPredicate
  • BinaryOperator
  • BiFunction

Kao rezultat toga, cijeli paket sadrži 44 funkcionalna tipa, što sigurno može početi zbunjivati.

6. Označene iznimke i Lambda izrazi

Provjerene iznimke već su prije Java 8 bile problematično i kontroverzno pitanje. Od dolaska Jave 8 nastalo je novo izdanje.

Provjerene iznimke moraju se odmah uhvatiti ili prijaviti. Od java.util.funkcija funkcionalna sučelja ne deklariraju izbacivanje izuzetaka, kod koji baca provjereni izuzetak neće uspjeti tijekom kompilacije:

static void writeToFile (Integer integer) baca IOException {// logika za pisanje u datoteku koja baca IOException}
Popis cijelih brojeva = Arrays.asList (3, 9, 7, 0, 10, 20); cijeli brojevi.forEach (i -> writeToFile (i));

Jedan od načina za prevladavanje ovog problema je zamotavanje provjerene iznimke u pokušaj uhvatiti blokirati i ponovno baciti RuntimeException:

Popis cijelih brojeva = Arrays.asList (3, 9, 7, 0, 10, 20); integers.forEach (i -> {try {writeToFile (i);} catch (IOException e) {throw new RuntimeException (e);}});

Ovo će uspjeti. Međutim, bacanje RuntimeException proturječi svrsi provjerene iznimke i čini čitav kôd umotan s šifrom uzorka, što pokušavamo smanjiti koristeći se lambda izrazima. Jedno od nesretnih rješenja je oslanjanje na tajni hack.

Drugo rješenje je pisanje potrošačkog funkcionalnog sučelja - što može stvoriti iznimku:

@FunctionalInterface javno sučelje ThrowingConsumer {void accept (T t) baca E; }
static Consumer throwingConsumerWrapper (ThrowingConsumer throwingConsumer) {return i -> {try {throwingConsumer.accept (i); } catch (Exception ex) {throw new RuntimeException (ex); }}; }

Nažalost, provjerenu iznimku još uvijek omotavamo u iznimku tijekom izvođenja.

Na kraju, za detaljno rješenje i objašnjenje problema možemo istražiti sljedeće dubinsko ronjenje: Iznimke u Java 8 Lambda Expressions.

8. Zaključak

U ovom brzom opisu raspravljali smo o nekim nedostacima Java 8.

Iako su neki od njih bili namjerni odabir dizajna koji su napravili arhitekti Java jezika, a u mnogim slučajevima postoji zaobilazno rješenje ili alternativno rješenje; moramo biti svjesni njihovih mogućih problema i ograničenja.


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