常用集合对比及使用
1、常用集合
1.1、ArrayList 和 LinkedList
List 的两个重要的实现类 : ArrayList 和 LinkedList 。
1.1.1、关于 ArrayList
ArrayList ,擅长随机访问元素,但在 List 中间插入和删除元素时速度较慢。
1.1.2、关于 LinkedList
LinkedList ,它通过较低的代价在 List 中间进行的插入和删除操作,提供了优化的顺序访问。
LinkedList 对于随机访问来说相对较慢,但它具有比 ArrayList 更大的特征集。
LinkedList是一个双链表,在添加和删除元素时具有比ArrayList更好的性能。但在get与set方面弱于ArrayList.当然,这些对比都是指数据量很大或者操作很频繁。
什么时候使用 ArrayList 和 LinkedList ?
在ArrayList 的前面或中间插入数据时,必须将其后的所有数据进行相应的后移,这样必然花费较多时间,所以当在一列数据的后面添加数据而不是在前面或中间,并且需要随机地访问其中的元素时,ArrayList 能提供比较好的性能;
当访问链表中的某个元素时,就必须从链表的一端开始沿着连接方向一个一个元素地去查找,直到找到所需的元素为止,所以在一列数据的前面或中间添加或删除数据,并且按照顺序访问其中的元素时,就应该使用LinkedList 了。
1.2、HashSet、LinkedHashSet 和 TreeSet
Set 不保存重复的元素。 如果试图将相同对象的多个实例添加到 Set 中, 那么它会阻止这种重复行为,add方法返回false。
在使用Set判断两个对象相同时,不是使用 == 运算符,而是根据equals方法。只要两个对象用equals方法比较返回true,Set就不会接受这两个对象。
1.2.1、关于 HashSet
存储方式为散列函数,不是同步的。
不能保证元素的排列顺序,顺序有可能发生变化。
集合元素可以是null,但只能放入一个null。
1.2.2、关于 LinkedHashSet
存储方式也使用了散列,根据元素的hashCode值来决定元素的存储位置,但是它同时使用链表维护元素的次序。
当遍历该LinkedHashSet 集合时候,LinkedHashSet将会以元素的添加顺序访问集合的元素。
LinkedHashSet在迭代访问Set中的全部元素时,性能比HashSet好,但是插入时性能稍微逊色于HashSet。
1.2.3、关于 TreeSet
存储方式将元素存储在红-黑树数据结构中。
TreeSet判断两个对象不相等的方式是两个对象通过equals方法返回false,或者通过CompareTo方法比较没有返回 0 .
TreeSet可以确保集合元素处于排序状态。且支持两种排序方式,自然排序和定制排序。
自然排序是根据集合元素的大小,以升序排列,如果要定制排序,应该使用Comparator接口,实现 int compare(T o1,T o2)方法。
1.2.4、代码示例
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.TreeSet;
public class TestSet {
public static void main(String[] args) {
Set<String> hashSet = new HashSet<>();
for(int i = 0; i < 100; i++) {
hashSet.add("Yellow");
hashSet.add("Blue");
hashSet.add("Red");
hashSet.add("Red");
hashSet.add("Orange");
hashSet.add("Yellow");
hashSet.add("Blue");
hashSet.add("Purple");
}
System.out.println("hashSet : " + hashSet);
Set<String> treeSet = new TreeSet<>();
for(int t = 0; t < 100; t++) {
treeSet.add("Yellow");
treeSet.add("Blue");
treeSet.add("Red");
treeSet.add("Red");
treeSet.add("Orange");
treeSet.add("Yellow");
treeSet.add("Blue");
treeSet.add("Purple");
}
System.out.println("treeSet : " + treeSet);
Set<String> linkedHashSet = new LinkedHashSet<>();
for(int t = 0; t < 100; t++) {
linkedHashSet.add("Yellow");
linkedHashSet.add("Blue");
linkedHashSet.add("Red");
linkedHashSet.add("Red");
linkedHashSet.add("Orange");
linkedHashSet.add("Yellow");
linkedHashSet.add("Blue");
linkedHashSet.add("Purple");
}
System.out.println("linkedHashSet : " + linkedHashSet);
}
}
运行结果:
hashSet : [Red, Yellow, Blue, Purple, Orange]
treeSet : [Blue, Orange, Purple, Red, Yellow]
linkedHashSet : [Yellow, Blue, Red, Orange, Purple]
Process finished with exit code 0
1.3、HashMap、LinkedHashMap 和 TreeMap
1.3.1、关于 HashMap
HashMap 中 key 的值没有顺序,常用来做统计。
HashMap 的方法不是同步的,支持 key 和 value 为 null 的情况。
扩展 HashTable :
- HashTable 是 java 早期提供的,方法是同步的(加了synchronized),key和value都不能是null值。
- 由于 HashTable 是同步的,性能开销比较大,一般不推荐使用 HashTable。通常会选择使用HashMap。
代码示例:
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class TestMap {
public static void main(String[] args) {
Map<String, String> hashMap = new HashMap<>();
hashMap.put("key_a", "value1");
hashMap.put("key_b", "value2");
hashMap.put("key_c", "value3");
hashMap.put("key_d", "value4");
Set<Map.Entry<String, String>> set = hashMap.entrySet();
Iterator<Map.Entry<String, String>> iterator = set.iterator();
while(iterator.hasNext()) {
Map.Entry entry = iterator.next();
String key = (String) entry.getKey();
String value = (String) entry.getValue();
System.out.println("key:" + key + ",value:" + value);
}
}
}
打印结果:输出结果并不是按照顺序的。
1.3.2、关于 LinkedHashMap
LinkedHashMap 继承于HashMap,拥有 HashMap 的所有特性,是基于HashMap和双向链表来实现的。
LinkedHashMap key 和 value 都允许空。Key值重复会覆盖,Value 允许重复。
LinkedHashMap 有序(可分为插入顺序和访问顺序两种),但非线程安全。
需要考虑到元素插入的顺序的场景, 选择使用LinkedHashMap。
插入顺序代码示例:
import java.util.*;
public class TestMap {
public static void main(String[] args) {
// LinkedHashMap默认的构造参数是默认插入顺序的,
// 就是你插入的是什么顺序,读出来的就是什么顺序。
Map<String, String> linkedHashMap = new LinkedHashMap<>();
linkedHashMap.put("key_a", "value1");
linkedHashMap.put("key_b", "value2");
linkedHashMap.put("key_c", "value3");
linkedHashMap.put("key_d", "value4");
Set<Map.Entry<String, String>> set = linkedHashMap.entrySet();
Iterator<Map.Entry<String, String>> iterator = set.iterator();
while(iterator.hasNext()) {
Map.Entry entry = iterator.next();
String key = (String) entry.getKey();
String value = (String) entry.getValue();
System.out.println("key:" + key + ",value:" + value);
}
}
}
打印结果:
访问顺序代码示例:
import java.util.*;
public class TestMap {
public static void main(String[] args) {
// 第三个参数用于指定accessOrder值,accessOrder默认为 false,表示不是访问顺序而是插入顺序存储的。
Map<String, String> linkedHashMap = new LinkedHashMap<>(16, 0.75f, true);
linkedHashMap.put("key_a", "value1");
linkedHashMap.put("key_b", "value2");
linkedHashMap.put("key_c", "value3");
linkedHashMap.put("key_d", "value4");
System.out.println("开始时顺序 >>>> ");
Set<Map.Entry<String, String>> set = linkedHashMap.entrySet();
Iterator<Map.Entry<String, String>> iterator = set.iterator();
while(iterator.hasNext()) {
Map.Entry entry = iterator.next();
String key = (String) entry.getKey();
String value = (String) entry.getValue();
System.out.println("key:" + key + ",value:" + value);
}
System.out.println();
System.out.println("## 通过get方法,导致key为 key_c 对应的 Entry 到表尾 >>>>>");
linkedHashMap.get("key_c");
Set<Map.Entry<String, String>> set2 = linkedHashMap.entrySet();
Iterator<Map.Entry<String, String>> iterator2 = set2.iterator();
while(iterator2.hasNext()) {
Map.Entry entry = iterator2.next();
String key = (String) entry.getKey();
String value = (String) entry.getValue();
System.out.println("key:" + key + ",value:" + value);
}
}
}
打印结果:
1.3.3、关于 TreeMap
TreeMap是基于红黑树的一种提供顺序访问的Map,和HashMap不同,它的get或put操作的时间复杂度是O(log(n))。
具体的顺序由指定的Comparator来决定,或者根据键key的具体顺序来决定。
TreeMap的顺序是Key的自然顺序(如整数从小到大),也可以指定比较函数。但不是插入的顺序。
默认排序代码示例:
import java.util.*;
public class TestMap {
public static void main(String[] args) {
Map<String, String> treeMap = new TreeMap<>();
treeMap.put("key_a", "value1");
treeMap.put("key_b", "value2");
treeMap.put("key_e", "value5");
treeMap.put("key_d", "value4");
treeMap.put("key_c", "value3");
Set<Map.Entry<String, String>> set = treeMap.entrySet();
Iterator<Map.Entry<String, String>> iterator = set.iterator();
while(iterator.hasNext()) {
Map.Entry entry = iterator.next();
String key = (String) entry.getKey();
String value = (String) entry.getValue();
System.out.println("key:" + key + ",value:" + value);
}
}
}
打印结果:
1.4、扩展 Iterators 迭代器
由于创建迭代器的代价小,故迭代器通常被称为轻量级对象。Java 的 Iterator 只能单向移动。
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class TestIterators {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("first");
list.add("second");
list.add("third");
// 使用 iterator() 方法要求集合返回一个 Iterator。
Iterator iterator = list.iterator();
// 使⽤ hasNext() ⽅法检查序列中是否还有元素。
while (iterator.hasNext()) {
// 使⽤ next() ⽅法获得序列中的下⼀个元素。
System.out.println(iterator.next());
}
// 可以使用 remove() ⽅法将迭代器最近返回的那个元素删除。
}
}
打印结果:
1.5、集合框架简图
.