【问题标题】:Is there way of optimizing below code further using java8?有没有办法使用java8进一步优化下面的代码?
【发布时间】:2019-02-06 01:11:49
【问题描述】:

我在项目中遇到了以下代码。我想知道它是否可以通过使用 java 8 流或一般的集合 API 来进一步优化。

private Set<Student> getFilteredSet() {
    Set<Student> unfilteredSet = getAllStudents();
    Set<Student> adminAreaSet = getAdminStudents();

    Set<String> adminAreaID = new HashSet<>();
    Set<Student> filteredSet = new HashSet<>();

    for (final Student student : adminAreaSet) {
        adminAreaID.add(student.getId());
    }
    for (final Student student : unfilteredSet) {
        if (adminAreaID.contains(student.getId())) {
            filteredSet.add(student);
        }
    }   
    return filteredSet;
}

注意:unfilteredSetadminAreaSet持有不同的子类型Student

【问题讨论】:

  • 以什么方式优化?
  • 有几个经常相互冲突的目标需要优化。例如:速度、内存消耗、代码长度、可读性、重用性……
  • 速度优化
  • 流式传输几乎总是比常规 for 循环慢。

标签: java optimization collections java-8 java-stream


【解决方案1】:

由于问题被标记为,因此提高代码可读性的一种方法是将其转换为:

Set<String> adminAreaID = getAdminStudents().stream()
        .map(Student::getId)
        .collect(Collectors.toSet());

return getAllStudents().stream()
        .filter(student -> adminAreaID.contains(student.getId()))
        .collect(Collectors.toSet());

【讨论】:

  • @shmosel 可能不在该方法的范围/上下文中(因为我们已经实现了目标)。只是想指出 Collectors.toSet() 返回的 Set 类型不能保证。但我同意,这里不需要。
  • 是的。今天它返回HashSet::new。但不能保证它会在未来继续这样做......对吧?
  • @shmosel 是的。我同意你所说的。如果是这样,那么没有人会使用它并通过传递我们期望的类型来使用它(toCollection)。
  • @user7 请注意,即使HashSetcontains 并不总是提供O(1)。如果 Collectors.toSet 曾经返回不同的东西,那么一定有一个原因,这可能是您的应用程序使用不同的 Set 实现的原因。
  • @user7 是的,你可以假设他们不会让事情变得更糟,但是,可能会有不同的考虑。如果您的代码在内存非常低的环境中运行,并且特定 JRE 提供的映射比O(1) 查找更差,但需要的内存显着减少,该怎么办?这就是我所说的“有原因”的意思,你不会从抵消它中受益。所以如果你不需要保证,比如可变性,不要坚持要HashMap
【解决方案2】:

根据您的评论,您正在寻找速度优化。在整个互联网上有很多比较 Stream 和 Collection 的帖子,甚至更多。 我建议您通过示例查看此问题,该问题比较了每个循环的 Streams 和 old 之间的速度性能: Java 8: performance of Streams vs Collections。 由于使用 Stream 会创建大量中间对象并调用中间方法,因此每个循环都比 basic 慢似乎是正常的。 但是,您可以使用流来获得更易读/更小的代码。

为了回答这个问题,我认为考虑到速度性能,您的代码已经非常出色了。我所看到的是您应该初始化 adminAreaID 因为您确切知道它将具有的大小:

    Set<String> adminAreaID = new HashSet<>(adminAreaSet.size(), 1.);

通过设置大小和负载因子,您可以确保没有时间用于扩展您的集合。 根据https://docs.oracle.com/javase/7/docs/api/java/util/HashMap.html

负载因子是哈希表允许满的程度的度量。 在其容量自动增加之前获取。

您必须将其设置为 1。因为您不会获得更高的 adminAreaSet 大小。此外,如果您将其设置为 0.75(默认值),当循环达到其容量的 75% 时,您的 Set 将增长一次,这是无用的。

如果您没有内存问题,您应该对 filtersSet 做同样的事情:

    Set<Student> filteredSet = new HashSet<>(unfilteredSet.size(), 1.);

事实上,当您过滤 unfilteredSet 时,您不会达到最大容量,但它会确保您过滤后的Set 在填充期间不会长大。

【讨论】:

    猜你喜欢
    • 2023-02-21
    • 2018-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-03
    • 1970-01-01
    • 2021-10-27
    • 1970-01-01
    相关资源
    最近更新 更多