J'ai une entité:
public class Entity
{
private long id;
private String data;
public long getId() {
return id;
}
public String getData() {
return data;
}
}
et une collection d'entités:
Collection<Entity> entities= ...
Quel est le moyen le plus efficace de trouver le Collection<Long>
de tous les identifiants dans entities
?
En supposant que vous avez
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;
}
}
En Java 8, vous pouvez écrire
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);
empreintes
[1, 10, 100]
Comme vous pouvez l’imaginer, cela est plutôt moche dans Java 7 ou moins. Notez que Entity.getId
, lorsqu'il est appliqué à map (), signifie que cette méthode est appelée pour chaque élément.
Maintenant, la partie la plus intéressante est que vous pouvez le faire.
List<Long> ids = entities.parallelStream()
.map(Entity::getId).collect(Collectors.toList());
Dans dans la plupart des cas , utiliser un flux parallèle nuit aux performances, mais rend l’essai et la vision incroyablement faciles (peut-être trop facile;)
Le moyen le plus efficace est d’avoir ou de construire une carte.
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));
Vous n'obtiendrez rien de moins que:
Collection<Long> ids = new ArrayList<>();
for (Entity e : entities) ids.add(e.getId());
Je suppose que tous les moyens iraient sur la collection
Pas nécessairement. Cela crée une collection qui est directement sauvegardée par la collection d'entités sous-jacentes (les modifications futures apportées à la collection d'entités apparaissent dans la collection 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(); }
};
}
};
Je ne sais pas si c'est forcément le plus efficace, mais pour les versions antérieures à Java 8, je me suis habitué à utiliser les interfaces de propriété décrites ci-dessous: http://blog.cgdecker.com/2010/06/property -interfaces-and-guava.html
Comme décrit dans l'article du blog, vous auriez une interface simple nommée quelque chose comme HasId:
public interface HasId {
long getId();
}
Votre classe d'entité ressemblerait à ceci:
public class Entity implements HasId {
private long id;
private String data;
public long getId() {
return id;
}
public String getData() {
return data;
}
}
et vous auriez une fonction simple comme celle-ci quelque part:
public class ToId implements Function<HasId, Long> {
public Long apply(HasId hasId) {
return hasId.getId();
}
}
Enfin, pour en profiter:
Collection<Long> ids = Collections2.transform(entities, new ToId());
C'est excessif si vous n'en avez besoin que pour une seule chose, mais si vous avez une tonne d'objets pouvant implémenter correctement HasId ou d'autres interfaces de ce type, je trouve le travail très agréable.
Le plus efficace? En gros, il suffit de parcourir et d’ajouter à la liste. Vous devez regarder chaque article.
Collection<Long> ids = new LinkedList<Long>();
for (Entity e : entities) {
ids.add(e.id);
}
Ou, si vous pouvez utiliser Java 1.8, vous pouvez faire quelque chose comme:
entities.forEach((e) -> ids.add(e.id));
Au lieu de cela, convertir la liste en flux, puis revenir à la liste
Je recommanderai ci-dessous
Collection ids = new LinkedList (); Entity.forEach ((e) -> ids.add (e.id));