JavaRush /Java blogi /Random-UZ /Kofe tanaffusi №177. Java 8 da Java Stream bo'yicha bataf...

Kofe tanaffusi №177. Java 8 da Java Stream bo'yicha batafsil qo'llanma

Guruhda nashr etilgan
Manba: Hackernoon Ushbu postda kod misollari va tushuntirishlar bilan birga Java Stream bilan ishlash bo'yicha batafsil qo'llanma taqdim etiladi. Kofe tanaffusi №177.  Java 8 - 1 da Java Stream bo'yicha batafsil qo'llanma

Java 8 da Java Threads bilan tanishish

Java 8 ning bir qismi sifatida taqdim etilgan Java Streams ma'lumotlar to'plami bilan ishlash uchun ishlatiladi. Ularning o'zlari ma'lumotlar tuzilmasi emas, lekin yakuniy natijaga erishish uchun buyurtma berish va tartibga solish orqali boshqa ma'lumotlar tuzilmalaridan ma'lumotlarni kiritish uchun ishlatilishi mumkin. Eslatma: Oqim va mavzuni chalkashtirmaslik kerak, chunki rus tilida ikkala atama ko'pincha bir xil tarjimada "oqim" deb ataladi. Stream operatsiyalarni bajarish uchun ob'ektni (ko'pincha ma'lumotlarni uzatish yoki saqlashni) bildiradi, Thread (so'zma-so'z tarjima - ip) esa ma'lum dastur kodini boshqa kod tarmoqlari bilan parallel ravishda bajarishga imkon beruvchi ob'ektni bildiradi. Stream alohida maʼlumotlar tuzilmasi boʻlmagani uchun u hech qachon maʼlumotlar manbasini oʻzgartirmaydi. Java oqimlari quyidagi xususiyatlarga ega:
  1. Java Stream-dan “java.util.stream” paketi yordamida foydalanish mumkin. Uni kod yordamida skriptga import qilish mumkin:

    import java.util.stream.* ;

    Ushbu koddan foydalanib, biz Java Stream-da bir nechta o'rnatilgan funktsiyalarni osongina amalga oshirishimiz mumkin.

  2. Java Stream Java-dagi to'plamlar va massivlar kabi ma'lumotlar to'plamidan kiritilgan ma'lumotlarni qabul qilishi mumkin.

  3. Java Stream kirish ma'lumotlar strukturasini o'zgartirishni talab qilmaydi.

  4. Java Stream manbani o'zgartirmaydi. Buning o'rniga, tegishli quvur liniyasi usullaridan foydalangan holda mahsulot ishlab chiqaradi.

  5. Java Streams oraliq va terminal operatsiyalariga bo'ysunadi, biz ularni keyingi bo'limlarda muhokama qilamiz.

  6. Java Stream-da oraliq operatsiyalar o'tkaziladi va dangasa baholash formatida amalga oshiriladi. Ular terminal funktsiyalari bilan tugaydi. Bu Java Stream-dan foydalanishning asosiy formatini tashkil qiladi.

Keyingi bo'limda biz Java 8 da kerak bo'lganda Java Stream yaratish uchun ishlatiladigan turli usullarni ko'rib chiqamiz.

Java 8 da Java Stream yaratish

Java mavzulari bir necha usulda yaratilishi mumkin:

1. Stream.empty() usuli yordamida bo'sh oqim yaratish

Keyinchalik kodingizda foydalanish uchun bo'sh oqim yaratishingiz mumkin. Agar siz Stream.empty() usulidan foydalansangiz , qiymatsiz bo'sh oqim hosil bo'ladi. Agar biz ish vaqtida null ko'rsatgich istisnosini o'tkazib yubormoqchi bo'lsak, bu bo'sh oqim foydali bo'lishi mumkin. Buning uchun quyidagi buyruqdan foydalanishingiz mumkin:
Stream<String> str = Stream.empty();
Yuqoridagi bayonot ichida hech qanday elementsiz str nomli bo'sh oqim hosil qiladi . Buni tekshirish uchun str.count() atamasi yordamida oqim sonini yoki hajmini tekshiring . Masalan,
System.out.println(str.count());
Natijada biz chiqishda 0 ni olamiz .

2. Stream.Builder misoli bilan Stream.builder() usuli yordamida oqim yarating.

Stream Builder-dan, shuningdek , quruvchi dizayn naqshidan foydalangan holda oqim yaratish uchun foydalanishimiz mumkin . Ob'ektlarni bosqichma-bosqich qurish uchun mo'ljallangan. Keling, Stream Builder yordamida qanday qilib oqim yaratishimiz mumkinligini ko'rib chiqaylik .
Stream.Builder<Integer> numBuilder = Stream.builder();

numBuilder.add(1).add(2).add( 3);

Stream<Integer> numStream = numBuilder.build();
Ushbu koddan foydalanib, siz int elementlarini o'z ichiga olgan numStream nomli oqim yaratishingiz mumkin . Avval yaratilgan numBuilder deb nomlangan Stream.Builder misoli tufayli hamma narsa juda tez amalga oshiriladi .

3. Stream.of() usuli yordamida belgilangan qiymatlar bilan oqim yarating

Oqim yaratishning yana bir usuli Stream.of() usulidan foydalanishni o'z ichiga oladi . Bu berilgan qiymatlar bilan oqim yaratishning oddiy usuli. U mavzuni e'lon qiladi va ishga tushiradi. Oqim yaratish uchun Stream.of() usulidan foydalanishga misol:
Stream<Integer> numStream = Stream.of(1, 2, 3);
Bu kod, xuddi Stream.Builder yordamida oldingi usulda qilganimiz kabi, int elementlarini o'z ichiga olgan oqim hosil qiladi . Bu erda biz oldindan belgilangan [1, 2 va 3] qiymatlari bilan Stream.of() yordamida to'g'ridan-to'g'ri oqim yaratdik .

4. Arrays.stream() usuli yordamida mavjud massivdan oqim yarating

Tarmoq yaratishning yana bir keng tarqalgan usuli Java-da massivlardan foydalanishni o'z ichiga oladi. Bu yerdagi oqim Arrays.stream() usuli yordamida mavjud massivdan yaratilgan . Barcha massiv elementlari oqim elementlariga aylantiriladi. Mana yaxshi misol:
Integer[] arr = {1, 2, 3, 4, 5};

Stream<Integer> numStream = Arrays.stream(arr);
Ushbu kod butun sonli massiv bo'lgan arr deb nomlangan massivning mazmunini o'z ichiga olgan numStream hosil qiladi .

5. Stream.concat() usuli yordamida ikkita mavjud oqimni birlashtirish

Oqim yaratish uchun ishlatilishi mumkin bo'lgan yana bir usul bu Stream.concat() usulidir . U bitta ipni yaratish uchun ikkita ipni birlashtirish uchun ishlatiladi. Ikkala oqim ham tartibda birlashtirilgan. Bu shuni anglatadiki, birinchi ip birinchi bo'lib, keyin ikkinchi ip va hokazo. Bunday birikmaning misoli quyidagicha ko'rinadi:
Stream<Integer> numStream1 = Stream.of(1, 2, 3, 4, 5);

Stream<Integer> numStream2 = Stream.of(1, 2, 3);

Stream<Integer> combinedStream = Stream.concat( numStream1, numStream2);
Yuqoridagi bayonot birma-bir birinchi numStream1 va ikkinchi numStream2 oqimining elementlarini o'z ichiga olgan combinedStream nomli yakuniy oqim yaratadi .

Java Stream bilan operatsiyalar turlari

Yuqorida aytib o'tilganidek, Java 8 da Java Stream bilan ikki turdagi operatsiyalarni bajarishingiz mumkin: oraliq va terminal. Keling, ularning har birini batafsil ko'rib chiqaylik.

Oraliq operatsiyalar

Oraliq operatsiyalar chiqish oqimini hosil qiladi va faqat terminal operatsiyasiga duch kelganda bajariladi. Bu shuni anglatadiki, oraliq operatsiyalar dangasalik bilan bajariladi, quvur liniyasi qilinadi va faqat terminal operatsiyasi bilan yakunlanishi mumkin. Siz dangasa baholash va quvur liniyasi haqida birozdan keyin bilib olasiz. Oraliq operatsiyalarga quyidagi usullar misol bo'la oladi: filter() , map() , different() , peek() , sorted() va boshqalar.

Terminal operatsiyalari

Terminal operatsiyalari oraliq operatsiyalarning bajarilishini yakunlaydi va shuningdek, chiqish oqimining yakuniy natijalarini qaytaradi. Terminal operatsiyalari dangasa bajarilish va quvur liniyasining tugashini bildirganligi sababli, bu ipni terminal operatsiyasidan keyin qayta ishlatib bo'lmaydi. Terminal operatsiyalariga quyidagi usullar misol bo'la oladi: forEach() , collect() , count() , reduce() va boshqalar.

Java Stream bilan operatsiyalarga misollar

Oraliq operatsiyalar

