Наиболее эффективный способ поиска коллекции всех идентификаторов в коллекции объектов
У меня есть сущность:
public class Entity
{
private long id;
private String data;
public long getId() {
return id;
}
public String getData() {
return data;
}
}
и набор объектов:
Collection<Entity> entities= ...
Каков наиболее эффективный способ найти Collection<Long>
всех идентификаторов в entities
?
Ответы
Ответ 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));
Ответ 2
Вы не получите ничего короче, чем:
Collection<Long> ids = new ArrayList<>();
for (Entity e : entities) ids.add(e.getId());
Я предполагаю, что все пути будут перебирать по коллекции
Не обязательно. Это создает коллекцию, которая напрямую поддерживается базой объектов (будущие изменения в коллекции объектов отображаются в коллекции идентификаторов):
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(); }
};
}
};
Ответ 3
Самый эффективный? В основном просто перебирайте и добавляйте в список. Вы должны посмотреть на каждый предмет.
Collection<Long> ids = new LinkedList<Long>();
for (Entity e : entities) {
ids.add(e.id);
}
Или, если вы можете использовать Java 1.8, вы можете сделать что-то вроде:
entities.forEach((e) -> ids.add(e.id));
Ответ 4
Я не знаю, является ли это наиболее эффективным, но для pre-Java 8 я стал использовать интерфейсы свойств, как описано здесь: http://blog.cgdecker.com/2010/06/property-interfaces-and-guava.html
Как описано в сообщении в блоге, у вас будет простой интерфейс с именем HasId:
public interface HasId {
long getId();
}
Класс Entity будет выглядеть следующим образом:
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
Вместо преобразования списка в поток, а затем обратно в список
Я буду рекомендовать ниже
Идентификаторы коллекции = new LinkedList(); entity.forEach((e) → ids.add(e.id));