LinkedHashSet是JDK 1.4中引入的新的集合类(LinkedHashMap也是同期引入)。 LinkedHashSet,顾名思义,就是在Hash的实现上添加了Linked的支持。对于LinkedHashSet,在每个节点上通过一个链表串联起来,这样,就可以保证确定的顺序。对于希望有常量复杂度的高效存取性能要求、同时又要求排序的情况下,可以直接使用LinkedHashSet。
它实现了Set接口。存入Set的每个元素必须是唯一的,因为Set不保存重复元素。但是Set接口不保证维护元素的次序(那里面的元素每次顺序如何确定?TODO)。Set与Collection有完全一样的接口Iterable,同时Set继承了Collection。
LinkedHashSet具有HashSet的查询速度,且内部使用链表维护元素的顺序(插入的顺序),于是在使用迭代器便利Set时,结果会按元素插入的次序显示。
需求如: 含多个(有重复)元素ArrayList,去除重复。
1, 可以使用如下略显冗余的代码:
1 public static List removeDuplicateWithOrder(List list) {
2 Set set = new HashSet();
3 List newList = new ArrayList();
4 for (Iterator iter = list.iterator(); iter.hasNext();) {
5 Object element = iter.next();
6 if (set.add(element))
7 newList.add(element);
8 }
9 return newList;
10 }
此方法有滥用set之嫌。
2, 我们也可以使用本文章中提及的LinkedHashSet:
return new ArrayList<T>(new LinkedHashSet<T>(list));
此方法,既利用set去除了重复,又使用linked保持住了原顺序。
3, 貌似apache commons lang中有专门去重复的集合工具。
这儿的链表操作是常量级的,这也是LinkedHashSet/LinkedHashMap比TreeSet/TreeMap性能更高的原因。当然,LinkedHashSet不是thread-safe的,在多线程环境下,需要进行同步包装:
Collections.synchronizedCollection(Collection);
or:
Collections.synchronizedSet(Set);
在使用LinkedHashSet的iterator()方法遍历元素时,如果其他线程有读取操作,也要进行同步,否则,就会抛出同其它fail-fast一样的由于删除或增加操作而引起的CurrentModificationException。
如上两种方法的效率比较,设为TODO,
1, 利用set.add(element)方法,本质是利用其contains()方法判断,而contains()的本质就是遍历。
JDK doc中写道:
More formally, adds the specified element e to this set if the set contains no element e2 such that (e==null ? e2==null : e.equals(e2)). If this set already contains the element, the call leaves the set unchanged and returns false. In combination with the restriction on constructors, this ensures that sets never contain duplicate elements.
2, 测试数据,可以使用数据量:1W,5W,10W,100W。