[英]Java 8: Simplify and convert code to stream API
Code structure代码结构
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;
}
There is a method to transform and return specific result有一种方法可以转换并返回特定结果
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;
}
Need an advice how can I convert that logic to Java 8 stream api ?需要建议如何将该逻辑转换为 Java 8 流 api?
Such questions are more suitable for CodeReview , but ok, I'll answer.这样的问题更适合CodeReview ,不过好吧,我来回答。
First, even in previous Java versions there's no need to create the result
list in the loop.首先,即使在以前的 Java 版本中,也不需要在循环中创建
result
列表。 The result
is actually the same List
as the input articles
list as you don't create new objects, you modify the existing ones.该
result
实际上是相同的List
作为输入articles
列为你不创建新对象,修改现有的。 Thus if you want to copy the original list (for whatever reason), you could write simply:因此,如果您想复制原始列表(无论出于何种原因),您可以简单地编写:
return new ArrayList<>(articles);
But probably you may omit the copying and return simply articles
.但可能你可以省略复制并返回简单的
articles
。 Or even better change the return type to void
.或者甚至更好地将返回类型更改为
void
。 This way it will be more clear that your method actually changes the passed objects instead of creating the new ones.通过这种方式,您的方法实际上会更改传递的对象而不是创建新对象,这将更加清晰。
To search whether the Collection
has element matching the given predicate use Stream.anyMatch()
:要搜索
Collection
是否具有与给定谓词匹配的元素,请使用Stream.anyMatch()
:
String languageCriteria =
article.translations.stream().anyMatch(t -> t.language.equals(language))
? language : "en";
To filter the elements according to the given predicate use Stream.filter()
:要根据给定的谓词过滤元素,请使用
Stream.filter()
:
article.translations = article.translations.stream()
.filter(t -> t.language.equals(languageCriteria))
.collect(Collectors.toList());
Though it's likely that the original article.translations
list is not used anywhere alse, and you can perform the filtering in-place using Collection.removeIf()
instead of creating the Stream
and separate List
:尽管原始
article.translations
列表很可能没有在其他任何地方使用,但您可以使用Collection.removeIf()
执行就地过滤,而不是创建Stream
和单独的List
:
article.translations.removeIf(t -> !t.language.equals(languageCriteria));
So your method might look like this:所以你的方法可能是这样的:
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));
});
}
Further to encapsulate the Article
modifications I would extract the loop body to the method of Article
class:为了进一步封装
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));
}
}
Now your original method may look like this:现在您的原始方法可能如下所示:
void filterArticleTranslations(List<Article> articles, String language) {
articles.forEach(article -> article.filterTranslations(language));
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.