JavaRush /Java Blogu /Random-AZ /Kofe fasiləsi №177. Java 8-də Java Stream üçün Ətraflı Bə...

Kofe fasiləsi №177. Java 8-də Java Stream üçün Ətraflı Bələdçi

Qrupda dərc edilmişdir
Mənbə: Hackernoon Bu yazı kod nümunələri və izahatları ilə birlikdə Java Stream ilə işləmək haqqında ətraflı təlimat təqdim edir. Kofe fasiləsi №177.  Java 8-1-də Java Stream üçün Ətraflı Bələdçi

Java 8-də Java Threads-a giriş

Java 8-in bir hissəsi kimi təqdim edilən Java Streams məlumat kolleksiyaları ilə işləmək üçün istifadə olunur. Onlar özləri məlumat strukturu deyillər, lakin son nəticəni əldə etmək üçün sifariş vermək və boru kəmərini çəkməklə digər məlumat strukturlarından məlumat daxil etmək üçün istifadə edilə bilər. Qeyd: Stream və Thread-ı qarışdırmamaq vacibdir, çünki rus dilində hər iki termin çox vaxt eyni tərcümədə "axın" adlanır. Stream əməliyyatları yerinə yetirmək üçün (ən çox məlumatların ötürülməsi və ya saxlanması) obyekti, Thread (hərfi tərcümə - mövzu) isə digər kod filialları ilə paralel olaraq müəyyən proqram kodunu icra etməyə imkan verən obyekti bildirir. Stream ayrıca məlumat strukturu olmadığı üçün heç vaxt məlumat mənbəyini dəyişdirmir. Java axınları aşağıdakı xüsusiyyətlərə malikdir:
  1. Java Stream “java.util.stream” paketindən istifadə etməklə istifadə edilə bilər. Kodu istifadə edərək skriptə idxal edilə bilər:

    import java.util.stream.* ;

    Bu kodu istifadə edərək, biz Java Stream-də bir neçə daxili funksiyanı da asanlıqla həyata keçirə bilərik.

  2. Java Stream Java-da kolleksiyalar və massivlər kimi məlumat kolleksiyalarından daxil olan məlumatları qəbul edə bilər.

  3. Java Stream giriş məlumat strukturunun dəyişdirilməsini tələb etmir.

  4. Java Stream mənbəni dəyişmir. Əvəzində, müvafiq boru kəməri üsullarından istifadə edərək məhsul istehsal edir.

  5. Java axınları aralıq və terminal əməliyyatlara tabedir, biz bunları sonrakı bölmələrdə müzakirə edəcəyik.

  6. Java Stream-də ara əməliyyatlar tənbəl qiymətləndirmə formatında həyata keçirilir. Onlar terminal funksiyaları ilə bitir. Bu, Java Stream-dən istifadə üçün əsas formatı təşkil edir.

Növbəti hissədə biz Java 8-də tələb olunduqda Java Axını yaratmaq üçün istifadə olunan müxtəlif üsullara baxacağıq.

Java 8-də Java Stream yaratmaq

Java mövzuları bir neçə yolla yaradıla bilər:

1. Stream.empty() metodundan istifadə edərək boş axının yaradılması

Daha sonra kodunuzda istifadə etmək üçün boş axın yarada bilərsiniz. Stream.empty() metodundan istifadə etsəniz , heç bir dəyəri olmayan boş axın yaradılacaq. Bu boş axın lazımlı ola bilər, əgər biz işləmə zamanı null göstərici istisnasını keçmək istəyirik. Bunu etmək üçün aşağıdakı əmrdən istifadə edə bilərsiniz:
Stream<String> str = Stream.empty();
Yuxarıdakı ifadə daxilində heç bir element olmadan str adlı boş axın yaradacaq . Bunu yoxlamaq üçün str.count() terminindən istifadə edərək axının sayını və ya ölçüsünü yoxlamaq kifayətdir . Misal üçün,
System.out.println(str.count());
Nəticədə çıxışda 0 alırıq .

2. Stream.Builder nümunəsi ilə Stream.builder() metodundan istifadə edərək axın yaradın

Qurucu dizayn nümunəsindən istifadə edərək axın yaratmaq üçün Stream Builder-dən də istifadə edə bilərik . Obyektlərin addım-addım tikintisi üçün nəzərdə tutulmuşdur. Gəlin Stream Builder-dən istifadə edərək axını necə qura biləcəyimizi görək .
Stream.Builder<Integer> numBuilder = Stream.builder();

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

Stream<Integer> numStream = numBuilder.build();
Bu kodu istifadə edərək, siz int elementləri olan numStream adlı axın yarada bilərsiniz . Əvvəlcə yaradılan numBuilder adlı Stream.Builder instansiyası sayəsində hər şey olduqca tez edilir .

3. Stream.of() metodundan istifadə edərək müəyyən edilmiş dəyərlərlə axın yaradın

Axın yaratmağın başqa bir yolu Stream.of() metodundan istifadə etməkdir . Bu, verilmiş dəyərlərlə axın yaratmağın sadə yoludur. O, elan edir və həmçinin mövzunu işə salır. Axın yaratmaq üçün Stream.of() metodundan istifadə nümunəsi:
Stream<Integer> numStream = Stream.of(1, 2, 3);
Bu kod, Stream.Builder istifadə edərək əvvəlki metodda etdiyimiz kimi int elementlərindən ibarət axın yaradacaq . Burada əvvəlcədən təyin edilmiş [1, 2 və 3] dəyərləri ilə Stream.of() istifadə edərək birbaşa axın yaratdıq .

4. Arrays.stream() metodundan istifadə edərək mövcud massivdən axın yaradın

Mövzu yaratmaq üçün başqa bir ümumi üsul Java-da massivlərdən istifadə etməyi əhatə edir. Buradakı axın Arrays.stream() metodundan istifadə edərək mövcud massivdən yaradılır . Bütün massiv elementləri axın elementlərinə çevrilir. Budur yaxşı bir nümunə:
Integer[] arr = {1, 2, 3, 4, 5};

Stream<Integer> numStream = Arrays.stream(arr);
Bu kod tam ədəd massivi olan arr adlı massivin məzmununu ehtiva edən numStream yaradacaq .

5. Stream.concat() metodundan istifadə etməklə iki mövcud axının birləşdirilməsi

Axın yaratmaq üçün istifadə edilə bilən başqa bir üsul Stream.concat() metodudur . Tək bir ip yaratmaq üçün iki ipi birləşdirmək üçün istifadə olunur. Hər iki axın ardıcıllıqla birləşdirilir. Bu o deməkdir ki, birinci ip birinci gəlir, ondan sonra ikinci ip gəlir və s. Belə birləşmə nümunəsi belə görünür:
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);
Yuxarıdakı ifadə birinci axın numStream1 və ikinci axın numStream2 elementlərini bir-bir ehtiva edən birləşdirilmişStream adlı yekun axın yaradacaq .

Java Stream ilə əməliyyat növləri

Artıq qeyd edildiyi kimi, Java 8-də Java Stream ilə iki növ əməliyyat həyata keçirə bilərsiniz: aralıq və terminal. Onların hər birinə daha ətraflı baxaq.

Aralıq əməliyyatlar

Aralıq əməliyyatlar çıxış axını yaradır və yalnız terminal əməliyyatı ilə qarşılaşdıqda yerinə yetirilir. Bu o deməkdir ki, aralıq əməliyyatlar tənbəl şəkildə yerinə yetirilir, boru kəməri çəkilir və yalnız terminal əməliyyatı ilə tamamlana bilər. Tənbəl qiymətləndirmə və boru kəməri haqqında bir az sonra öyrənəcəksiniz. Aralıq əməliyyatlara misal olaraq aşağıdakı üsulları göstərmək olar: filter() , map() , different() , peek() , sorted() və digərləri.

Terminal əməliyyatları