Java oqimiga qo'llanilishi mumkin bo'lgan ba'zi oraliq operatsiyalarga misollar:

filtr()

Ushbu usul Java-da ma'lum bir predikatga mos keladigan oqimdan elementlarni filtrlash uchun ishlatiladi. Bu filtrlangan elementlar keyin yangi oqim hosil qiladi. Yaxshiroq tushunish uchun bir misolni ko'rib chiqaylik.
Stream<Integer> numStream = Stream.of(43, 65, 1, 98, 63); List<Integer> even = numStream.filter(n -> n % 2 == 0) .collect(Collectors.toList()); System.out.println(even);
Xulosa:
[98]
Izoh: Ushbu misolda siz hatto elementlar (2 ga bo'linadigan) filter() usuli yordamida filtrlanganligini va numStream butun sonlar ro'yxatida saqlanganligini ko'rishingiz mumkin , ularning mazmuni keyinroq chop etiladi. 98 oqimdagi yagona juft butun son bo'lgani uchun u chiqishda chop etiladi.

map()

Ushbu usul dastlabki kirish oqimining elementlarida xaritalangan funktsiyalarni bajarish orqali yangi oqim yaratish uchun ishlatiladi. Ehtimol, yangi oqim boshqa ma'lumotlar turiga ega. Misol quyidagicha ko'rinadi:
Stream<Integer> numStream = Stream.of(43, 65, 1, 98, 63); List<Integer> d = numStream.map(n -> n*2) .collect(Collectors.toList()); System.out.println(d);
Xulosa:
[86, 130, 2, 196, 126]
Tushuntirish: Bu erda map() usuli numStream oqimining har bir elementini ikki barobarga oshirish uchun foydalanilganini ko'ramiz . Chiqishdan ko'rinib turibdiki, oqimdagi elementlarning har biri muvaffaqiyatli ikki barobarga oshirildi.

alohida()

Bu usul dublikatlarni filtrlash orqali oqimdagi faqat alohida elementlarni olish uchun ishlatiladi. Shunga o'xshash misol quyidagicha ko'rinadi:
Stream<Integer> numStream = Stream.of(43,65,1,98,63,63,1); List<Integer> numList = numStream.distinct() .collect(Collectors.toList()); System.out.println(numList);
Xulosa:
[43, 65, 1, 98, 63]
Izoh: Bu holda, numStream uchun different() usuli qo'llaniladi . U oqimdan dublikatlarni olib tashlash orqali numList-dagi barcha alohida elementlarni oladi . Chiqishdan ko'rinib turibdiki, dastlab ikkita dublikat (63 va 1) bo'lgan kirish oqimidan farqli o'laroq, dublikatlar yo'q.

peek()

Ushbu usul terminal operatsiyasini bajarishdan oldin oraliq o'zgarishlarni kuzatish uchun ishlatiladi. Bu peek() dan keyingi oraliq operatsiyalar bajarilishi mumkin bo'lgan oqim yaratish uchun oqimning har bir elementida operatsiyani bajarish uchun ishlatilishi mumkinligini anglatadi.
Stream<Integer> numStream = Stream.of(43, 65, 1, 98, 63); List<Integer> nList = numStream.map(n -> n*10) .peek(n->System.out.println("Mapped: "+ n)) .collect(Collectors.toList()); System.out.println(nList);
Xulosa:
Xaritada: 430 Xaritada: 650 Xaritada: 10 Xaritada: 980 Xaritada: 630 [430, 650, 10, 980, 630]
Izoh: Bu erda peek() usuli oraliq natijalarni yaratish uchun ishlatiladi, chunki map() usuli oqim elementlariga qo'llaniladi. Bu erda biz chop etish bayonotida ro'yxatning yakuniy mazmunini chop etish uchun collect() terminal operatsiyasidan foydalanishdan oldin ham , har bir oqim elementi xaritasi uchun natija oldindan ketma-ket chop etilishini ko'rishimiz mumkin .

tartiblangan()

Sorted() usuli oqim elementlarini saralash uchun ishlatiladi. Odatiy bo'lib, u elementlarni o'sish tartibida tartiblaydi. Parametr sifatida ma'lum bir tartiblash tartibini ham belgilashingiz mumkin. Ushbu usulni amalga oshirishning namunasi quyidagicha ko'rinadi:
Stream<Integer> numStream = Stream.of(43, 65, 1, 98, 63); numStream.sorted().forEach(n -> System.out.println(n));
Xulosa:
1 43 ​​63 65 98
Izoh: Bu yerda sorted() usuli sukut boʻyicha oqim elementlarini oʻsish tartibida saralash uchun ishlatiladi (chunki aniq tartib belgilanmagan). Chiqishda chop etilgan elementlar o'sish tartibida joylashtirilganligini ko'rishingiz mumkin.

Terminal operatsiyalari

Java oqimlariga qo'llanilishi mumkin bo'lgan ba'zi terminal operatsiyalariga misollar:

har biriga()

ForEach() usuli oqimning barcha elementlarini takrorlash va funksiyani har bir elementda birma-bir bajarish uchun ishlatiladi. Bu for , while va boshqalar kabi sikl iboralariga muqobil vazifasini bajaradi . Misol:
Stream<Integer> numStream = Stream.of(43, 65, 1, 98, 63); numStream.forEach(n -> System.out.println(n));
Xulosa:
43 65 1 98 63
Izoh: Bu yerda forEach() usuli oqimning har bir elementini birma-bir chop etish uchun ishlatiladi.

count()

count() usuli oqimdagi mavjud elementlarning umumiy sonini olish uchun ishlatiladi. Bu ko'pincha to'plamdagi elementlarning umumiy sonini aniqlash uchun ishlatiladigan size() usuliga o'xshaydi . Java Stream bilan count() usulidan foydalanish misoli quyidagicha:
Stream<Integer> numStream = Stream.of(43, 65, 1, 98, 63); System.out.println(numStream.count());
Xulosa:
5
Tushuntirish: numStream 5 ta butun elementni o'z ichiga olganligi sababli, undagi count() usuli yordamida 5 chiqadi.

yig'ish()

Collection() usuli oqim elementlarini o'zgaruvchan qisqartirishni amalga oshirish uchun ishlatiladi. U ishlov berish tugagandan so'ng oqimdan tarkibni olib tashlash uchun ishlatilishi mumkin. Bu qisqartirishlarni amalga oshirish uchun Kollektor sinfidan foydalanadi .
Stream<Integer> numStream = Stream.of(43, 65, 1, 98, 63); List<Integer> odd = numStream.filter(n -> n % 2 == 1) .collect(Collectors.toList()); System.out.println(odd);
Xulosa:
[43, 65, 1, 63]
Izoh: Ushbu misolda oqimdagi barcha g'alati elementlar filtrlanadi va odd nomli ro'yxatga yig'iladi/kamaytiriladi . Oxirida g'alati bo'lganlar ro'yxati chop etiladi.

min() va max()

Min() usuli , nomidan ko'rinib turibdiki, oqimdagi minimal elementni topish uchun ishlatilishi mumkin. Xuddi shunday, oqimdagi maksimal elementni topish uchun max() usulidan foydalanish mumkin. Keling, ularni misol bilan qanday ishlatish mumkinligini tushunishga harakat qilaylik:
Stream<Integer> numStream = Stream.of(43, 65, 1, 98, 63); int smallest = numStream.min((m, n) -> Integer.compare(m, n)).get(); System.out.println("Smallest element: " + smallest);
numStream = Stream.of(43, 65, 1, 98, 63); int largest = numStream.max((m, n) -> Integer.compare(m, n)).get(); System.out.println("Largest element: " + largest);
Xulosa:
Eng kichik element: 1 ta eng katta element: 98
Izoh: Ushbu misolda biz numStreamdagi eng kichik elementni min () usuli yordamida va eng katta elementni max() usuli yordamida chop etdik . E'tibor bering, bu erda max() usulini ishlatishdan oldin numStream ga yana elementlar qo'shdik . Buning sababi, min() terminal operatsiyasi bo'lib, asl oqimning mazmunini yo'q qiladi, faqat yakuniy natijani qaytaradi (bu holda "eng kichik" butun son edi).

findAny() va findFirst()

findAny() oqimning istalgan elementini ixtiyoriy sifatida qaytaradi . Agar oqim bo'sh bo'lsa, u bo'sh bo'lgan ixtiyoriy qiymatni ham qaytaradi . findFirst() oqimning birinchi elementini ixtiyoriy sifatida qaytaradi . findAny() usulida bo'lgani kabi , findFirst() usuli ham mos keladigan oqim bo'sh bo'lsa, bo'sh Ixtiyoriy parametrni qaytaradi. Keling, ushbu usullar asosida quyidagi misolni ko'rib chiqaylik:
Stream<Integer> numStream = Stream.of(43, 65, 1, 98, 63); Optional<Integer> opt = numStream.findFirst();System.out.println(opt); numStream = Stream.empty(); opt = numStream.findAny();System.out.println(opt);
Xulosa:
Majburiy emas[43] Ixtiyoriy.boʻsh
Izoh: Bu erda, birinchi holatda, findFirst() usuli oqimning birinchi elementini ixtiyoriy sifatida qaytaradi . Keyin, ip bo'sh ip sifatida qayta tayinlanganda, findAny() usuli bo'sh Optional ni qaytaradi .

allMatch() , anyMatch() va noneMatch()

AllMatch() usuli oqimdagi barcha elementlarning ma'lum bir predikatga mos kelishini tekshirish uchun ishlatiladi va agar mos keladigan bo'lsa, mantiqiy qiymatni true , aks holda false qaytaradi . Agar oqim bo'sh bo'lsa, u true qiymatini qaytaradi . AnyMatch() usuli oqimdagi elementlardan birortasi ma'lum bir predikatga mos kelishini tekshirish uchun ishlatiladi. Agar shunday bo'lsa rost , aks holda yolg'on qaytaradi . Agar oqim bo'sh bo'lsa, u false ni qaytaradi . Agar oqimdagi hech bir element predikatga mos kelmasa, noneMatch() usuli true ni qaytaradi , aks holda esa false . Buni ko'rsatish uchun misol quyidagicha ko'rinadi:
Stream<Integer> numStream = Stream.of(43, 65, 1, 98, 63); boolean flag = numStream.allMatch(n -> n1); System.out.println(flag); numStream = Stream.of(43, 65, 1, 98, 63); flag = numStream.anyMatch(n -> n1); System.out.println(flag); numStream = Stream.of(43, 65, 1, 98, 63); flag = numStream.noneMatch(n -> n==1);System.out.println(flag);
Xulosa:
yolg'on haqiqiy yolg'on
Izoh: Element sifatida 1 ni o'z ichiga olgan numStream oqimi uchun allMatch() usuli false qaytaradi , chunki barcha elementlar 1 emas, faqat bittasi. anyMatch() usuli rost qaytaradi , chunki elementlardan kamida bittasi 1. noneMatch() usuli notoʻgʻri qaytaradi , chunki 1 haqiqatda ushbu oqimda element sifatida mavjud.

Java oqimidagi dangasa baholashlar

Java 8 da Java Streams bilan ishlashda dangasa baholash optimallashtirishga olib keladi. Ular, asosan, oraliq operatsiyalarni terminal operatsiyasiga duch kelguncha kechiktirishni o'z ichiga oladi. Dangasa baholash natija haqiqatda zarur bo'lgunga qadar hisob-kitoblarga resurslarni keraksiz sarflashning oldini olish uchun javobgardir. Oraliq operatsiyalar natijasida hosil bo'lgan chiqish oqimi faqat terminal ishi tugagandan so'ng hosil bo'ladi. Lazy baholash Java oqimlaridagi barcha oraliq operatsiyalar bilan ishlaydi. Dangasa baholashdan juda foydali foydalanish cheksiz oqimlar bilan ishlashda yuzaga keladi. Shunday qilib, juda ko'p keraksiz ishlov berishning oldi olinadi.

Java oqimidagi quvurlar

Java oqimidagi quvur liniyasi kirish oqimidan, nol yoki undan ko'p oraliq operatsiyalardan va nihoyat terminal operatsiyasidan iborat. Java Streams da oraliq operatsiyalar dangasalik bilan bajariladi. Bu quvurli oraliq operatsiyalarni muqarrar qiladi. Asosan tartibda birlashtirilgan oraliq operatsiyalar bo'lgan quvur liniyalari bilan dangasa bajarish mumkin bo'ladi. Quvur quvurlari terminal operatsiyasi nihoyat duch kelganidan keyin bajarilishi kerak bo'lgan oraliq operatsiyalarni kuzatishga yordam beradi.

Xulosa

Keling, bugun o'rganganlarimizni umumlashtiramiz. Ushbu maqolada:
  1. Biz Java Streams nima ekanligini tezda ko'rib chiqdik.
  2. Keyin biz Java 8 da Java iplarini yaratishning ko'plab turli usullarini o'rgandik.
  3. Biz Java oqimlarida bajarilishi mumkin bo'lgan ikkita asosiy turdagi operatsiyalarni (oraliq operatsiyalar va terminal operatsiyalari) o'rgandik.
  4. Keyin biz oraliq va terminal operatsiyalarning bir nechta misollarini batafsil ko'rib chiqdik.
  5. Biz dangasa baholash haqida ko'proq ma'lumotga ega bo'ldik va nihoyat Java iplarida quvur liniyasini o'rganishni o'rgandik.
Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION