【问题标题】:Best practice for java stream().filter()java stream().filter() 的最佳实践
【发布时间】:2019-12-08 04:56:10
【问题描述】:

我正在开发一个 java spring 应用程序,想过滤并获取 mongodb 数据库中的特定项目,但我的代码非常混乱,想知道在使用流过滤器时如何改进我的代码

public String getPrimaryTechnology(String id){
    Article article = articleRepository.findById(id).get();

    List<AWS_entity> aws_entitiesList =  article.getAws().getEntities();

    Predicate<AWS_entity> priority1 = aws -> article.getTitle().contains(aws.getName()) 
            && aws.getCategory().equals("TITLE");

    Predicate<AWS_entity> priority2 = aws -> article.getTitle().contains(aws.getName()) 
            && aws.getCategory().equals("COMMERCIAL_ITEM"));

    Predicate<AWS_entity> priority3 = aws -> article.getTitle().contains(aws.getName())
            && (aws.getCategory().equals("ORGANIZATION") || aws.getCategory().equals("OTHER"));


    Optional<AWS_entity> aws_entity = Optional.ofNullable(aws_entitiesList
            .stream()
            .sorted(Comparator.comparing(AWS_entity::getCount).reversed())
            .filter(priority1)
            .findFirst()
            .orElse(aws_entitiesList.stream()
                    .filter(priority2)
                    .findFirst()
                    .orElse(aws_entitiesList.stream()
                            .filter(priority3)
                            .findFirst().orElse(null)
                    )
            ))
    ;

    if(!aws_entity.isPresent())
        return "none identified";
    else return aws_entity.get().getName();
}

【问题讨论】:

  • 你的 Java 版本是多少?
  • @ernest_k 我有 java openjdk11
  • @Mhanxsolo 如果您想提高速度,我建议从答案中改进流解决方案。代替 sort->filter->findfirst 使用 filter->max(或 min),而不是 filter->findfirst 使用 findAny。
  • 循环并没有那么快,除了它们操作的是原始类型的数组,而不是对象。您可以找到一些循环与流的比较。
  • 请注意:当您使用.orElse 时,它的参数将总是被评估,无论它是否实际需要。考虑到您正在经历(可能)大型收藏,这可能非常昂贵(阅读:慢)。在这种情况下使用.orElseGet:只有在需要时才会执行昂贵的操作。 .orElse 应保留用于返回常量的情况(即Collection.emptyList""0)。

标签: java filter java-stream


【解决方案1】:

两种可能的简化方法(您已经为使代码更具可读性做了很多工作)

首先,您可以使用高阶函数来计算谓词。这样,您不需要声明三个。
其次,你可以使用与Optional.or相同的链。

这是它的样子:

Article article = articleRepository.findById(id).get();
List<AWS_entity> aws_entitiesList = article.getAws().getEntities();

//a function that returns your predicates
Function<List<String>, Predicate<AWS_entity>> predictateFunction = 
        list -> aws -> article.getTitle().contains(aws.getName())
                        && list.stream()
                        .anyMatch(category -> aws.getCategory.equals(category));

return aws_entitiesList.stream()
        .filter(predictateFunction.apply(Arrays.asList("TITLE")))
        .max(Comparator.comparing(AWS_entity::getCount))
        .or(() -> aws_entitiesList.stream()
                    .filter(predictateFunction.apply(
                             Arrays.asList("COMMERCIAL_ITEM")))
                    .findFirst()
        )
        .or(() -> aws_entitiesList.stream()
                    .filter(predictateFunction.apply(
                             Arrays.asList("ORGANIZATION", "OTHER")))
                    .findFirst()
        )
        .map(entity -> entity.getName())
        .orElse("none identified");

【讨论】:

  • 您可以使用 filter->max(或 min,取决于)代替 sort->filter->findfirst 和 findAny 代替 filter->findfirst。
  • @gurioso 谢谢 - 这会比说 filter -> sort -> findFirst 更好吗?
  • 排序肯定比选择最大/最小更昂贵。流媒体可以优化一点,但不是那样,我猜。我会做一个实验。可能是猜测 filter->findfirst 的优化。
  • 可以将Function 简化为映射到字符串输入为Function&lt;String, Predicate&lt;AWS_entity&gt;&gt; predicateFunction = str -&gt; aws -&gt; article.getTitle().contains(aws.getName()) &amp;&amp; aws.getCategory().equals(str);,进一步anyMatch 可以替换为Predicate.or,例如predicateFunction.apply("ORGANIZATION").or(predicateFunction.apply("OTHER"))
  • @ernest_k:根据实体的实际结构,这可能会导致不同的结果。如果找不到实体或实体名称为null,则此答案的版本将返回"none identified"。问题中的原始版本仅针对缺少的实体返回 "none identified"。如果找到了实体,但没有名称,则返回 null
【解决方案2】:

要添加另一种方法,可以使用Function&lt;String, Stream&lt;AWS_entity&gt;&gt;,例如:

Function<String, Stream<AWS_entity>> priorityStream = str ->
        aws_entitiesList.stream()
                .filter(aws -> article.getTitle().contains(aws.getName())
                        && aws.getCategory().equals(str));

然后把它当作

Stream<AWS_entity> firstPref = priorityStream.apply("TITLE")
        .sorted(Comparator.comparing(AWS_entity::getCount).reversed());
Stream<AWS_entity> secondPref = priorityStream.apply("COMMERCIAL_ITEM");
Stream<AWS_entity> thirdPref = Stream.concat(priorityStream.apply("ORGANIZATION"),
        priorityStream.apply("OTHER"));

return firstPref.findFirst()
        .or(secondPref::findFirst)
        .or(thirdPref::findFirst)
        .map(AWS_entity::getName)
        .orElse("none identified"); 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-03-22
    • 2010-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-24
    • 2012-09-20
    • 2011-04-07
    相关资源
    最近更新 更多