ג'אווה 8 וזרמים אינסופיים

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

במאמר זה נבחן א java.util.Stream API ונראה כיצד נוכל להשתמש במבנה זה כדי לפעול בזרם אינסופי של נתונים / אלמנטים.

האפשרות לעבוד על רצף האלמנטים האינסופי מבוססת על העובדה שזרמים בנויים כעצלנים.

עצלות זו מושגת על ידי הפרדה בין שני סוגים של פעולות שניתן לבצע בזרמים: ביניים ו מָסוֹף פעולות.

2. פעולות ביניים ומסופים

את כל זרם הפעולות מחולקות ל ביניים ו מָסוֹף פעולות ומשולבים ליצירת צינורות זרם.

צינור זרם מורכב ממקור (כגון א אוסף, מערך, פונקציית מחולל, ערוץ קלט / פלט או מחולל רצפים אינסופי); ואחריו אפס פעולות ביניים או יותר ופעולת מסוף.

2.1. ביניים פעולות

ביניים פעולות אינן מבוצעות יחידה מסוימת מָסוֹף הפעולה מופעלת.

הם מורכבים ויוצרים צינור של זרם ביצוע. ה ביניים ניתן להוסיף פעולה לא זרם צינור בשיטות:

  • לְסַנֵן()
  • מַפָּה()
  • flatMap ()
  • מוּבהָק()
  • מְמוּיָן()
  • לְהָצִיץ()
  • לְהַגבִּיל()
  • לדלג()

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

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

ככזה, מעבר של זרם לא מתחיל עד מָסוֹף פעולת הצינור מבוצעת.

זהו מאפיין חשוב מאוד, חשוב במיוחד עבור זרמים אינסופיים - מכיוון שהוא מאפשר לנו ליצור זרמים שיופעלו למעשה רק כאשר מָסוֹף מבצע נקרא.

2.2. מָסוֹף פעולות

מָסוֹף פעולות עשויות לחצות את הנחל כדי לייצר תוצאה או תופעת לוואי.

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

הלהיטות של פעולה סופנית חשובה באשר לאינסוף זרמים בגלל ברגע העיבוד עלינו לחשוב היטב אם שלנו זרם מוגבל כראוי על ידי, למשל, א לְהַגבִּיל() טרנספורמציה. מָסוֹף הפעולות הן:

  • לכל אחד()
  • forEachOrended ()
  • toArray ()
  • לְהַפחִית()
  • לאסוף()
  • דקה ()
  • מקסימום ()
  • לספור()
  • anyMatch ()
  • allMatch ()
  • noneMatch ()
  • findFirst ()
  • findAny ()

כל אחת מהפעולות הללו תפעיל את כל פעולות הביניים.

3. זרמים אינסופיים

עכשיו שאנחנו מבינים את שני המושגים האלה - ביניים ו מָסוֹף פעולות - אנו מסוגלים לכתוב זרם אינסופי הממנף את העצלות של זרמים.

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

חשוב להשתמש ב- לְהַגבִּיל() שיטה לפני ביצוע א לאסוף() שיטה זו פעולת מסוף, אחרת התוכנית שלנו תפעל ללא הגבלת זמן:

// נתון זרם infiniteStream = Stream.iterate (0, i -> i + 2); // כאשר List collect = infiniteStream .limit (10) .collect (Collectors.toList ()); // ואז assertEquals (collect, Arrays.asList (0, 2, 4, 6, 8, 10, 12, 14, 16, 18));

יצרנו זרם אינסופי באמצעות לְחַזֵר() שיטה. ואז קראנו a לְהַגבִּיל() טרנספורמציה ו לאסוף() הפעלת מסוף. ואז בתוצאה שלנו רשימה, יהיו לנו 10 אלמנטים ראשונים של רצף אינסופי בגלל עצלות של a זרם.

4. זרם אינסופי של סוג אלמנטים מותאם אישית

בואו נגיד שאנחנו רוצים ליצור זרם אינסופי של אקראי UUIDs.

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

ספק randomUUIDSupplier = UUID :: randomUUID;

כאשר אנו מגדירים ספק אנו יכולים ליצור זרם אינסופי באמצעות a לִיצוֹר() שיטה:

Stream infiniteStreamOfRandomUUID = Stream.generate (randomUUIDSupplier);

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

רשימת randomInts = infiniteStreamOfRandomUUID .skip (10) .limit (10) .collect (Collectors.toList ());

אנו משתמשים ב- לדלג() טרנספורמציה כדי להשליך את 10 התוצאות הראשונות ולקחת את 10 האלמנטים הבאים. אנו יכולים ליצור זרם אינסופי של כל רכיב מסוג מותאם אישית על ידי העברת פונקציה של a ספק ממשק ל- לִיצוֹר() שיטה על א זרם.

6. עושה תוך כדי - דרך הזרם

בואו נגיד שיש לנו פשוט לעשות .. תוך כדי לולאה בקוד שלנו:

int i = 0; ואילו (i <10) {System.out.println (i); i ++; }

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

למרבה הצער, אין שיטה כזו בזרם וכאשר אנו רוצים להשיג פונקציונליות דומה לתקן עושה תוך כדי לולאה עלינו להשתמש ב- לְהַגבִּיל() שיטה:

מספרים שלמים של זרם = זרם .iterate (0, i -> i + 1); מספרים שלמים .limit (10) .forEach (System.out :: println);

השגנו את אותה פונקציונליות כמו חובה בזמן לולאה עם פחות קוד, אבל התקשר אל לְהַגבִּיל() הפונקציה אינה תיאורית כפי שהייתה אם היה לנו עושה תוך כדי() שיטה על א זרם לְהִתְנַגֵד.

5. מסקנה

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

את הקוד התומך בכל הדוגמאות הללו ניתן למצוא בפרויקט GitHub - זהו פרויקט Maven, כך שיהיה קל לייבא ולהפעיל אותו כפי שהוא.


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