מבוא ל- Protonpack

1. סקירה כללית

במדריך זה נבחן את התכונות העיקריות של Protonpack שהיא ספרייה המרחיבה את התקן זרם API על ידי הוספת פונקציונליות חינם.

עיין ברשימה זו כאן כדי לגלות את היסודות של Java זרם ממשק API.

2. תלות של Maven

כדי להשתמש בספריית Protonpack, עלינו להוסיף תלות ב- pom.xml קוֹבֶץ:

 com.codepoetics protonpack 1.15 

חפש את הגרסה האחרונה ב- Maven Central.

3. StreamUtils

זהו המחלקה העיקרית המרחיבה את תקן Java זרם ממשק API.

כל השיטות הנדונות כאן הן פעולות ביניים, כלומר הן משנות א זרם אך אינו מפעיל את עיבודו.

3.1. takeWhile () ו takeUntil ()

takeWhile () לוקח ערכים מזרם המקור כל עוד הם עומדים בתנאי המסופק:

זרם streamOfInt = זרם .iterate (1, i -> i + 1); תוצאת רשימה = StreamUtils .takeWhile (streamOfInt, i -> i <5) .collect (Collectors.toList ()); assertThat (תוצאה). מכיל (1, 2, 3, 4);

לעומת זאת, takeUntil () לוקח ערכים עד שערך עומד בתנאי המסופק ואז עוצר:

זרם streamOfInt = זרם .iterate (1, i -> i + 1); תוצאת רשימה = StreamUtils .takeUntil (streamOfInt, i -> i> = 5) .collect (Collectors.toList ()); assertThat (תוצאה). מכיל בדיוק (1, 2, 3, 4);

ב- Java 9 ואילך, takeWhile () הוא חלק מהתקן זרם ממשק API.

3.2. רוכסן()

רוכסן() לוקח שניים או שלושה זרמים כקלט ופונקציה קומבינר. השיטה לוקח ערך מאותה מיקום של כל זרם ומעביר אותו למשלב.

הוא עושה זאת עד שאחד מהזרמים נגמר לערכים:

מחרוזת [] מועדונים = {"יובנטוס", "ברצלונה", "ליברפול", "PSG"}; מחרוזת [] שחקנים = {"רונאלדו", "מסי", "סלאח"}; הגדר zippedFrom2Sources = StreamUtils .zip (זרם (מועדונים), זרם (שחקנים), (מועדון, שחקן) -> מועדון + "" + שחקן) .collect (Collectors.toSet ()); טוען כי (zippedFrom2Sources). מכיל ("יובנטוס רונאלדו", "ברצלונה מסי", "ליברפול סלאח"); 

באופן דומה, עומס יתר רוכסן() שלוקח זרם של שלושה מקורות:

מחרוזת [] ליגות = {"Serie A", "La Liga", "Premier League"}; הגדר zippedFrom3Sources = StreamUtils. Zip (זרם (מועדונים), זרם (שחקנים), זרם (ליגות), (מועדון, שחקן, ליגה) -> מועדון + "" + שחקן + "" + ליגה) .collect (Collectors.toSet ( )); טוען כי (zippedFrom3Sources). מכיל ("יובנטוס רונאלדו סרייה A", "ברצלונה מסי לה ליגה", "ליברפול סלאח פרמייר ליג");

3.3. zipWithIndex ()

zipWithIndex () לוקח ערכים ורוכס כל ערך באינדקס שלו כדי ליצור זרם של ערכים באינדקס:

זרם streamOfClubs = זרם. Of ("יובנטוס", "ברצלונה", "ליברפול"); מַעֲרֶכֶת zipsWithIndex = StreamUtils. zipWithIndex (streamOfClubs) .collect (Collectors.toSet ()); assertThat (zipsWithIndex) .contains (Indexed.index (0, "Juventus"), Indexed.index (1, "Barcelona"), Indexed.index (2, "Liverpool"));

3.4. לְמַזֵג()

לְמַזֵג() עובד עם מספר זרמי מקור ומשלב. זה לוקח את הערך של אותו מיקום אינדקס מכל זרם מקור ומעביר אותו למשלב.

השיטה עובדת על ידי לקיחת ערך אחד מאותו אינדקס מכל זרם ברצף, החל מ- זֶרַע ערך.

לאחר מכן הערך מועבר למשלב, והערך המשולב המתקבל מוחזר למשלב כדי ליצור את הערך הבא:

זרם streamOfClubs = זרם. Of ("יובנטוס", "ברצלונה", "ליברפול", "PSG"); זרם streamOfPlayers = זרם. Of ("רונאלדו", "מסי", "סלאח"); זרם streamOfLothers = זרם. Of ("סדרה A", "לה ליגה", "ליגת העל"); Set merged = StreamUtils.merge (() -> "", (valOne, valTwo) -> valOne + "" + valTwo, streamOfClubs, streamOfPlayers, streamOfLothers) .collect (Collectors.toSet ()); טוען כי (מוזג). מכיל ("יובנטוס רונאלדו סרייה A", "ברצלונה מסי לה ליגה", "ליברפול סלאח פרמייר ליג", "PSG");

3.5. mergeToList ()

mergeToList () לוקח זרמים מרובים כקלט. זה משלב את הערך של אותו אינדקס מכל זרם ל- a רשימה:

זרם streamOfClubs = זרם. Of ("יובנטוס", "ברצלונה", "PSG"); זרם streamOfPlayers = זרם. Of ("רונאלדו", "מסי"); זרם mergedStreamOfList = StreamUtils .mergeToList (streamOfClubs, streamOfPlayers); רשימה mergedListOfList = mergedStreamOfList .collect (Collectors.toList ()); assertThat (mergedListOfList.get (0)) .contains בדיוק ("יובנטוס", "רונאלדו"); assertThat (mergedListOfList.get (1)) .contains בדיוק ("ברצלונה", "מסי"); assertThat (mergedListOfList.get (2)) .containsExactly ("PSG");

3.6. משלב ()

משלב ()יוצר ערכים חלופיים שנלקחו ממספר זרמים באמצעות a בוחר.

השיטה נותנת קבוצה המכילה ערך אחד מכל זרם ל- בוחר, וה בוחר יבחר ערך אחד.

לאחר מכן הערך שנבחר יוסר מהערכה ויוחלף בערך הבא ממנו מקורו של הערך שנבחר. איטרציה זו נמשכת עד שנגמר הערכים של כל המקורות.

הדוגמה הבאה משתמשת משלב () כדי ליצור ערכים מתחלפים עם רובין העגול אִסטרָטֶגִיָה:

זרם streamOfClubs = זרם. Of ("יובנטוס", "ברצלונה", "ליברפול"); זרם streamOfPlayers = זרם. Of ("רונאלדו", "מסי"); זרם streamOfLothers = זרם. Of ("סדרה A", "לה ליגה"); רשימה interleavedList = StreamUtils .interleave (Selectors.roundRobin (), streamOfClubs, streamOfPlayers, streamOfL חברים) .collect (Collectors.toList ()); טוען כי (interleavedList). יש גודל (7). מכיל בדיוק ("יובנטוס", "רונאלדו", "סרייה A", "ברצלונה", "מסי", "לה ליגה", "ליברפול"); 

שים לב שהקוד שלעיל נועד למטרות הדרכה מכיוון ש- robin-robin בוחר מסופק על ידי הספרייה כ- Selectors.roundRobin ().

3.7. skipUntil () ו skipWhile ()

skipUntil () מדלג על הערכים עד שערך עומד בתנאי:

מספר שלם [] מספרים = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; רשימה skipippedUntilGreaterThan5 = StreamUtils .skipUntil (זרם (מספרים), i -> i> 5) .collect (Collectors.toList ()); assertThat (דילג על UntilGreaterThan5). מכיל בדיוק (6, 7, 8, 9, 10); 

בניגוד, skipWhile ()מדלג על הערכים בזמן שהערכים עומדים בתנאי:

מספר שלם [] מספרים = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; רשימה דלגה מדלגתWhileLessThanEquals5 = StreamUtils .skipWhile (stream (numbers), i -> i <= 5 ||) .collect (Collectors.toList ()); assertThat (מדלגWhileLessThanEquals5). מכיל בדיוק (6, 7, 8, 9, 10); 

דבר אחד חשוב ב skipWhile () היא שהיא תמשיך לזרום לאחר שמצא את הערך הראשון שאינו עומד בתנאי:

רשימה דלגה skipWhileGreaterThan5 = StreamUtils .skipWhile (זרם (מספרים), i -> i> 5) .collect (Collectors.toList ()); assertThat (דילג על זמןGreaterThan5). מכיל בדיוק (1, 2, 3, 4, 5, 6, 7, 8, 9, 10); 

ב- Java 9 ואילך, dropWhile() בתקן זרם API מספק את אותה פונקציונליות כמו skipWhile ().

3.8. לְהִתְפַּתֵחַ()

לְהִתְפַּתֵחַ() מייצר זרם שעלול להיות אינסופי על ידי החלת גנרטור מותאם אישית לערך זרע ואז על כל ערך שנוצר - ניתן לסיים את הזרם על ידי החזרה Optional.empty ():

זרם נפרש = StreamUtils .unfold (2, i -> (i <100)? Optional.of (i * i): Optional.empty ()); assertThat (unfolded.collect (Collectors.toList ())). מכיל בדיוק (2, 4, 16, 256);

3.9. חלון ()

חלון ()יוצר מספר קבוצות משנה של זרם המקור כזרם של רשימה. השיטה לוקחת זרם מקור, גודל חלון ו דלג על ערך כפרמטר.

ה רשימה אורך שווה חַלוֹןגודל, בעוד שערך kip קובע היכן תת-הקבוצה מתחילה ביחס לקבוצת המשנה הקודמת:

מספר שלם [] מספרים = {1, 2, 3, 4, 5, 6, 7, 8}; List windowedWithSkip1 = StreamUtils .windowed (stream (numbers), 3, 1) .collect (Collectors.toList ()); assertThat (windowedWithSkip1) .contains בדיוק (asList (1, 2, 3), asList (2, 3, 4), asList (3, 4, 5), asList (4, 5, 6), asList (5, 6, 7 )); 

בנוסף, מובטח כי החלון האחרון יהיה בגודל הרצוי, כפי שניתן לראות בדוגמה הבאה:

List windowedWithSkip2 = StreamUtils.windowed (זרם (מספרים), 3, 2) .collect (Collectors.toList ()); assertThat (windowedWithSkip2). מכיל בדיוק (asList (1, 2, 3), asList (3, 4, 5), asList (5, 6, 7)); 

3.10. לְקַבֵּץ()

יש שני לְקַבֵּץ() שיטות שעובדות אחרת לגמרי.

הראשון לְקַבֵּץ() מקבץ אלמנטים שווים על פי פרדיקט נתון:

מספר שלם [] מספרים = {1, 2, 2, 3, 4, 4, 4, 5}; רשימה מצטברת = StreamUtils .aggregate (Arrays.stream (numbers), (int1, int2) -> int1.compareTo (int2) == 0) .collect (Collectors.toList ()); assertThat (מצטבר). מכיל בדיוק (asList (1), asList (2, 2), asList (3), asList (4, 4, 4), asList (5)); 

הפרדיקט מקבל את הערכים באופן רציף. לכן, האמור לעיל ייתן תוצאה אחרת אם המספר לא הוזמן.

מצד שני, השני לְקַבֵּץ() פשוט רגיל קיבצו אלמנטים מזרם המקור לקבוצות בגודל הרצוי:

רשימה aggregatedFixSize = StreamUtils .aggregate (stream (numbers), 5) .collect (Collectors.toList ()); assertThat (aggregatedFixSize) .contains בדיוק (asList (1, 2, 2, 3, 4), asList (4, 4, 5)); 

3.11. aggregateOnListCondition ()

aggregateOnListCondition () ערכי קבוצות מבוסס על קבוצה פעילה נוכחית וקיימת. הפרדיקט מקבל את הקבוצה הפעילה כיום כ- רשימה והערך הבא. לאחר מכן עליה לקבוע אם הקבוצה צריכה להמשיך או לפתוח קבוצה חדשה.

הדוגמה הבאה פותרת דרישה לקבץ ערכי מספרים שלמים רצופים יחד בקבוצה, כאשר סכום הערכים בכל קבוצה לא יכול להיות גדול מ -5:

מספר שלם [] מספרים = {1, 1, 2, 3, 4, 4, 5}; זרם מצטבר = StreamUtils .aggregateOnListCondition (stream (numbers), (currentList, nextInt) -> currentList.stream (). mapToInt (Integer :: intValue) .sum () + nextInt <= 5); assertThat (מצטבר). מכיל בדיוק (asList (1, 1, 2), asList (3), asList (4), asList (4), asList (5));

4. ניתן להזרים

מופע של זרם אינו ניתן לשימוש חוזר. מהסיבה הזו, ניתן להזרים מספק זרמים לשימוש חוזר על ידי עטיפה וחשיפה של אותן שיטות כמו זרם:

Streamable s = Streamable.of ("a", "b", "c", "d"); רשימה שנאספה 1 = s.collect (Collectors.toList ()); רשימה שנאספו 2 = s.collect (Collectors.toList ()); assertThat (שנאסף 1). hasSize (4); assertThat (שנאסף 2). hasSize (4);

5. CollectorUtils

CollectorUtils משלים את התקן אספנים על ידי הוספת מספר שיטות אספנות שימושיות.

5.1. maxBy () ו minBy ()

maxBy ()מוצא את הערך המרבי בזרם באמצעות לוגיקת ההקרנה המסופקת:

מועדוני זרם = Stream.of ("יובנטוס", "ברצלונה", "PSG"); LongestName אופציונלי = clubs.collect (CollectorUtils.maxBy (מחרוזת :: אורך)); assertThat (longestName) .contains ("ברצלונה");

בניגוד, minBy ()מוצא את הערך המינימלי באמצעות לוגיקת ההקרנה המסופקת.

5.2. ייחודי()

ה ייחודי() אספן עושה דבר מאוד פשוט: הוא מחזיר את הערך היחיד אם לזרם נתון יש אלמנט אחד בדיוק:

זרם singleElement = Stream.of (1); ייחודי אופציונלי = singleElement.collect (CollectorUtils.unique ()); assertThat (ייחודי). מכיל (1); 

אחרת, ייחודי() ישליך חריג:

זרם multipleElement = Stream.of (1, 2, 3); assertThatExceptionOfType (NonUniqueValueException.class) .isTrowneBy (() -> {multipleElement.collect (CollectorUtils.unique ());}); 

6. מסקנה

במאמר זה למדנו כיצד ספריית Protonpack מרחיבה את ה- API של Java Stream כדי להקל על השימוש. זה מוסיף שיטות שימושיות שבהן אנו משתמשים בדרך כלל, אך חסרות ממשק ה- API הסטנדרטי.

החל מג'אווה 9, חלק מהפונקציונליות שמספקת Protonpack תהיה זמינה בממשק ה- Stream הסטנדרטי.

כרגיל, ניתן למצוא את הקוד ב- Github.


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