我们可以使用Java在Map中一次放置多个键和值

时间:2017-03-09 08:16:29

标签: java hashmap guava

这是我的工作。我有一个要转换为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);
}

5 个答案:

答案 0 :(得分:4)

您可以尝试使用正确的容量和加载因子优化HashMap

  

HashMap的一个实例有两个影响其性能的参数:初始容量和负载因子。容量是哈希表中的桶数,初始容量只是创建哈希表时的容量。加载因子是在自动增加容量之前允许哈希表获取的完整程度的度量。当哈希表中的条目数超过加载因子和当前容量的乘积时,哈希表将被重新哈希(即,重建内部数据结构),以便哈希表具有大约两倍的桶数。 / p>

容量的最佳值为n / lf,因此添加元素不会触发重新散列,其中n是最大元素数,lf是负载因子。默认加载因子为0.75,但您可以在构造函数中设置它以满足您的需要。

  

在设置初始容量时,应考虑地图中预期的条目数及其加载因子,以便最大限度地减少重新扫描操作的次数。如果初始容量大于最大条目数除以负载因子,则不会发生任何重新连接操作。

默认值会使您的地图多次使用放置操作重新分割元素,这会影响性能

循环是强制性的,由您或收集者制作。

答案 1 :(得分:1)

您可以尝试在列表中调用并行流:

objects.parallelStream().collect(Collectors.toMap(object -> object.getId(), object -> object));

或者在Parallelism Java tutorial

中查看更多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));
   }
}