JavaRush /Blog Java /Random-PL /Pozbycie się pętli w Javie 8
KapChook
Poziom 19
Volga

Pozbycie się pętli w Javie 8

Opublikowano w grupie Random-PL
Styl funkcjonalny wprowadzony w Javie 8 jest doskonałym dodatkiem do języka. Teraz Java nie jest czystym OOP, teraz jest hybrydą OOP i programowania funkcjonalnego. To zmienia zasady gry i musimy zmienić nasze mózgi OOP, aby wchłonąć te zmiany. Pozbycie się pętli w Javie 8 - 1Ale dlaczego powinniśmy zaakceptować te zmiany? Po co tracić czas na dogadywanie się ze stylem funkcjonalnym, skoro możemy rozwiązać problem za pomocą czystego OOP?
  • Styl funkcjonalny wprowadzony w Javie 8 pomaga nam zmniejszyć rozbieżność pomiędzy logiką biznesową a kodem. Dzięki temu możemy opowiedzieć historię w naturalnym toku, na wyższym poziomie. Zamiast mówić, jak chcesz to zrobić, możesz powiedzieć, co chcesz zrobić.

  • Kod staje się czystszy i bardziej zwięzły.

  • Funkcje wyższego rzędu pozwalają nam na:

    • Wyślij funkcje do innych funkcji
    • Twórz funkcje wewnątrz innych funkcji
    • Zwraca funkcje z innych funkcji

    To wielka wygrana dla Java, gdzie musimy w tym celu wysyłać, tworzyć i zwracać obiekty. Będziemy mogli pisać kod, który będzie bardziej niezawodny, skoncentrowany i łatwiejszy w ponownym użyciu.

  • Dzięki lambdom możemy wykonywać leniwe obliczenia. Gdy wyrażenie lambda zostanie wysłane jako argument metody, kompilator oceni je, gdy zostanie wywołane w metodzie. Różni się to od zwykłych argumentów metod, które są oceniane natychmiast.

  • Lambdy sprawiają, że pisanie testów jednostkowych staje się zabawą. Pozwalają nam tworzyć lekkie testy, które są przejrzyste, mają niewielkie rozmiary i można je szybko napisać. Możemy wykorzenić testowany kod za pomocą lambd. Dzięki temu możemy przetestować, jak różne scenariusze wpłyną na kod.

  • Nowe wzorce do nauczenia.

  • I wiele więcej!

Ale wystarczy wody, w tym artykule przyjrzymy się alternatywnym rozwiązaniom tradycyjnych cykli. Oczywiście cykle są elastyczne, ale nie jest to pozbawione ceny. break, radykalnie zmieniają zachowanie pętli, zmuszając nas do zrozumienia nie tylko tego, co kod próbuje osiągnąć, continueale returntakże zrozumienia, jak działa pętla. Teraz przyjrzymy się, jak możemy przekształcić pętle w bardziej zwięzły i czytelny kod.

Zacznijmy kodowanie!

Będziemy pracować z artykułami. Artykuł ma tytuł, autora i kilka tagów.
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;
    }
}
Każdy przykład będzie zawierał tradycyjne rozwiązanie wykorzystujące pętle oraz rozwiązanie wykorzystujące nowe możliwości Java 8. W pierwszym przykładzie chcemy znaleźć pierwszy artykuł w kolekcji ze znacznikiem „Java”. Przyjrzyjmy się rozwiązaniu wykorzystującemu pętlę.
public Article getFirstJavaArticle() {

    for (Article article : articles) {
        if (article.getTags().contains("Java")) {
            return article;
        }
    }
    return null;
}
Rozwiążmy teraz problem za pomocą operacji z Stream API.
public Optional<Article> getFirstJavaArticle() {
    return articles.stream()
        .filter(article -> article.getTags().contains("Java"))
        .findFirst();
    }
Całkiem fajnie, prawda? Najpierw używamy operacji filter, aby znaleźć wszystkie artykuły ze znacznikiem „Java”, a następnie używamy, findFirst()aby uzyskać pierwsze wystąpienie. Ponieważ strumienie są leniwe i filtr zwraca strumień, w tym podejściu elementy będą przetwarzane tylko do momentu znalezienia pierwszego dopasowania. Teraz oznaczmy wszystkie artykuły tagiem „Java”, a nie tylko pierwszy. Najpierw rozwiązanie za pomocą pętli.
public List<Article> getAllJavaArticles() {

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

    for (Article article : articles) {
        if (article.getTags().contains("Java")) {
            result.add(article);
        }
    }
    return result;
}
Rozwiązanie wykorzystujące operacje na strumieniach.
public List<Article> getAllJavaArticles() {
    return articles.stream()
        .filter(article -> article.getTags().contains("Java"))
        .collect(Collectors.toList());
    }
W tym przykładzie użyliśmy operacji, collectaby skrócić wynikowy strumień, zamiast deklarować kolekcję i jawnie dodawać pasujące wpisy. Jak na razie dobrze. Czas na przykłady, które sprawią, że Stream API naprawdę zabłyśnie. Pogrupujmy wszystkie artykuły według autora. Jak zwykle zaczynamy od rozwiązania problemu za pomocą pętli:
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;
}
Czy możemy znaleźć czyste rozwiązanie tego problemu za pomocą operacji na strumieniu?
public Map<String, List<Article>> groupByAuthor() {
    return articles.stream()
        .collect(Collectors.groupingBy(Article::getAuthor));
}
Niesamowity! Stosując operację groupingByi odwołanie do metody getAuthor()otrzymujemy czysty i czytelny kod. Teraz znajdźmy resztę tagów użytych w kolekcji. Zacznijmy od przykładu pętli:
public Set<String> getDistinctTags() {

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

    for (Article article : articles) {
        result.addAll(article.getTags());
    }
    return result;
}
OK, przyjrzyjmy się, jak możemy rozwiązać ten problem za pomocą operacji na strumieniu:
public Set<String> getDistinctTags() {
    return articles.stream()
        .flatMap(article -> article.getTags().stream())
        .collect(Collectors.toSet());
}
Fajny! flatmappomaga nam spłaszczyć listę tagów w jeden strumień wyników, którego następnie używamy collectdo utworzenia zestawu zwrotnego.

Nieograniczone możliwości

To były 4 przykłady tego, jak pętle można zastąpić bardziej czytelnym kodem. Koniecznie sprawdź Stream API, ponieważ ten artykuł to tylko zarys. Opanowanie nowego funkcjonalnego stylu Java będzie wyzwaniem dla programistów OOP, ale jest to wyzwanie, które powinno zostać dobrze przyjęte. Pójdę nawet dalej i powiem, że powinieneś nauczyć się czysto funkcjonalnego języka programowania. W ten sposób możesz w pełni zrozumieć możliwości i moc, jakie zapewnia. Myślę, że pomoże ci to zrozumieć programowanie funkcjonalne na innym poziomie. Naucz się więc programowania funkcjonalnego wraz ze starym, dobrym OOP i używaj ich obu, aby pisać jeszcze lepszy kod! Darmowa mieszanka tłumaczeń dwóch artykułów - Dlaczego warto zająć się programowaniem funkcjonalnym w Javie 8 i Odejściem od pętli w Javie 8
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION