【问题标题】:Java 8: Simplify and convert code to stream APIJava 8:简化代码并将其转换为流 API
【发布时间】:2015-11-22 20:03:28
【问题描述】:

代码结构

public class Article {
   public String name;   
   public String description;
   public List<Translation> translations;
}

public class Translation { 
   public String field;
   public String value;
   public String language;
}

有一种方法可以转换并返回特定结果

List<Article> returnArticleswithCorrectTranslation(List<Article> articles, String language) {
    List<Article> result = new ArrayList<>();
    for (Article article: articles) {
        String languageCriteria = language;
        boolean isTranslationFound = false;
        for (Translation translation : article.translations) {
            if (translation.language.equals(language)) {
              isTranslationFound = true;
            }
        }

        if (!isTranslationFound) {
            languageCriteria = "en";
        }
        List<Translation> resultTranslations = new ArrayList<>();
        for (Translation translation : article.translations) {
            if (translation.language.equals(languageCriteria)) {
                resultTranslations.add(translation);
            }
        }
        article.translations = resultTranslations;
        result.add(article);

    }
    return result;
}

需要建议如何将该逻辑转换为 Java 8 流 api?

【问题讨论】:

    标签: java java-8 java-stream


    【解决方案1】:

    这样的问题更适合CodeReview,不过好吧,我来回答。

    首先,即使在以前的 Java 版本中,也无需在循环中创建 result 列表。 result 实际上与 List 与输入 articles 列表相同,因为您不创建新对象,而是修改现有对象。因此,如果您想复制原始列表(无论出于何种原因),您可以简单地编写:

    return new ArrayList<>(articles);
    

    但也许你可以省略复制并简单地返回articles。或者甚至更好地将返回类型更改为void。这样一来,您的方法实际上更改了传递的对象而不是创建新的对象会更加清楚。

    要搜索Collection 是否有与给定谓词匹配的元素,请使用Stream.anyMatch()

    String languageCriteria = 
            article.translations.stream().anyMatch(t -> t.language.equals(language)) 
            ? language : "en";
    

    要根据给定谓词过滤元素,请使用Stream.filter()

    article.translations = article.translations.stream()
            .filter(t -> t.language.equals(languageCriteria))
            .collect(Collectors.toList());
    

    虽然原始article.translations 列表很可能不会在其他任何地方使用,但您可以使用Collection.removeIf() 就地执行过滤,而不是创建Stream 和单独的List

    article.translations.removeIf(t -> !t.language.equals(languageCriteria));
    

    所以你的方法可能如下所示:

    void filterArticleTranslations(List<Article> articles, String language) {
        articles.forEach(article -> {
            String languageCriteria = 
                    article.translations.stream().anyMatch(t -> t.language.equals(language)) 
                    ? language : "en";
    
            article.translations.removeIf(t -> !t.language.equals(languageCriteria));
        });
    }
    

    为了进一步封装Article的修改,我会将循环体提取到Article类的方法中:

    public static class Article {
        String name;
        String description;
        List<Translation> translations;
    
        public void filterTranslations(String language) {
            String languageCriteria = 
                    translations.stream().anyMatch(t -> t.language.equals(language)) 
                    ? language : "en";
    
            translations.removeIf(t -> !t.language.equals(languageCriteria));
        }
    }
    

    现在您的原始方法可能如下所示:

    void filterArticleTranslations(List<Article> articles, String language) {
        articles.forEach(article -> article.filterTranslations(language));
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-08-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-14
      相关资源
      最近更新 更多