JavaRush /Java Blog /Random EN /Getting rid of loops in Java 8
KapChook
Level 19
Volga

Getting rid of loops in Java 8

Published in the Random EN group
The functional style introduced in Java 8 is a great addition to the language. Now Java is not pure OOP, now it is a hybrid of OOP and functional programming. This is a game changer and we need to change our OOP brains to absorb these changes. Getting rid of loops in Java 8 - 1But why should we accept these changes? Why should we waste time trying to get along with a functional style when we can solve the problem using pure OOP?
  • The functional style introduced in Java 8 helps us reduce the gap between business logic and code. It allows us to tell the story in a natural flow at a higher level. Instead of saying how you want to do it, you can say what you want to do.

  • The code becomes cleaner and more concise.

  • High order functions allow us to:

    • Send functions to other functions
    • Create functions inside other functions
    • Return functions from other functions

    This is a big win for Java, where we need to send, create, and return objects to do this. We will be able to write code that is more reliable, focused, and easier to reuse.

  • Thanks to lambdas, we can do lazy calculations. When a lambda expression is sent as a method argument, the compiler will evaluate it when it is called in the method. This is different from normal method arguments, which are evaluated immediately.

  • Lambdas make writing unit tests fun. They allow us to create lightweight tests that are clean, small in size, and quick to write. We can root out the code under test using lambdas. This allows us to test how all kinds of scenarios will affect the code.

  • New patterns to learn.

  • And much more!

But enough water, in this article we will take a look at alternative solutions to traditional cycles. Of course, cycles are flexible, but this does not come without a price. break, dramatically change the behavior of the loop, forcing us to understand not only what the code is trying to achieve, continuebut returnalso to understand how the loop works. Now we'll take a look at how we can transform loops into more concise and readable code.

Let the coding begin!

We will work with articles. An article has a title, author and several tags.
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;
    }
}
Each example will contain a traditional solution using loops and a solution using the new features of Java 8. In the first example, we want to find the first article in the collection with the tag “Java”. Let's take a look at a solution using a loop.
public Article getFirstJavaArticle() {

    for (Article article : articles) {
        if (article.getTags().contains("Java")) {
            return article;
        }
    }
    return null;
}
Now let's solve the problem using operations from the Stream API.
public Optional<Article> getFirstJavaArticle() {
    return articles.stream()
        .filter(article -> article.getTags().contains("Java"))
        .findFirst();
    }
Pretty cool, isn't it? We first use the operation filterto find all articles with the tag “Java”, then we use findFirst()to get the first occurrence. Since streams are lazy and the filter returns a stream, this approach will only process elements until it finds the first match. Now let's get all the articles tagged “Java” instead of just the first one. First the solution using loops.
public List<Article> getAllJavaArticles() {

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

    for (Article article : articles) {
        if (article.getTags().contains("Java")) {
            result.add(article);
        }
    }
    return result;
}
Solution using stream operations.
public List<Article> getAllJavaArticles() {
    return articles.stream()
        .filter(article -> article.getTags().contains("Java"))
        .collect(Collectors.toList());
    }
In this example, we used an operation collectto shorten the resulting stream, rather than declaring a collection and explicitly adding the entries that match. So far so good. Time for examples that will make the Stream API really shine. Let's group all articles by author. As usual, we start by solving it using loops:
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;
}
Can we find a clean solution to this problem using stream operations?
public Map<String, List<Article>> groupByAuthor() {
    return articles.stream()
        .collect(Collectors.groupingBy(Article::getAuthor));
}
Amazing! By using an operation groupingByand a method reference getAuthor(), we get clean and readable code. Now let's find the rest of the tags used in the collection. Let's start with a loop example:
public Set<String> getDistinctTags() {

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

    for (Article article : articles) {
        result.addAll(article.getTags());
    }
    return result;
}
Okay, let's take a look at how we can solve this using stream operations:
public Set<String> getDistinctTags() {
    return articles.stream()
        .flatMap(article -> article.getTags().stream())
        .collect(Collectors.toSet());
}
Cool! flatmaphelps us flatten the list of tags into a single result stream, which we then use collectto create the return set.

Endless Possibilities

These were 4 examples of how loops can be replaced with more readable code. Be sure to check out the Stream API, as this article has only scratched the surface. Mastering the new functional style of Java will be a challenge for OOP developers, but it is a challenge that should be well received. I'll even go further and say that you should learn a pure functional programming language. This way you can fully understand the capabilities and power it provides. I think this will help you understand functional programming on a different level. So learn functional programming along with good old OOP, and use them both to write even greater code! A free mix of translations of two articles - Why you should embrace functional programming in Java 8 and Swerving Away from Loops in Java 8
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION