集合進(jìn)階1---為集合指定初始容量
集合在Java編程中使用非常廣泛,當(dāng)容器的量變得非常大的時(shí)候碑诉,它的初始容量就會(huì)顯得很重要了.
因?yàn)閿U(kuò)容是需要消耗大量的人力物力財(cái)力的惭婿。
同樣的道理驾诈,Collection的初始容量也顯得異常重要凤瘦。所以:對(duì)于已知的情景,請(qǐng)為集合指定初始容量拂封。
import java.util.ArrayList;
import java.util.List;
public class ColTest {
public static void main(String[] args) {
Base_User baseUser = null;
long begin1 = System.currentTimeMillis();
List<Base_User> list1 = new ArrayList<Base_User>();
for(int i = 0 ; i < 1000000; i++){
baseUser = new Base_User(i,"chenssy_"+i,i);
list1.add(baseUser);
}
long end1 = System.currentTimeMillis();
System.out.println("list1 time:" + (end1 - begin1));
long begin2 = System.currentTimeMillis();
List<Base_User> list2 = new ArrayList<>(1000000);
for(int i = 0 ; i < 1000000; i++){
baseUser = new Base_User(i,"chenssy_"+i,i);
list2.add(baseUser);
}
long end2 = System.currentTimeMillis();
System.out.println("list2 time:" + (end2 - begin2));
}
}
分析:
插入1000000條數(shù)據(jù)解幽,list1沒(méi)有沒(méi)有申請(qǐng)初始化容量,而list2初始化容量1000000烘苹。運(yùn)行結(jié)果我們可以看出list2的速度是list1的兩倍左右躲株。
ArrayList的擴(kuò)容機(jī)制是比較消耗資源的。我們先看ArrayList的add方法:
public boolean add(E e) {
ensureCapacity(size + 1);
elementData[size++] = e;
return true;
}
public void ensureCapacity(int minCapacity) {
modCount++; //修改計(jì)數(shù)器
int oldCapacity = elementData.length;
//當(dāng)前需要的長(zhǎng)度超過(guò)了數(shù)組長(zhǎng)度镣衡,進(jìn)行擴(kuò)容處理
if (minCapacity > oldCapacity) {
Object oldData[] = elementData;
//新的容量 = 舊容量 * 1.5 + 1
int newCapacity = (oldCapacity * 3)/2 + 1;
if (newCapacity < minCapacity)
newCapacity = minCapacity;
//數(shù)組拷貝霜定,生成新的數(shù)組
elementData = Arrays.copyOf(elementData, newCapacity);
}
}
ArrayList每次新增一個(gè)元素,就會(huì)檢測(cè)ArrayList的當(dāng)前容量是否已經(jīng)到達(dá)臨界點(diǎn)廊鸥,如果到達(dá)臨界點(diǎn)則會(huì)擴(kuò)容1.5倍望浩。
然而ArrayList的擴(kuò)容以及數(shù)組的拷貝生成新的數(shù)組是相當(dāng)耗資源的。
大數(shù)據(jù)量的前提下,指定初始化容量惰说,效率的提升和資源的利用會(huì)顯得更加具有優(yōu)勢(shì)磨德。
集合進(jìn)階2---使用entrySet遍歷Map集合KV
HashMap的遍歷有兩種常用的方法,那就是使用keyset及entryset來(lái)進(jìn)行遍歷
但兩者的遍歷速度是有差別的吆视。
第一種: entryset 效率高
Map map = new HashMap();
Iterator iter = map.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
Object key = entry.getKey();
Object val = entry.getValue();
}
第二種: keySet 效率低
Map map = new HashMap();
Iterator iter = map.keySet().iterator();
while (iter.hasNext()) {
Object key = iter.next();
Object val = map.get(key);
}
對(duì)于keySet其實(shí)是遍歷了2次典挑,一次是轉(zhuǎn)為iterator,一次就從hashmap中取出key所對(duì)于的value啦吧。
而entryset只是遍歷了第一次您觉,他把key和value都放到了entry中,所以就快了授滓。
集合進(jìn)階3---合理利用集合的穩(wěn)定性和有序性
合理利用集合的穩(wěn)定性(order)和有序性(sort)琳水,避免集合的無(wú)序性和不穩(wěn)定性帶來(lái)的負(fù)面影響肆糕。
- 穩(wěn)定性指集合每次遍歷的元素次序是一定的。
- 有序性是指遍歷的結(jié)果按某種比較規(guī)則依次排序的在孝。
ArrayList是order/unsort诚啃,HashMap是unorder/unsort,TreeSet是order/sort私沮,還可以通過(guò)TreeSet結(jié)合ArrayList對(duì)結(jié)果進(jìn)行排序绍申。
Java 常用集合的一些特征:
①、LinkedList 底層是雙向鏈表顾彰。ArrayList:底層采用數(shù)組結(jié)構(gòu),里面添加的元素有序可以重復(fù)胃碾。
②涨享、HashSet:底層采用哈希表算法,里面添加的元素?zé)o序不可重復(fù)仆百。
③厕隧、HashMap:底層也是采用哈希表算法,但是里面添加的元素是 key-value 的形式俄周。key 不允許重復(fù)吁讨,value 可以。
如何好好利用這些集合的原理峦朗,簡(jiǎn)化我們的編程呢建丧。
1、統(tǒng)計(jì)一字符串中每個(gè)字符出現(xiàn)的次數(shù)波势?
解析:給定一串字符串翎朱,統(tǒng)計(jì)每個(gè)字符出現(xiàn)的次數(shù)。統(tǒng)計(jì)的字符是不能重復(fù)的尺铣,而出現(xiàn)的個(gè)數(shù)我們可以不用管拴曲。那么很容易聯(lián)想到 Map 的集合原理,key-value凛忿。我們將統(tǒng)計(jì)的字符放在 Map<Character,Integer>中是一種很好的實(shí)現(xiàn)方式澈灼。
HashMap
import java.util.HashMap;
import java.util.Map;
public class CnTest {
public static Map<Character, Integer> countChar(Map<Character, Integer> map,String str){
//將所給的字符串解析為一個(gè)字符構(gòu)造的數(shù)組
char[] chars = str.toCharArray();
for(char c : chars){
if(map.containsKey(c)){
int oldCount = map.get(c);
map.put(c, oldCount+1);
}else{
map.put(c, 1);
}
}
return map;
}
public static void main(String[] args) {
String str = "hello world";
//定義一個(gè) Map 集合,用來(lái)存放統(tǒng)計(jì)的 字符--個(gè)數(shù)
Map<Character, Integer> hashMap = new HashMap<Character, Integer>();
System.out.println(countChar(hashMap,str));
//{w=1, d=1, =1, e=1, r=1, o=2, l=3, h=1}
}
}
補(bǔ)充:這里我們用來(lái)保存統(tǒng)計(jì)字符的是 HashMap 的實(shí)現(xiàn)類店溢,這里打印出來(lái)的字符統(tǒng)計(jì)是無(wú)序的叁熔。
LinkedHashMap
根據(jù)字符串給定的順序有序的統(tǒng)計(jì)出
public static void main(String[] args) {
String str = "hello world";
//定義一個(gè) Map 集合,用來(lái)存放統(tǒng)計(jì)的 字符--個(gè)數(shù)
Map<Character, Integer> linkedHashMap = new LinkedHashMap<Character, Integer>();
System.out.println(countChar(linkedHashMap,str));
//{h=1, e=1, l=3, o=2, =1, w=1, r=1, d=1}
}
TreeMap
用 uicode 的編碼順序打印給定的字符串
public static void main(String[] args) {
String str = "hello world";
//定義一個(gè) Map 集合床牧,用來(lái)存放統(tǒng)計(jì)的 字符--個(gè)數(shù)
Map<Character, Integer> treeMap = new TreeMap<Character, Integer>();
System.out.println(countChar(treeMap,str));
//{ =1, d=1, e=1, h=1, l=3, o=2, r=1, w=1}
}
二者疤、去掉給定數(shù)組重復(fù)的數(shù)據(jù)?
解析:將數(shù)組中的元素都放到Set叠赦,然后將 Set 集合轉(zhuǎn)變?yōu)閿?shù)組就可以了驹马。
import java.util.HashSet;
import java.util.Set;
public class CrTest {
public static Integer[] clearRepeat(int [] array){
Set<Integer> set = new HashSet<Integer>();
for(int i : array){
set.add(i);
}
Integer[] newArray = set.toArray(new Integer[set.size()]);
return newArray;
}
public static void main(String[] args) {
//創(chuàng)建一個(gè)數(shù)組革砸,可以看出 2和4 是重復(fù)的
int [] array = {1,2,3,4,2,2,3,4};
Integer[] newArray = clearRepeat(array);
for(Integer i : newArray){
System.out.println(i);
}
//1 2 3 4
}
}
同理我們可以改變 Set 集合的實(shí)現(xiàn)類,hashSet 是無(wú)序的糯累,我們可以會(huì)用** LinkedHashSet** 保證既定順序算利;TreeSet 保證自然順序
over