集合进阶 1--- 为集合指定初始容量
集合在 Java 编程中使用非常广泛, 当容器的量变得非常大的时候, 它的初始容量就会显得很重要了.
因为扩容是需要消耗大量的人力物力财力的.
同样的道理, Collection 的初始容量也显得异常重要. 所以: 对于已知的情景, 请为集合指定初始容量.
- 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 条数据, list1 没有没有申请初始化容量, 而 list2 初始化容量 1000000. 运行结果我们可以看出 list2 的速度是 list1 的两倍左右.
ArrayList 的扩容机制是比较消耗资源的. 我们先看 ArrayList 的 add 方法:
- public boolean add(E e) {
- ensureCapacity(size + 1);
- elementData[size++] = e;
- return true;
- }
- public void ensureCapacity(int minCapacity) {
- modCount++; // 修改计数器
- int oldCapacity = elementData.length;
- // 当前需要的长度超过了数组长度, 进行扩容处理
- if (minCapacity> oldCapacity) {
- Object oldData[] = elementData;
- // 新的容量 = 旧容量 * 1.5 + 1
- int newCapacity = (oldCapacity * 3)/2 + 1;
- if (newCapacity <minCapacity)
- newCapacity = minCapacity;
- // 数组拷贝, 生成新的数组
- elementData = Arrays.copyOf(elementData, newCapacity);
- }
- }
ArrayList 每次新增一个元素, 就会检测 ArrayList 的当前容量是否已经到达临界点, 如果到达临界点则会扩容 1.5 倍.
然而 ArrayList 的扩容以及数组的拷贝生成新的数组是相当耗资源的.
大数据量的前提下, 指定初始化容量, 效率的提升和资源的利用会显得更加具有优势.
集合进阶 2--- 使用 entrySet 遍历 Map 集合 KV
HashMap 的遍历有两种常用的方法, 那就是使用 keyset 及 entryset 来进行遍历
但两者的遍历速度是有差别的.
第一种: 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);
- }
对于 keySet 其实是遍历了 2 次, 一次是转为 iterator, 一次就从 hashmap 中取出 key 所对于的 value.
而 entryset 只是遍历了第一次, 他把 key 和 value 都放到了 entry 中, 所以就快了.
集合进阶 3--- 合理利用集合的稳定性和有序性
合理利用集合的稳定性 (order) 和有序性(sort), 避免集合的无序性和不稳定性带来的负面影响.
稳定性指集合每次遍历的元素次序是一定的.
有序性是指遍历的结果按某种比较规则依次排序的.
ArrayList 是 order/unsort,HashMap 是 unorder/unsort,TreeSet 是 order/sort, 还可以通过 TreeSet 结合 ArrayList 对结果进行排序.
Java 常用集合的一些特征:
,LinkedList 底层是双向链表. ArrayList: 底层采用数组结构, 里面添加的元素有序可以重复.
,HashSet: 底层采用哈希表算法, 里面添加的元素无序不可重复.
,HashMap: 底层也是采用哈希表算法, 但是里面添加的元素是 key-value 的形式. key 不允许重复, value 可以.
如何好好利用这些集合的原理, 简化我们的编程呢.
1, 统计一字符串中每个字符出现的次数?
解析: 给定一串字符串, 统计每个字符出现的次数. 统计的字符是不能重复的, 而出现的个数我们可以不用管. 那么很容易联想到 Map 的集合原理, key-value. 我们将统计的字符放在 Map<Character,Integer > 中是一种很好的实现方式.
- HashMap
- import java.util.HashMap;
- import java.util.Map;
- public class CnTest {
- public static Map<Character, Integer> countChar(Map<Character, Integer> map,String str){
- // 将所给的字符串解析为一个字符构造的数组
- 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";
- // 定义一个 Map 集合, 用来存放统计的 字符 -- 个数
- 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}
- }
- }
补充: 这里我们用来保存统计字符的是 HashMap 的实现类, 这里打印出来的字符统计是无序的.
LinkedHashMap
根据字符串给定的顺序有序的统计出
- public static void main(String[] args) {
- String str = "hello world";
- // 定义一个 Map 集合, 用来存放统计的 字符 -- 个数
- 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";
- // 定义一个 Map 集合, 用来存放统计的 字符 -- 个数
- 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}
- }
二, 去掉给定数组重复的数据?
解析: 将数组中的元素都放到 Set, 然后将 Set 集合转变为数组就可以了.
- 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) {
- // 创建一个数组, 可以看出 2 和 4 是重复的
- 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 集合的实现类, hashSet 是无序的, 我们可以会用 ** LinkedHashSet** 保证既定顺序; TreeSet 保证自然顺序
over
by: 一只阿木木
来源: http://www.bubuko.com/infodetail-2636660.html