En Java, un EnumSet almacena los elementos que contiene en un vector de máscara de bits/bits utilizando un long
(RegularEnumSet
) o long[]
(JumboEnumSet
). Ahora he encontrado un caso de uso donde tengo muchos miles de objetos de dominio (llamémoslos Node
), cada uno de los cuales mostrará todos los elementos de una enumeración (llamémoslo Flag
) en un orden que variará por Objeto.tienda una ordenación de las enumeraciones en Java
Actualmente estoy almacenando el pedido como Guava ImmutableSet
, porque eso garantiza conservar el orden de inserción. Sin embargo, he usado the methods explained on this page para comparar el uso de memoria en un EnumSet<Flag>
, un ImmutableSet<Flag>
y un Flag[]
. Estos son los resultados cuando a) la bandera tiene 64 elementos de enumeración y b) las tres variantes contiene los 64 artículos:
EnumSet: 32 bytes
ImmutableSet: 832 bytes
matriz: 272 bytes
Así que mi pregunta es: ¿hay una forma inteligente de empaquetar el orden enum en un valor numérico para obtener una huella de memoria más pequeña que la de la matriz? Si hace una diferencia: en mi caso de uso, supongo que el orden siempre contiene todos los elementos de Enum.
Para aclarar: mi enumeración es mucho más pequeña que eso y no tengo ningún problema de memoria a partir de ahora, ni es probable que esta situación alguna vez me dé problemas de memoria. Es solo que esta ineficiencia me molesta, incluso en este nivel microscópico.
Actualización:
Después de las sugerencias de las diversas respuestas y comentarios que ocurrió con esta estructura de datos que utiliza una matriz de bytes. Advertencia: no implementa la interfaz Set (no verifica valores únicos) y no se escalará a enumeraciones grandes más allá de lo que puede contener un byte. Además, la complejidad es bastante horrible, porque Enum.values () tiene que ser consultado en varias ocasiones (see here for a discussion of this problem), pero aquí va:
public class EnumOrdering<E extends Enum<E>> implements Iterable<E> {
private final Class<E> type;
private final byte[] order;
public EnumOrdering(final Class<E> type, final Collection<E> order) {
this.type = type;
this.order = new byte[order.size()];
int offset = 0;
for (final E item : order) {
this.order[offset++] = (byte) item.ordinal();
}
}
@Override
public Iterator<E> iterator() {
return new AbstractIterator<E>() {
private int offset = -1;
private final E[] enumConstants = type.getEnumConstants();
@Override
protected E computeNext() {
if (offset < order.length - 1) {
return enumConstants[order[++offset]];
}
return endOfData();
}
};
}
}
El consumo de memoria es:
EnumOrdering: 104
¡Es un resultado bastante bueno hasta ahora, gracias a bestsss y JB Nizet!
Actualización: Me han cambiado el código sólo para implementar Iterable, porque cualquier otra cosa sería necesario para implementaciones sensibles iguales/hashCode/etc contiene
array simple de byte [] hará, byte [] contiene el enum.ordinal. si tiene más de 256 elementos, puede usar short []/int []. Alternativamente, puedes empacar los artículos en menos de 8bits. Es posible que tenga que tener especial cuidado con la serialización, de cualquier forma el código será menos de 200 líneas y es bastante trivial. – bestsss
si no necesita el orden de inserción, solo use un solo largo; puede contener hasta 64 elementos enum, como se hace en C. – bestsss
@bestsss si no necesitaba el orden de inserción usaría un EnumSet, que hace exactamente eso –