【问题标题】:Most efficient way to find the collection of all ids in a collection of entities在实体集合中查找所有 id 集合的最有效方法
【发布时间】:2014-07-11 20:27:18
【问题描述】:

我有一个实体:

public class Entity
{
    private long id;    
    private String data;

    public long getId() {
        return id;
    }

    public String getData() {
        return data;
    }
}

以及实体的集合:

Collection<Entity> entities= ...

entities 中的所有id 中找到Collection&lt;Long&gt; 的最有效方法是什么?

【问题讨论】:

  • 请澄清一下,“最有效”是指“最快”还是“最短”?
  • @Boann 因为我认为所有方法都会遍历集合......在这种情况下,我的意思是“最短”

标签: java collections guava apache-commons


【解决方案1】:

假设你有

class Entity {
    final long id;
    final String data;

    public long getId() {
        return id;
    }

    public String getData() {
        return data;
    }

    Entity(long id, String data) {
        this.id = id;
        this.data = data;
    }
}

在 Java 8 中你可以编写

Collection<Entity> entities = Arrays.asList(new Entity(1, "one"), 
                  new Entity(11, "eleven"), new Entity(100, "one hundred"));
// get a collection of all the ids.
List<Long> ids = entities.stream()
                         .map(Entity::getId).collect(Collectors.toList());

System.out.println(ids);

打印

[1, 10, 100]

您可以想象,这在 Java 7 或更低版本中相当难看。请注意,Entity.getId 应用于 map() 表示在每个元素上调用此方法。

现在,真正有趣的部分是你可以做到这一点。

List<Long> ids = entities.parallelStream()
                         .map(Entity::getId).collect(Collectors.toList());

大多数情况下使用并行流会损害性能,但它使尝试并看到非常容易(可能太容易;)


最有效的方法是拥有或构建地图。

Map<Long, Entity> entitiesMap = ...
// get all ids
Collection<Long> addIds = entitiesMap.keySet();

// look up entities by id.
List<Long> ids = ...
List<Entity> matching = new ArrayList<>();
for(Long id: ids)
    matching.add(entitiesMap.get(id));

【讨论】:

  • 当然可以,但是在GuavaApache Commons 中是否有可以为我执行此操作的实用程序?
  • @rapt 没有闭包,使用库比编写一个简单的循环需要更多的代码。你会用 Java 8 吗?
  • 在这种情况下,忘记 Guava 和 Apache Commons,只使用流,这会容易得多。您是否有用于 Id 的吸气剂,因为这会有所帮助。
  • @rapt 在 Java 7 中,您将使用循环。只是由于 Java 8 的语法糖,它才有意义。注意:循环仍然是更短的代码。
  • 等价于 .map(e -> e.getId()).collect(..)
【解决方案2】:

最有效?基本上只是迭代并添加到列表中。您必须查看每个项目。

Collection<Long> ids = new LinkedList<Long>();
for (Entity e : entities) {
    ids.add(e.id);
}

或者,如果您可以使用 Java 1.8,您可以执行以下操作:

entities.forEach((e) -> ids.add(e.id));

【讨论】:

  • 最好使用ArrayList 并指定其大小(即entities.size())。
  • entities.forEach((e) -&gt; ids.add(e))ids.addAll(entries) 相同;
  • 对不起,我的意思是 ids.add(e.id)
【解决方案3】:

你不会得到比以下更短的任何东西:

Collection<Long> ids = new ArrayList<>();
for (Entity e : entities) ids.add(e.getId());

我假设所有方法都会遍历集合

不一定。这将创建一个由底层实体集合直接支持的集合(实体集合的未来更改出现在 ids 集合中):

Collection<Long> ids = new AbstractCollection<Long>() {
    @Override
    public int size() {
        return entities.size();
    }

    @Override
    public Iterator<Long> iterator() {
        return new Iterator<Long>() {
            private Iterator<Entity> base = entities.iterator();
            @Override public boolean hasNext() { return base.hasNext(); }
            @Override public Long next() { return base.next().getId(); }
            @Override public void remove() { base.remove(); }
        };
    }
};

【讨论】:

    【解决方案4】:

    我不知道这是否一定是最有效的,但对于 Java 8 之前的版本,我已经开始喜欢使用此处描述的属性接口:http://blog.cgdecker.com/2010/06/property-interfaces-and-guava.html

    如博文中所述,您将拥有一个名为 HasId 之类的简单接口:

    public interface HasId {
        long getId();
    }
    

    你的实体类应该是这样的:

    public class Entity implements HasId {
        private long id;    
        private String data;
    
        public long getId() {
            return id;
        }
    
        public String getData() {
            return data;
        }
    }
    

    你会在某个地方有一个像这样的简单函数:

    public class ToId implements Function<HasId, Long> {
        public Long apply(HasId hasId) {
            return hasId.getId();
        }
    }
    

    最后,利用它:

    Collection<Long> ids = Collections2.transform(entities, new ToId());
    

    如果你只需要它来做一件事,这就太过分了,但是如果你有大量的对象可以很好地实现 HasId 或其他类似的接口,我觉得使用它非常愉快。

    【讨论】:

      【解决方案5】:

      而是将列表转换为流,然后再返回列表

      我会在下面推荐

      集合 ids = new LinkedList(); entity.forEach((e) -> ids.add(e.id));

      【讨论】:

        【解决方案6】:

        我们也可以试试这个方法

        List<Long> ids = new ArrayList<>();
        entities.Stream().map(entity->ids.add(entity.getId()));
        

        【讨论】:

        • 您正在回复一个已被接受的旧问题。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-10-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-12-15
        • 2023-01-18
        相关资源
        最近更新 更多