JavaRush /בלוג Java /Random-HE /היפטרות מלולאות ב-Java 8
KapChook
רָמָה
Volga

היפטרות מלולאות ב-Java 8

פורסם בקבוצה
הסגנון הפונקציונלי שהוצג ב-Java 8 הוא תוספת נהדרת לשפה. כעת ג'אווה אינה OOP טהורה, כעת היא הכלאה של OOP ותכנות פונקציונלי. זהו מחליף משחק ואנחנו צריכים לשנות את מוחות ה-OOP שלנו כדי לספוג את השינויים האלה. היפטרות מלולאות ב-Java 8 - 1אבל מדוע עלינו לקבל את השינויים הללו? מדוע עלינו לבזבז זמן בניסיון להסתדר עם סגנון פונקציונלי כאשר אנו יכולים לפתור את הבעיה באמצעות OOP טהור?
  • הסגנון הפונקציונלי שהוצג ב-Java 8 עוזר לנו לצמצם את הפער בין ההיגיון העסקי לקוד. היא מאפשרת לנו לספר את הסיפור בזרימה טבעית ברמה גבוהה יותר. במקום להגיד איך אתה רוצה לעשות את זה, אתה יכול להגיד מה שאתה רוצה לעשות.

  • הקוד הופך נקי ותמציתי יותר.

  • פונקציות מסדר גבוה מאפשרות לנו:

    • שלח פונקציות לפונקציות אחרות
    • צור פונקציות בתוך פונקציות אחרות
    • החזר פונקציות מפונקציות אחרות

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

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

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

  • דפוסים חדשים ללמוד.

  • ועוד הרבה!

אבל מספיק מים, במאמר זה נסתכל על פתרונות חלופיים למחזורים מסורתיים. כמובן שהמחזורים גמישים, אבל זה לא בא בלי מחיר. break, לשנות באופן דרמטי את התנהגות הלולאה, מה שמאלץ אותנו להבין לא רק מה הקוד מנסה להשיג, continueאלא returnגם להבין איך הלולאה עובדת. כעת נסקור כיצד אנו יכולים להפוך לולאות לקוד תמציתי וקריא יותר.

תן לקידוד להתחיל!

נעבוד עם מאמרים. למאמר יש כותרת, מחבר ומספר תגים.
private class Article {

    private final String title;
    private final String author;
    private final List<String> tags;

    private Article(String title, String author, List<String> tags) {
        this.title = title;
        this.author = author;
        this.tags = tags;
    }

    public String getTitle() {
        return title;
    }

    public String getAuthor() {
        return author;
    }

    public List<String> getTags() {
        return tags;
    }
}
כל דוגמה תכיל פתרון מסורתי באמצעות לולאות ופתרון המשתמש בתכונות החדשות של Java 8. בדוגמה הראשונה, אנו רוצים למצוא את המאמר הראשון באוסף עם התגית "Java". בואו נסתכל על פתרון באמצעות לולאה.
public Article getFirstJavaArticle() {

    for (Article article : articles) {
        if (article.getTags().contains("Java")) {
            return article;
        }
    }
    return null;
}
כעת נפתור את הבעיה באמצעות פעולות מ- Stream API.
public Optional<Article> getFirstJavaArticle() {
    return articles.stream()
        .filter(article -> article.getTags().contains("Java"))
        .findFirst();
    }
די מגניב, לא? תחילה אנו משתמשים בפעולה filterכדי למצוא את כל המאמרים עם התגית "Java", ולאחר מכן אנו משתמשים findFirst()כדי לקבל את המופע הראשון. מכיוון שהזרמים עצלנים והפילטר מחזיר זרם, גישה זו תעבד רק אלמנטים עד שתמצא את ההתאמה הראשונה. עכשיו בואו נקבל את כל המאמרים שתויגו "Java" במקום רק הראשון. ראשית הפתרון באמצעות לולאות.
public List<Article> getAllJavaArticles() {

    List<Article> result = new ArrayList<>();

    for (Article article : articles) {
        if (article.getTags().contains("Java")) {
            result.add(article);
        }
    }
    return result;
}
פתרון באמצעות פעולות זרם.
public List<Article> getAllJavaArticles() {
    return articles.stream()
        .filter(article -> article.getTags().contains("Java"))
        .collect(Collectors.toList());
    }
בדוגמה זו, השתמשנו בפעולה collectכדי לקצר את הזרם שנוצר, במקום להכריז על אוסף ולהוסיף במפורש את הערכים התואמים. בינתיים הכל טוב. הגיע הזמן לדוגמאות שיגרמו ל-Stream API לזרוח באמת. בואו נקבץ את כל המאמרים לפי מחבר. כרגיל, אנו מתחילים בפתרון באמצעות לולאות:
public Map<String, List<Article>> groupByAuthor() {

    Map<String, List<Article>> result = new HashMap<>();

    for (Article article : articles) {
        if (result.containsKey(article.getAuthor())) {
            result.get(article.getAuthor()).add(article);
        } else {
            ArrayList<Article> articles = new ArrayList<>();
            articles.add(article);
            result.put(article.getAuthor(), articles);
        }
    }
    return result;
}
האם נוכל למצוא פתרון נקי לבעיה זו באמצעות פעולות זרם?
public Map<String, List<Article>> groupByAuthor() {
    return articles.stream()
        .collect(Collectors.groupingBy(Article::getAuthor));
}
מדהים! על ידי שימוש בפעולה groupingByובהפניה לשיטה getAuthor(), אנו מקבלים קוד נקי וקריא. עכשיו בואו נמצא את שאר התגים המשמשים באוסף. נתחיל עם דוגמה ללולאה:
public Set<String> getDistinctTags() {

    Set<String> result = new HashSet<>();

    for (Article article : articles) {
        result.addAll(article.getTags());
    }
    return result;
}
אוקיי, בואו נסתכל כיצד נוכל לפתור את זה באמצעות פעולות זרם:
public Set<String> getDistinctTags() {
    return articles.stream()
        .flatMap(article -> article.getTags().stream())
        .collect(Collectors.toSet());
}
מגניב! flatmapעוזר לנו לשטח את רשימת התגים לזרם תוצאות בודד, שבו אנו משתמשים לאחר מכן collectכדי ליצור את ערכת ההחזרה.

אינסוף אפשרויות

אלו היו 4 דוגמאות כיצד ניתן להחליף לולאות בקוד קריא יותר. הקפד לבדוק את ה-API של Stream, מכיוון שמאמר זה רק שרט את פני השטח. שליטה בסגנון הפונקציונלי החדש של Java יהיה אתגר עבור מפתחי OOP, אבל זה אתגר שצריך להתקבל היטב. אני אפילו ארחיק יותר ואומר שכדאי לך ללמוד שפת תכנות פונקציונלית טהורה. כך תוכלו להבין היטב את היכולות והעוצמה שהוא מספק. אני חושב שזה יעזור לך להבין תכנות פונקציונלי ברמה אחרת. אז למד תכנות פונקציונלי יחד עם OOP הישן והטוב, והשתמש בשניהם כדי לכתוב קוד גדול עוד יותר! שילוב חינם של תרגומים של שני מאמרים - מדוע כדאי לאמץ תכנות פונקציונלי ב-Java 8 ו- Swerving Away from Loops ב-Java 8
הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION