NetBeans подсказала мне что нужно использовать EnumSet<Enum> вместо HashSet<Enum>...
полез я в исходник EnumSet — судя по описанию и по идее что там описано — да лучше использовать EnumSet.
накрапал я маленький тест ...
public class EnumSetTest extends TestCase {
static final int IT_NUM = 100000000;
public enum LType {
SYV("syv"),
DEC("dec"),
BZZZZZ("bzzzzz"),
ASDF("asdf"),
QWERTY("qwerty"),
A1S2("a1s2"),
ZXCV("zxcv"),
SPU("spu");
String value;
LType(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public static LType fromValue(String v) {
for (LType l : LType.values()) {
if (l.value.equals(v.toLowerCase())) {
return l;
}
}
throw new IllegalArgumentException(v);
}
@Override
public String toString() {
return value;
}
}
public void testHashSet() {
LType[] values = LType.values();
HashSet<LType> types = new HashSet<LType>(values.length);
{
Timer t = new Timer("testHashSet:create");
for(int i = 0; i < IT_NUM; ++i) {
types.add(values[i % values.length]);
}
t.endAndEcho();
}
{
Random rand = new Random();
Timer t = new Timer("testHashSet:access");
long f = 0;
for (int i = 0; i < IT_NUM * IT_NUM; ++i) {
int v = Math.abs(rand.nextInt()) % values.length;
boolean rv = types.contains(values[v]);
if (rv)
++f;
}
System.out.println("found: " + Long.toString(f));
t.endAndEcho();
}
}
public void testEnumSet() {
LType[] values = LType.values();
Set<LType> types = EnumSet.noneOf(LType.class);
{
Timer t = new Timer("testEnumSet:create");
for (int i = 0; i < IT_NUM; ++i) {
types.add(values[i % values.length]);
}
t.endAndEcho();
}
{
Random rand = new Random();
Timer t = new Timer("testEnumSet:access");
long f = 0;
for (int i = 0; i < IT_NUM * IT_NUM; ++i) {
int v = Math.abs(rand.nextInt()) % values.length;
boolean rv = types.contains(values[v]);
if (rv) {
++f;
}
}
System.out.println("found: " + Long.toString(f));
t.endAndEcho();
}
}
}
final Entry<K,V> getEntry(Object key) {
int hash = (key == null) ? 0 : hash(key.hashCode());
for (Entry<K,V> e = table[indexFor(hash, table.length)];
e != null;
e = e.next) {
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
}
return null;
}
а у EnumSet оставлен из — java.util.AbstractCollection<E>
public boolean contains(Object o) {
Iterator<E> e = iterator();
if (o==null) {
while (e.hasNext())
if (e.next()==null)
return true;
} else {
while (e.hasNext())
if (o.equals(e.next()))
return true;
}
return false;
}
Ты на почти 2х миллиардах итераций получил разницу в 9 сек и назвал это "проседает по скорости"? Я бы на твоём месте не парился (а ещё лучше бы поразмышлял, почему вместо 10^16 итераций у тебя всего 2^9, хоть чему-то полезному научишься на этом примере
DV>>
A>Ты на почти 2х миллиардах итераций получил разницу в 9 сек и назвал это "проседает по скорости"? Я бы на твоём месте не парился (а ещё лучше бы поразмышлял, почему вместо 10^16 итераций у тебя всего 2^9, хоть чему-то полезному научишься на этом примере
вы намекаете на то что мое число не влезло в положительную часть signed int? Это банальная опечатка. Я просто добавил ноликов не считая.
Но про 512 итераций вы тоже загнули...
С уважением Denys Valchuk
IMHO чем больше мнений тем оптимальней выбор варианта... :)
Здравствуйте, Denys V., Вы писали:
DV>NetBeans подсказала мне что нужно использовать EnumSet<Enum> вместо HashSet<Enum>... DV>полез я в исходник EnumSet — судя по описанию и по идее что там описано — да лучше использовать EnumSet. DV>накрапал я маленький тест ...
Как обычно и бывает, маленький тест ничего не показывает когда дело доходит то микробенчмарков.
Я переписал твой тест с использованием Google caliper.
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Set;
import org.junit.Test;
import com.google.caliper.Benchmark;
import com.google.caliper.Param;
import com.google.caliper.Runner;
import com.google.caliper.SimpleBenchmark;
import com.google.common.collect.ObjectArrays;
public class SetsBenchmark extends SimpleBenchmark {
static final int IT_NUM = 10000000;
public static enum LType {
SYV("syv"), DEC("dec"), BZZZZZ("bzzzzz"), ASDF("asdf"), QWERTY("qwerty"), A1S2("a1s2"), ZXCV("zxcv"), SPU(
"spu");
String value;
LType(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public static LType fromValue(String v) {
for (LType l : LType.values()) {
if (l.value.equals(v.toLowerCase())) {
return l;
}
}
throw new IllegalArgumentException(v);
}
@Override
public String toString() {
return value;
}
}
@Param({"enumset", "hashset"})
String setType;
public void timeSet(int reps) {
for (int r = 0; r < reps; r++) {
LType[] values = LType.values();
Set<LType> types = createSet(setType, values.length);
for (int i = 0; i < IT_NUM; ++i) {
types.add(values[i % values.length]);
}
long f = 0;
for (int i = 0; i < IT_NUM; ++i) {
int v = i % values.length;
boolean rv = types.contains(values[v]);
if (rv) {
++f;
}
}
}
}
private Set<LType> createSet(String type, int length) {
if (type.equals("enumset")) {
return EnumSet.noneOf(LType.class);
} else {
return new HashSet<>(length);
}
}
@Test
public void benchmarkPut() throws Exception {
runBenchmark(SetsBenchmark.class);
}
private static void runBenchmark(Class<? extends Benchmark> benchmark) {
String[] args = ObjectArrays.concat(new String[] {"--trials", "1"}, benchmark.getName());
new Runner().run(args);
}
}
Нулей только поменьше поставил, а то ждать долго. И рандом убрал, чтобы не путал карты.
Запустил.
Получил следующее
setType ms linear runtime
enumset 217 ==============
hashset 439 ==============================
И того получаем что EnumSet в среднем в два раза быстрее чем HashSet.
А с учетом того что RegularEnumSet использует всего одно поле long для хранения информации, то значит что оно еще и по памяти как минимум в несколько раз выгоднее.
Здравствуйте, Denys V., Вы писали:
DV>Здравствуйте, Nicht, Вы писали:
N>> Google caliper.
DV>Спасибо, за хорошую ссылку? DV>вы какую ревизию собирали? DV>у меня последняя (r354) не собирается...
Я мейвеном пользуюсь. Беру снепшоты из OSS репозитория Sonatype. У них там очень много зеркал всяких репозиториев в одном месте.
DV> Random rand = new Random();
DV> Timer t = new Timer("testHashSet:access");
DV> long f = 0;
DV> for (int i = 0; i < IT_NUM * IT_NUM; ++i) {
DV> int v = Math.abs(rand.nextInt()) % values.length;
DV> boolean rv = types.contains(values[v]);
DV> if (rv)
DV> ++f;
DV> }
DV>
Повезло, что ни в одной из 1874919424 итераций не попалось отрицательное.
Здравствуйте, gegMOPO4.
Вы писали:
MOPO> Здравствуйте, Denys V., Вы писали: MOPO> DV>
MOPO> DV> Random rand = new Random();
MOPO> DV> Timer t = new Timer("testHashSet:access");
MOPO> DV> long f = 0;
MOPO> DV> for (int i = 0; i < IT_NUM * IT_NUM; ++i) {
MOPO> DV> int v = Math.abs(rand.nextInt()) % values.length;
MOPO> DV> boolean rv = types.contains(values[v]);
MOPO> DV> if (rv)
MOPO> DV> ++f;
MOPO> DV> }
MOPO> DV>
MOPO> Повезло, что ни в одной из 1874919424 итераций не попалось отрицательное.
А почему повезло? См. выделенное
Здравствуйте, xBlackCat, Вы писали: BC>Здравствуйте, gegMOPO4. BC>Вы писали: MOPO>> Здравствуйте, Denys V., Вы писали: MOPO>> DV>
MOPO>> DV> Random rand = new Random();
MOPO>> DV> Timer t = new Timer("testHashSet:access");
MOPO>> DV> long f = 0;
MOPO>> DV> for (int i = 0; i < IT_NUM * IT_NUM; ++i) {
MOPO>> DV> int v = Math.abs(rand.nextInt()) % values.length;
MOPO>> DV> boolean rv = types.contains(values[v]);
MOPO>> DV> if (rv)
MOPO>> DV> ++f;
MOPO>> DV> }
MOPO>> DV>
MOPO>> Повезло, что ни в одной из 1874919424 итераций не попалось отрицательное. BC>А почему повезло? См. выделенное
Потому, что нарваться на -2147483648 за 1874919424 попытки не так уж мала — 1-(1-1./(1<<32))**1874919424 = 35%. -Integer.MIN_VALUE == Integer.MIN_VALUE.
И вообще, читайте документацию на то, что используете. В частности, Random.nextInt(int).
Здравствуйте, gegMOPO4.
Вы писали:
MOPO> Здравствуйте, xBlackCat, Вы писали: MOPO> BC>А почему повезло? См. выделенное MOPO> Потому, что нарваться на -2147483648 за 1874919424 попытки не так уж мала — 1-(1-1./(1<<32))**1874919424 = 35%. -Integer.MIN_VALUE == Integer.MIN_VALUE. MOPO> И вообще, читайте документацию на то, что используете. В частности, Random.nextInt(int).
Да. Действительно. Как-то ускользнул этот момент. Лучше было бы использовать