LinkedHashSet 能保持插入顺序是因为底层用 LinkedHashMap 实现,其双向链表按插入顺序链接节点;它不支持 null 元素,非线程安全,时间复杂度 O(1),内存开销略高于 HashSet。
LinkedHashSet 保留插入顺序,但不是线程安全的,也不能存 null(除非你用的是 Java 8+ 的 removeIf 等操作间接触发,但本身仍不支持 null 元素)。

它底层用 LinkedHashMap 实现 —— 每个元素作为 key 存进 LinkedHashMap,value 固定为 PRESENT(一个静态 Object)。而 LinkedHashMap 维护了一个双向链表,节点按插入顺序链接,所以迭代时自然有序。
这和 TreeSet 的“排序”完全不同:TreeSet 是按 compareTo 或 Comparator 排序,LinkedHashSet 只认“谁先来”,不比较大小。
HashSet 一致HashSet 多约 8–16 字节/元素如果你需要“按添加顺序遍历”,比如缓存最近访问项、记录用户操作流水、构建配置项加载顺序,就用 LinkedHashSet;如果你要“自动升序/自定义序”,比如排行榜、区间查询、去重并排序输出,就该用 TreeSet。
常见误用:
LinkedHashSet → 实际只是按 add() 调用顺序,和系统时间无关LinkedHashSet 支持重复元素的“多次插入” → 它仍是 Set,重复 add 不生效,也不会更新位置LinkedHashSet 非线程安全,ConcurrentHashMap + KeySetView 或 Collections.synchronizedSet() 才是替代方案调用 new LinkedHashSet(Collection) 时,会按该集合的 iterator() 顺序逐个 add。这意味着:
ArrayList,顺序就是列表索引顺序HashSet,顺序是不确定的(取决于其内部桶分布和哈希值)LinkedHashSet,顺序会被完整保留null 会抛 NullPointerException;传入含 null 元素的集合(如 Arrays.asList(null))会在 add 时立即抛异常所以别指望靠“用 HashSet 初始化 LinkedHashSet”来“去重并顺便排个序”——它只会把 HashSet 那套不可预测的迭代顺序固化下来。
最易被忽略的一点:它的序列化行为和 HashSet 不同,会把链表结构也写进去,反序列化后顺序严格还原;但如果你用 writeObject + 自定义序列化逻辑绕过默认机制,就可能破坏这个保证。