Zpravy

Jak převést průtok na objem?

Datový tok je jednou z nejdůležitějších vlastností Java 8. Abyste poznali všechny její výhody, musíte pochopit její podstatu.

tok – Jedná se o posloupnost dat, která vám umožňuje zpracovávat je všechna nebo selektivně speciálním způsobem. Lze vytvářet proudy nebo na ně převádět stávající struktury. Mohou nahradit smyčky, protože podobným způsobem pomáhají zpracovávat sekvenci dat.

Nejprve si vytvoříme seznam náhodných čísel:

List list = new ArrayList();
Random random = new Random();
for (int i = 0; i < 10; i++) int rand = random.nextInt(10);
list.add(rand);
>

Poté vybereme všechna čísla větší než 5 do nového seznamu:

List filteredList = new ArrayList();
for (Integer e :
list) if (e > 5) filteredList.add(e);
>
>
[8, 6, 8, 6]

Tato syntaxe je poměrně podrobná. Zkusme si zjednodušit logiku tohoto kódu pomocí vláken.

Poznámka. Protože pracujeme s náhodnými čísly, seznam se změní.

Stream randStream = Stream.generate(()-> new Random().nextInt(10)).limit(10);

List filteredList = randStream.filter(e -> e > 5).collect(Collectors.toList());
[7, 8, 6]

Vezměte prosím na vědomí, že velikost seznamu se změnila kvůli náhodné povaze čísel.

Je zřejmé, že jsme byli schopni napsat mnohem méně kódu a získat jednodušší výsledek.

Nejprve výše uvedený kód vygeneruje seznam náhodných čísel pomocí Stream.generate . Pomocí limit(10) jsme omezili jejich počet na 10. Výsledkem byl proud celých čísel ( Stream ).

Poté pomocí filtru byly z tohoto proudu vybrány všechny prvky větší než 5.

Jak vidíte, je zde méně kódu a mnohem více logiky ve srovnání se smyčkami for.

Spojme tyto dvě operace:

List filteredList = Stream.generate(() -> new Random().nextInt(10)). 
limit(10).filter(e -> e > 5).map(e -> e * 2).collect(Collectors.toList());

Poznámka. () -> jsou většinou Java verze anonymních funkcí (výrazy lambda), které byly zavedeny v Javě 8 spolu se streamy. Pokud existuje pouze jeden parametr, závorky nejsou potřeba (jako e -> e > 5 ). Jejich implementace je podobná funkcím šipek JavaScriptu.

Vlákna jsou velmi efektivní při programování velkých aplikací.

Nyní přejděme ke studiu základních operací s nimi.

Základní streamovací operace

Jak již bylo zmíněno, průtok Jedná se o posloupnost dat, která vám umožňuje zpracovávat je všechna nebo selektivně speciálním způsobem. Lze vytvářet proudy nebo na ně převádět stávající struktury. Java nabízí několik různých způsobů, jak toho dosáhnout.

Metoda generování

Stream streamGenerated = 
Stream.generate(() -> "value");

Volání metody .generate třídy Stream umožňuje vytvořit proud skládající se z řetězce „value“ .

Streamy jsou líně načteny (můžete je nazvat líně načítaná kolekce), což znamená, že jsou vyhodnocovány podle potřeby. V tomto ohledu se objevila jedna zajímavá vlastnost: po prohlášení Streamu nenásledovala exekuce žádné operace.

To je nutné, protože Stream.generate vytváří nekonečný počet hodnot. V tomto případě byla „hodnota“ generována nekonečněkrát. S přihlédnutím k línému načítání se však nepočítá.

Nyní omezme tento stream na 20 čísel přidáním metody .limit:

Stream streamGenerated = 
Stream.generate(() -> "value").limit(10);

Streamy fungují pomocí vzoru Builder, který umožňuje operátorům vzájemné propojení. .limit vrací Stream . Příkazy, které vracejí proudy, se nazývají mezilehlé příkazy. V podstatě pokračují v řetězci.

Přečtěte si více
Kolik přibere štika za rok?