Terminal əməliyyatları aralıq əməliyyatların icrasını tamamlayır və həmçinin çıxış axınının yekun nəticələrini qaytarır. Terminal əməliyyatları tənbəl icra və boru kəmərinin sona çatdığını bildirdiyi üçün terminal əməliyyatından sonra bu ip yenidən istifadə edilə bilməz. Terminal əməliyyatlarına misal olaraq aşağıdakı üsulları göstərmək olar: forEach() , collect() , count() , reduce() və s.

Java Stream ilə əməliyyatların nümunələri

Aralıq əməliyyatlar

Java axınına tətbiq oluna bilən bəzi ara əməliyyatların bəzi nümunələri bunlardır:

filter()

Bu üsul Java-da müəyyən bir predikata uyğun gələn bir axın elementlərini süzmək üçün istifadə olunur. Bu süzgəcdən keçirilmiş elementlər sonra yeni axın təşkil edir. Daha yaxşı başa düşmək üçün bir nümunəyə nəzər salaq.
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);
Nəticə:
[98]
İzahat: Bu misalda siz görə bilərsiniz ki, hətta elementlər (2-yə bölünür) filter () metodu ilə süzülür və məzmunu daha sonra çap olunan numStream tam siyahısında saxlanılır . 98 axındakı yeganə cüt tam ədəd olduğundan, çıxışda çap olunur.

xəritə()

Bu üsul orijinal giriş axınının elementlərində xəritələnmiş funksiyaları yerinə yetirməklə yeni axın yaratmaq üçün istifadə olunur. Ola bilsin ki, yeni axın fərqli məlumat növünə malikdir. Nümunə belə görünür:
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);
Nəticə:
[86, 130, 2, 196, 126]
İzahat: Burada görürük ki, map() metodu numStream axınının hər bir elementini sadəcə ikiqat artırmaq üçün istifadə olunur . Çıxışdan göründüyü kimi, axındakı elementlərin hər biri uğurla ikiqat artırıldı.

fərqli()

Bu üsul dublikatları süzməklə axındakı yalnız fərdi elementləri əldə etmək üçün istifadə olunur. Eyni nümunə belə görünür:
Stream<Integer> numStream = Stream.of(43,65,1,98,63,63,1); List<Integer> numList = numStream.distinct() .collect(Collectors.toList()); System.out.println(numList);
Nəticə:
[43, 65, 1, 98, 63]
İzahat: Bu halda numStream üçün different() metodu istifadə olunur . O , cərəyandan dublikatları silməklə numList -dəki bütün fərdi elementləri götürür . Çıxışdan göründüyü kimi, ilkin olaraq iki dublikat (63 və 1) olan giriş axınından fərqli olaraq heç bir dublikat yoxdur.

peek()

Bu üsul terminal əməliyyatını yerinə yetirməzdən əvvəl aralıq dəyişiklikləri izləmək üçün istifadə olunur. Bu o deməkdir ki, peek() əlavə aralıq əməliyyatların yerinə yetirilə biləcəyi axın yaratmaq üçün axının hər bir elementi üzərində əməliyyat yerinə yetirmək üçün istifadə edilə bilər.
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);
Nəticə:
Xəritəli: 430 Xəritədə: 650 Xəritədə: 10 Xəritədə: 980 Xəritədə: 630 [430, 650, 10, 980, 630]
İzahat: Burada peek() metodu axının elementlərinə map() metodu tətbiq edildiyi üçün aralıq nəticələrin yaradılması üçün istifadə olunur . Burada qeyd edə bilərik ki, hətta çap bəyanatında siyahının son məzmununu çap etmək üçün collect() terminal əməliyyatından istifadə etməzdən əvvəl , hər bir axın elementinin xəritələşdirilməsi üçün nəticə əvvəlcədən ardıcıl olaraq çap olunur.

sıralanmış()

Sorted() metodu axının elementlərini çeşidləmək üçün istifadə olunur. Varsayılan olaraq, o, elementləri artan qaydada çeşidləyir. Siz həmçinin parametr kimi xüsusi çeşidləmə sırasını təyin edə bilərsiniz. Bu metodun tətbiqi nümunəsi belə görünür:
Stream<Integer> numStream = Stream.of(43, 65, 1, 98, 63); numStream.sorted().forEach(n -> System.out.println(n));
Nəticə:
1 43 ​​63 65 98
İzahat: Burada axın elementlərini defolt olaraq artan qaydada çeşidləmək üçün sorted() metodundan istifadə olunur (çünki heç bir xüsusi sıra göstərilməyib). Çıxışda çap olunan maddələrin artan qaydada düzüldüyünü görə bilərsiniz.

Terminal əməliyyatları

Java axınlarına tətbiq oluna bilən bəzi terminal əməliyyatlarına bəzi nümunələr:

forEach()

ForEach() metodu axının bütün elementlərini təkrarlamaq və funksiyanı hər bir elementdə bir-bir yerinə yetirmək üçün istifadə olunur. Bu, for , while və başqaları kimi döngə ifadələrinə alternativ kimi çıxış edir . Misal:
Stream<Integer> numStream = Stream.of(43, 65, 1, 98, 63); numStream.forEach(n -> System.out.println(n));
Nəticə:
43 65 1 98 63
İzahat: Burada axının hər bir elementini bir-bir çap etmək üçün forEach() metodundan istifadə olunur.

saymaq()

count() metodu axındakı elementlərin ümumi sayını əldə etmək üçün istifadə olunur. Bu , kolleksiyadakı elementlərin ümumi sayını təyin etmək üçün tez-tez istifadə olunan size() metoduna bənzəyir . Java Stream ilə count() metodundan istifadə nümunəsi aşağıdakı kimidir:
Stream<Integer> numStream = Stream.of(43, 65, 1, 98, 63); System.out.println(numStream.count());
Nəticə:
5
İzahat: numStream 5 tam elementdən ibarət olduğundan, onun üzərindəki count() metodundan istifadə etməklə 5 çıxacaq.

toplamaq()

Collection () metodu axın elementlərinin dəyişkən azaldılmasını həyata keçirmək üçün istifadə olunur. O, emal tamamlandıqdan sonra məzmunu axından silmək üçün istifadə edilə bilər. Azaltmaları yerinə yetirmək üçün Kollektor sinifindən istifadə edir .
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);
Nəticə:
[43, 65, 1, 63]
İzahat: Bu nümunədə axındakı bütün tək elementlər süzülür və odd adlı siyahıya toplanır/kiçildilir . Sonda tək olanların siyahısı çap olunur.

min()max()

Min() metodu adından göründüyü kimi axındakı minimum elementi tapmaq üçün istifadə edilə bilər. Eynilə, axındakı maksimum elementi tapmaq üçün max() metodundan istifadə etmək olar. Onların bir nümunə ilə necə istifadə oluna biləcəyini anlamağa çalışaq:
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);
Nəticə:
Ən kiçik element: 1 Ən böyük element: 98
İzahat: Bu misalda biz min() metodundan istifadə edərək numStream-də ən kiçik elementi və max ( ) metodundan istifadə edərək ən böyük elementi çap etdik . Qeyd edək ki, burada max() metodundan istifadə etməzdən əvvəl biz numStream -ə yenidən elementlər əlavə etmişik . Çünki min() terminal əməliyyatıdır və yalnız son nəticəni qaytararaq (bu halda “ən kiçik” tam ədəd idi) orijinal axının məzmununu məhv edir.

findAny()findFirst()

findAny() axının istənilən elementini Könüllü olaraq qaytarır . Əgər axın boşdursa, o , həmçinin boş olacaq Könüllü dəyər qaytaracaq . findFirst() axının ilk elementini Könüllü olaraq qaytarır . findAny() metodunda olduğu kimi , findFirst() metodu da uyğun axın boş olarsa, boş Könüllü parametr qaytarır . Bu üsullara əsaslanaraq aşağıdakı nümunəyə nəzər salaq:
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);
Nəticə:
Könüllü[43] Könüllü.boş
İzahat: Burada birinci halda findFirst() metodu axının ilk elementini Könüllü olaraq qaytarır . Sonra, mövzu boş ip kimi təyin edildikdə, findAny() metodu boş Optional qaytarır .

allMatch() , anyMatch()noneMatch()

allMatch() metodu axındakı bütün elementlərin müəyyən bir predikata uyğun olub-olmadığını yoxlamaq üçün istifadə olunur və əgər uyğun gələrsə, boolean dəyərini doğru , əks halda isə false qaytarır . Əgər axın boşdursa, doğru qaytarır . AnyMatch() metodu axındakı elementlərdən hər hansı birinin müəyyən bir predikata uyğun olub olmadığını yoxlamaq üçün istifadə olunur. Əgər belədirsə doğru , əks halda yalan qaytarır . Axın boşdursa, false qaytarır . Əgər axındakı heç bir element predikata uyğun gəlmirsə noneMatch() metodu doğru , əks halda isə false qaytarır . Bunu göstərmək üçün bir nümunə belə görünür:
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);
Nəticə:
yalan doğru yalan
İzahat: Element olaraq 1-dən ibarət numStream axını üçün allMatch() metodu false qaytarır , çünki bütün elementlər 1 deyil, onlardan yalnız biri var. anyMatch() metodu doğru qaytarır , çünki elementlərdən ən azı biri 1-dir. noneMatch() metodu false qaytarır , çünki 1 faktiki olaraq bu axında element kimi mövcuddur.

Java axınında tənbəl qiymətləndirmələr

Tənbəl qiymətləndirmə Java 8-də Java Streams ilə işləyərkən optimallaşdırmalara gətirib çıxarır. Onlar, əsasən, terminal əməliyyatı ilə qarşılaşana qədər ara əməliyyatların təxirə salınmasını nəzərdə tutur. Tənbəl qiymətləndirmə, nəticə həqiqətən lazım olana qədər hesablamalarda lazımsız resurs israfının qarşısını almaq üçün məsuliyyət daşıyır. Aralıq əməliyyatlar nəticəsində yaranan çıxış axını yalnız terminal əməliyyatı başa çatdıqdan sonra yaradılır. Tənbəl qiymətləndirmə Java axınlarında bütün ara əməliyyatlarla işləyir. Tənbəl qiymətləndirmənin çox faydalı istifadəsi sonsuz axınlarla işləyərkən baş verir. Bu yolla bir çox lazımsız emalın qarşısı alınır.

Java Stream-də boru kəmərləri

Java axınındakı boru kəməri giriş axınından, bir-birinin ardınca düzülmüş sıfır və ya daha çox aralıq əməliyyatlardan və nəhayət, terminal əməliyyatından ibarətdir. Java Streams-də ara əməliyyatlar tənbəlliklə yerinə yetirilir. Bu, boru kəməri ilə aralıq əməliyyatları qaçılmaz edir. Əsasən sıra ilə birləşdirilmiş ara əməliyyatlar olan boru kəmərləri ilə tənbəl icra mümkün olur. Boru kəmərləri terminal əməliyyatı ilə nəhayət qarşılaşdıqdan sonra yerinə yetirilməli olan aralıq əməliyyatları izləməyə kömək edir.

Nəticə

İndi bu gün öyrəndiklərimizi ümumiləşdirək. Bu məqalədə:
  1. Java axınlarının nə olduğuna qısaca nəzər saldıq.
  2. Daha sonra Java 8-də Java mövzuları yaratmaq üçün bir çox müxtəlif üsulları öyrəndik.
  3. Java axınlarında yerinə yetirilə bilən iki əsas əməliyyat növünü (aralıq əməliyyatlar və terminal əməliyyatları) öyrəndik.
  4. Sonra biz həm aralıq, həm də terminal əməliyyatlarının bir neçə nümunəsini ətraflı nəzərdən keçirdik.
  5. Biz tənbəl qiymətləndirmə haqqında daha çox öyrəndik və nəhayət Java mövzularında boru kəməri çəkməyi öyrəndik.
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION