JavaRush /Java 博客 /Random-ZH /摆脱 Java 8 中的循环
KapChook
第 19 级
Volga

摆脱 Java 8 中的循环

已在 Random-ZH 群组中发布
Java 8 中引入的函数式风格是对该语言的一个重要补充。现在Java不再是纯粹的OOP,而是OOP和函数式编程的混合体。这是一个游戏规则的改变者,我们需要改变我们的 OOP 大脑来吸收这些变化。 消除 Java 8 中的循环 - 1但我们为什么要接受这些改变呢?当我们可以使用纯 OOP 解决问题时,为什么还要浪费时间去尝试函数式风格呢?
  • Java 8中引入的函数式风格帮助我们缩小了业务逻辑和代码之间的差距。它使我们能够在更高层次上以自然流畅的方式讲述故事。你可以说你想做什么,而不是说你想怎么做。

  • 代码变得更干净、更简洁。

  • 高阶函数使我们能够:

    • 将函数发送给其他函数
    • 在其他函数中创建函数
    • 从其他函数返回函数

    这对于 Java 来说是一个巨大的胜利,我们需要发送、创建和返回对象来执行此操作。我们将能够编写更可靠、更有针对性、更易于重用的代码。

  • 感谢 lambda,我们可以进行惰性计算。当 lambda 表达式作为方法参数发送时,编译器将在方法中调用它时对其进行计算。这与立即评估的普通方法参数不同。

  • Lambda 使编写单元测试变得有趣。它们使我们能够创建干净、体积小且编写速度快的轻量级测试。我们可以使用 lambda 来根除被测代码。这使我们能够测试各种场景将如何影响代码。

  • 学习新模式。

  • 以及更多!

但是水足够了,在本文中我们将看看传统循环的替代解决方案。当然,周期是灵活的,但这并不是没有代价的。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 个示例。请务必查看 Stream API,因为本文只触及了表面。掌握 Java 新的函数式风格对于 OOP 开发人员来说将是一个挑战,但这是一个应该受到广泛欢迎的挑战。我什至会更进一步说,你应该学习一门纯函数式编程语言。这样您就可以充分了解它提供的功能和力量。我认为这将帮助您在不同层面上理解函数式编程。因此,学习函数式编程和古老的 OOP,并使用它们来编写更出色的代码!两篇文章的免费翻译组合 -为什么你应该拥抱 Java 8 中的函数式编程远离 Java 8 中的循环
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION