1. 概述

在 Java 开发中,我们经常需要使用 Map 来存储键值对。但 Java 原生的集合框架(如 HashMap)并不支持直接使用原生类型(primitive types)作为键或值。

为什么不能直接使用原生类型?

因为 Java 集合框架是基于对象的,所以不能直接存储 intdouble 等原生类型。虽然可以通过装箱类(如 IntegerDouble)间接实现,但这会带来性能损耗和内存浪费。

为此,一些第三方高性能集合库提供了对原生类型 Map 的支持,本文将介绍 Eclipse Collections、HPPC、Fastutil 三个主流库的使用方式。


2. Eclipse Collections

Eclipse Collections 是一个高性能的 Java 集合框架,支持原生类型的集合操作,包括各种原生类型的 Map。

2.1. 可变与不可变 Map

Eclipse Collections 提供了工厂类来创建原生类型 Map。例如,创建一个 int -> int 的可变 Map:

MutableIntIntMap mutableIntIntMap = IntIntMaps.mutable.empty();

同样,创建不可变版本只需替换 mutableimmutable

ImmutableIntIntMap immutableIntIntMap = IntIntMaps.immutable.empty();

添加键值对也非常简单:

mutableIntIntMap.addToValue(1, 1);

你也可以创建混合类型的 Map,比如 String -> double

MutableObjectDoubleMap dObject = ObjectDoubleMaps.mutable.empty();
dObject.addToValue("price", 150.5);
dObject.addToValue("quality", 4.4);
dObject.addToValue("stability", 0.8);

2.2. 原生类型 Map 接口树

Eclipse Collections 中的原生集合都继承自 PrimitiveIterable 接口。每个原生类型都有对应的接口,如 IntIterableDoubleIterable 等。

这些接口又衍生出对应的 Map 实现:

  • IntIntMapMutableIntIntMap / ImmutableIntIntMap
  • IntObjectMap<K> → 原生 key + 对象 value
  • ObjectIntMap<K> → 对象 key + 原生 value

这种设计使得你可以灵活选择需要的 Map 类型。


3. HPPC

HPPC 是一个专注于高性能和内存效率的 Java 集合库,适合对性能要求极高的场景。

3.1. 简单使用示例

创建一个 int -> long 的 Map:

IntLongHashMap intLongHashMap = new IntLongHashMap();
intLongHashMap.put(25, 1L);
intLongHashMap.put(150, Long.MAX_VALUE);
intLongHashMap.put(1, 0L);

long value = intLongHashMap.get(150);

HPPC 支持以下组合:

  • 原生 key + 原生 value
  • 原生 key + 对象 value
  • 对象 key + 原生 value
  • 对象 key + 对象 value(支持泛型)

例如:

IntObjectOpenHashMap<BigDecimal> bigDecimalMap = new IntObjectOpenHashMap<>();
ObjectIntOpenHashMap<LocalDate> dateIntMap = new ObjectIntOpenHashMap<>();

3.2. Hash Map 与 Scatter Map

传统 Hash Map 在处理大量数据时可能会遇到哈希冲突,影响性能。HPPC 默认实现已优化此问题。

但如果你的 Map 主要用于查找或计数,且写操作较少,可以使用更轻量的 Scatter Map

  • IntScatterSet
  • IntIntScatterMap
  • IntObjectScatterMap<BigDecimal>

这类 Map 在内存和性能上更高效。


4. Fastutil

Fastutil 是一个高性能、低内存占用的 Java 集合库,特别适合处理大量原生类型数据。

4.1. 快速上手

创建一个 int -> boolean 的 Map:

Int2BooleanMap int2BooleanMap = new Int2BooleanOpenHashMap();
int2BooleanMap.put(1, true);
int2BooleanMap.put(7, false);
int2BooleanMap.put(4, true);

获取值:

boolean value = int2BooleanMap.get(1);

4.2. 原地迭代优化

Java 原生集合在迭代时会频繁创建临时 Iterator 对象,影响性能,尤其是处理大数据集时。

Fastutil 提供了高效的迭代方式:

Int2FloatMap map = new Int2FloatOpenHashMap();
// 添加数据...
for (Int2FloatMap.Entry e : FastUtil.fastIterable(map)) {
    // 这里 e 是复用的,避免了频繁 GC
}

你也可以使用 fastForEach

Int2FloatMaps.fastForEach(map, e -> {
    // e 也在每次迭代中复用
});

当然,标准的 forEach 也支持:

map.forEach((key, value) -> {
    // 使用 key 和 value
});

5. 总结

本文介绍了三种在 Java 中高效使用原生类型 Map 的方式:

特点
Eclipse Collections 功能丰富,接口设计清晰,支持可变/不可变、混合类型 Map
HPPC 高性能,内存效率高,支持 Hash Map 和 Scatter Map
Fastutil 内存占用低,迭代性能好,适合大数据量处理

选择建议:

  • 如果你需要功能全面、易用性强的集合框架 → 选 Eclipse Collections
  • 如果你追求极致性能、内存效率 → 选 HPPC
  • 如果你处理大数据量,注重迭代性能 → 选 Fastutil

📌 踩坑提醒:

  • 不要盲目使用装箱类型(如 Integer)替代原生类型,性能损耗可能超出预期
  • 使用第三方库时注意版本兼容性及依赖管理
  • 原生类型 Map 并非“万能”,根据业务场景选择合适的实现

如需进一步了解各库的详细使用方式,建议查阅其官方文档或示例项目。


原始标题:Map of Primitives in Java | Baeldung