Chcete-li vypočítat proudy, musíte přidat operátora terminálu. Převádí je na konkrétní typ, jako je int , float , double , nebo kolekce (pole, hash mapy) pro pozdější použití programem.

Nejběžnějším způsobem převodu datového proudu je obvykle kolekce, například seznam.

To je to, co nyní provedeme pomocí metody .collect.

List streamToList = streamGenerated.collect(Collectors.toList());

Metoda .collect přijímá kolektor, v závislosti na jeho typu můžete řídit, jak a na co se proud převádí. V tomto případě to bude seznam.

Uveďme si stručně příklady dalších operací kolektoru:

  • .toSet() ;
  • .toMap() ;
  • .joining() .
[value, value, value, value, value, value, value, value, value, value, value, value, value, value, value, value, value, value, value, value]

A zde je požadovaný seznam.

Iterační metoda

Podobá se .generate , ale na rozdíl od něj umožňuje vytvářet nejen iterovatelný stream jako smyčku for, ale také nekonečný stream.

Stream streamIterated = Stream.iterate(0, i -> i + 2).limit(10);

První argument je počáteční číslo a druhý odráží „princip“ prováděné iterace.

[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

Struktura .iterate připomíná strukturu cyklu for:

for (int i = 0; i < 20; i = i + 2) // код 
>

Sbírky

Kolekce v Javě vám umožňují ukládat a spravovat data. Všechny lze přímo převést na streamy. Kolekce obsahují tři typy rozhraní:

Rozhraní Seznam je vám pravděpodobně známé. Jeho různé implementace se skládají z ArrayList, Vector a Stack.

Řekněme, že máme ArrayList celých čísel s názvem arrayToStream. Lze jej snadno převést na stream. Všechny uvedené kolekce podporují tuto konverzi pomocí metody .stream:

Streamový proud = arrayToStream.proud();

Je to tak jednoduché.

Jak již bylo zmíněno, vlákna umožňují provádět širokou škálu operací. Dříve se k jejich omezení používal již .limit související s středně pokročilí operátory, které vždy vrátí jiný stream. A hned na začátku článku se nám podařilo pracovat ještě s jedním z nich – .filtrem.

Hlavní výhodou streamů je, že poskytují mnoho takových operátorů. Poskytují pohodlnější přístup k práci se smyčkami.

Některé z nich svým principem fungování připomínají podobné operace v Pythonu a JavaScriptu. V podstatě jsou streamy velmi podobné generátorům v obou jazycích.

Podívejme se na některé operátory.

mapa

Používá se k opakovanému nastavení každého prvku seznamu. To znamená převedení na jiný typ nebo použití určité logiky (vzorce) k jeho změně.

Máme například seznam čísel od 1 do 10: [1,2,3,4,5,6,7,8,9,10] . Musíte odmocnit každou z nich: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]. Přesně k tomu je potřeba mapa.

Operace s mapou v Javě je implementována prostřednictvím proudu a jako prostředník jej vrací. Pokud jej však potřebujete převést na konkrétní typ, můžete použít terminálové operátory, jako je .collect.

Čísla streamu 1 až 10 Stream = čísla 1 až 10.stream ().mapa(num -> num * num);

Pro převod na seznam budete potřebovat .collect .

Přečtěte si více
Proč jsou v listech švestek díry?

Bez něj by výstup čísel1To10Stream vypadal asi jako java.util.stream.ReferencePipeline$3@3feba861, protože ještě nebyl převeden na typ, který potřebujeme.

Výstup z .collect:

