这是我的工作。我有一个要转换为map的对象列表,其中key作为对象id,value作为对象。我在列表中有数千个对象,这会导致性能问题。有没有简单的方法可以不使用循环或使用其他数据集?
final List<Object> objects = new ArrayList<Object>();
final Map<Id, Object> objectMap = new HashMap<Id, Object>();
for (final Object object : objects)
{
objectMap.put(object.getId(), object);
}
答案 0 :(得分:4)
您可以尝试使用正确的容量和加载因子优化HashMap
:
HashMap的一个实例有两个影响其性能的参数:初始容量和负载因子。容量是哈希表中的桶数,初始容量只是创建哈希表时的容量。加载因子是在自动增加容量之前允许哈希表获取的完整程度的度量。当哈希表中的条目数超过加载因子和当前容量的乘积时,哈希表将被重新哈希(即,重建内部数据结构),以便哈希表具有大约两倍的桶数。 / p>
容量的最佳值为n / lf
,因此添加元素不会触发重新散列,其中n
是最大元素数,lf
是负载因子。默认加载因子为0.75,但您可以在构造函数中设置它以满足您的需要。
在设置初始容量时,应考虑地图中预期的条目数及其加载因子,以便最大限度地减少重新扫描操作的次数。如果初始容量大于最大条目数除以负载因子,则不会发生任何重新连接操作。
默认值会使您的地图多次使用放置操作重新分割元素,这会影响性能
循环是强制性的,由您或收集者制作。
答案 1 :(得分:1)
您可以尝试在列表中调用并行流:
objects.parallelStream().collect(Collectors.toMap(object -> object.getId(), object -> object));
中查看更多Java 8并行功能
答案 2 :(得分:1)
使用java 8的Stream不会让你对列表进行迭代,但可能比重复的put更加优化:
final List<Object> objects = new ArrayList<Object>();
final Map<Id, Object> objectMap = objects.stream().collect(Collectors.toMap(e -> e.getId(), e -> e));
答案 3 :(得分:1)
尝试使用流将List转换为Map。但无论如何使用内部循环。
Map<Id, Object> objectMap = objects.stream().collect(
Collectors.toMap(Object ::getId, Object));
答案 4 :(得分:1)
我运行了一个带有一百万个对象的jmh基准来比较什么是最好的。
forloop:26.191±0.567 ms / op
java8 Parallel:42.693±1.784 ms / op
Guava.uniqueIndex:38.097±3.521 ms / op
似乎for循环是最快的!
以下是基准测试:( MyObject扩展了Object并具有ID整数字段)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Fork(5)
@State(Scope.Benchmark)
public class ZipIteratorBenchmark {
static ArrayList<MyObject> objects;
@Setup(Level.Trial)
public void setup() {
objects = new ArrayList<>();
for (int i = 0; i < 1000000; i++) {
objects.add(new MyObject(i));
}
}
@Benchmark
public static Map<Integer, MyObject> forloop() {
final Map<Integer, MyObject> objectMap = new HashMap<>();
for (final MyObject object : objects) {
objectMap.put(object.getId(), object);
}
return objectMap;
}
@Benchmark
public static Map<Integer, MyObject> toMap() {
return FluentIterable.from(objects).uniqueIndex(MyObject::getId);
}
@Benchmark
public static Map<Integer, MyObject> java8Parallel() {
return objects.parallelStream().collect(Collectors.toConcurrentMap(MyObject::getId, object -> object));
}
}