[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

filtr

filtr funguje tak, jak jeho název napovídá: vybírá prvky seznamu na základě dané podmínky.

Například při práci se stejným seznamem čísel od 1 do 10 a výběrem všech sudých dostaneme [2, 4, 6, 8, 10] .

Stream numbers1To10Stream = numbers1To10.stream().filter(num -> num % 2 == 0);

Metoda filtru vyžaduje funkci, která přebírá hodnotu a určuje, zda je pravdivá nebo nepravdivá. Pokud je true , číslo se přenese do seznamu. V tomto případě je povinnou podmínkou zkontrolovat schopnost libovolného příchozího čísla být dělitelné 2: num -> num % 2 == 0.

[2, 4, 6, 8, 10]

odlišný

Tento přechodný příkaz eliminuje všechna opakování ze streamu.

Řekněme, že máme seznam čísel [3, 3, 3, 3, 8, 8, 8, 8] . Po odstranění všech opakujících se prvků má následující podobu [3, 8].

Stream distinct = duplicatedList.stream().distinct();

Nyní zaměřme svou pozornost na operátory terminálů, z nichž jeden jsme již viděli v akci – .collect . V některých případech je třeba provádět výpočty ve vláknech, ale místo seznamu je potřeba samostatná hodnota, například int nebo řetězec.

anyMatch

Jestliže jakýkoli prvku ve streamu splňuje zadanou podmínku, pak tento operátor vrátí true, jinak – false.

Na základě příkladu [3,4,7,9] zkontrolujme, zda jsou v tomto seznamu sudá čísla:

boolean anyMatchBool = anyMatchList.stream().anyMatch(num -> num % 2 == 0);

Připomínáme, že provozovatelé terminálů vracejí konkrétní typ. V tomto případě se vrací logický hodnota.

true

allMatch

Jestliže všechny prvky ve streamu splňují zadanou podmínku, pak tento operátor vrátí true, jinak – false.

Zvažte příklad [3,4,7,9]:

boolean anyMatchBool = allMatchList.stream().allMatch(num -> num % 2 == 0);

Výsledek tohoto příkladu je nepravdivý, protože v seznamu jsou lichá čísla.

Ale pokud by seznam byl [2,4,6,8], operátor by vrátil true, protože všechna čísla jsou sudá.

pro každého

Tento operátor vám umožňuje opakovat každý prvek vypisovat a provádět s nimi operace. V tomto případě není vrácena žádná hodnota, ale má to vedlejší efekt.

list.stream().forEach(num -> System.out.println(num));
3
4
7
9

Na rozdíl od mapy operátor forEach nemění aktuální seznam.

Nyní je čas cvičit.

Úkol

Musíte získat seznam knih se stavem „Platnost vypršela“ a zkontrolovat, zda některá z nich není uvedena jako Jordánsko:

boolean result = libraryRepo.stream().filter(b -> b.getStatus().equalsIgnoreCase("Expired")). 
anyMatchList(b -> b.getBorrower().equalsIgnoreCase("Jordan"));

Máme knihovnu, která poskytuje seznam knih. Z nich byly vybrány (filtrovány) všechny, kterým uplynula lhůta pro vrácení. Pak jsme zkontrolovali, jestli Jordan někoho z nich vzal. Pokud ano, pak je vráceno true, jinak false.

  • Když paralelismus trumfne souběžnost
  • Nezaslouženě zapomenutý ForkJoinPool
  • Prioritní fronty v Javě
Přečtěte si více
Proč semena neklíčí: 6 možných důvodů neúspěchu

Naučte se, jak převést stream na pole a naopak v Javě.

  • Přidal: baeldung
  • Datum natáčení 18.04.2021

1. Úvod

Obvykle je nutné převést různé dynamické datové struktury do polí.

V tomto tutoriálu si ukážeme, jak převést stream na pole a naopak v Javě.

2. Převeďte proud na pole

2.1. Nápověda k metodě

Nejlepší způsob, jak převést stream na pole, je použít metodu ToArray() streamu:

public String[] usingMethodReference(Stream stringStream)

Nyní můžeme snadno zkontrolovat, zda byl převod úspěšný:

Domů stringStream = Stream.of("baeldung", "převést", "na", "řetězec", "pole"); asseArrayEquals(new String[] < "baeldung", "převést", "na", "řetězec", "pole" >, usingMethodReference(stringStream));

2.2. Lambda výraz

Dalším ekvivalentem je projít lambda výrazem в ToARRAi () metoda:

public static String[] usingLambda(Stream stringStream) < return stringStream.toArray(size ->new String[velikost]); >

Získáme tak stejný výsledek jako při použití odkazu na metodu.

2.3. Vlastní třída

Nebo můžeme jít naplno a vytvořit plnohodnotnou třídu.

Jak vidíme z Tok dokumentaci, to trvá IntFunctional jako argument. Vezme velikost pole jako vstup a vrátí pole této velikosti.

Samozřejmě, IntFunctional rozhraní, abychom jej mohli implementovat:

třída MyArrayFunction implementuje IntFunction < @Override public String[] použít(int size) < return new String[size]; >>;

Poté můžeme sestavit a používat jako normálně:

public String[] usingCustomClass(Stream stringStream)

Proto můžeme učinit stejné prohlášení jako dříve.

2.4. Primitivní pole

V předchozích částech jsme prozkoumali, jak převést Tok struny к Struny pole. Ve skutečnosti můžeme převod tímto způsobem provést u libovolného Zařízení a bude to vypadat velmi podobně Struny příklady výše.

U primitivů je to však trochu jiné. Pokud máme Tok Celé číslo s, na které chceme převést inte , musíte například nejprve zavolat mapToInt() metoda:

public int[] intStreamToPrimitiveIntArray(Stream integerStream) < return integerStream.mapToInt(i ->i).toArray(); >

Tam také mapToLong() и mapToDouble() metody, které máme k dispozici. Všimněte si také, že jsme nepředali žádné argumenty toArray() Tentokrát.

Nakonec učiníme prohlášení o rovnosti a potvrdíme, že ano int pole je správné:

Domů integerStream = IntStream.rangeClosed(1, 7).boxed(); claimArrayEquals(new int[], intStreamToPrimitiveIntArray(integerStream));

Co kdybychom však museli udělat opak? Podívejme se.

3. Převeďte pole na proud

Samozřejmě můžeme jít i jinou cestou. A Java má na to nějaké specializované metody.

3.1. Pole objektů

Pole můžeme převést na Tok přes Arrays.stream() nebo Stream.of() metody :

veřejný Stream stringArrayToStreamUsingArraysStream(String[] stringArray) < return Arrays.stream(stringArray); >veřejný stream stringArrayToStreamUsingStreamOf(String[] stringArray) 

Je třeba poznamenat, že v obou případech je náš stream ve stejném čase jako naše pole.

3.2. Pole primitivů

Podobně můžeme transformovat řadu primitiv:

public IntStream primitiveIntArrayToStreamUsingArraysStream(int[] intArray) < return Arrays.stream(intArray); >veřejný stream primitiveIntArrayToStreamUsingStreamOf(int[] intArray)

Ale na rozdíl od transformace Zařízení s poli, je zde důležitý rozdíl. Při převodu pole primitiv Arrays.stream() se vrací IntStream , zatímco Stream.of() se vrací Tok .

3.3. Arrays.stream vs. Proud

Abychom pochopili rozdíly uvedené v předchozích částech, podíváme se na implementaci příslušných metod.

Přečtěte si více
Jak poznat staré větve rybízu?

Nejprve se podívejme na implementaci těchto dvou metod v Javě:

na veřejnosti Domů stream(T[] pole) < return stream(pole, 0, pole.délka); >veřejné Domů of(T. hodnoty) 

To vidíme Stream.of() ve skutečnosti Arrays.stream() interně, a to je samozřejmě důvod, proč dostáváme stejné výsledky.

Nyní zkontrolujeme metody v případě, že chceme transformovat pole primitiv:

public IntStream stream(int[] pole) < return stream(pole, 0, pole.délka); >veřejné Domů of(T t) < return StreamSupport.stream(new Streams.StreamBuilderImpl<>(t), false); >

Tentokrát, Stream.of() nevolá Arrays.stream() .

4. Závěr

V tomto článku jsme viděli, jak můžeme převádět Tok s na pole v Javě a naopak. Také jsme vysvětlili, proč při převodu pole dostáváme různé výsledky Zařízení s a když používáme mnoho primitiv.

Úplný zdrojový kód lze jako vždy nalézt na GitHubu.

Přečtěte si více k tématu:

  • Průvodce třídou java.util.Array
  • Průnik mezi dvěma celočíselnými poli

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *

Back to top button