在Java裡,對於物件的收集、處理有兩種不同的概念
1.Collection -
收集物件並形成一個具有相同處理規範的物件集合
List 在收集物件時會記錄其索引順序,所以可藉由索引取回物件
Set 會過濾掉已經收集過的物件,形成一組不重複的物件集合
Queue 以佇列的形式收集物件,對於佇列兩端的物件有較方便的操作
2.Map -
Map是一群成對的key-value物件,讓使用者可以透過另外一個物件查詢目標值
對於物件集合,提供了搜尋的方便性
java.util.Collection 介面定義了 add()、remove()等method
另外其子類別容器也都要實作 java.lang.Iterable 介面,所以容器中的物件也都可以逐一被處理
ArrayList實作時使用Object陣列來保存收的物件
陣列在記憶體中是連續的線性空間
根據索引進行隨機存取的速度較快,但對調整索引順序的處理效率則較差
此外,因使用連續空間,陣列的長度固定也需要考量
ArrayList內部陣列長度不夠時會建立新陣列,並將舊陣列的參考指定給新陣列
如果大致知道需要的空間,事先建立足夠長度的內部陣列可以節省建立新陣列的成本
相關可以看物件容器容量大小的調整一文
LinkedList使用了Link結構,只有在加入新物件時才會耗費成本
但Link結構找物件時都必須從第一個Node開始
以指定索引隨機存取物件的情況來說效率較差
相對的在調整索引順序再有較好的表現
set的目的則是不收集重複的物件
例如HashSet的運作原理是在加入物件時,會先呼叫物件的hashCode()取得雜湊碼
並將其放入相對應雜湊碼的雜湊桶(Hash bucket)
若裡面已事先有物件則再呼叫equals()進行比較
只有equals()為false表示兩個並非重複物件時才可以收藏
實際上許多Java判斷物件是否重複的方法都會呼叫hashCode()和equals()
Java的規格書建議兩個方法必須同時實作,如:
class demo {
private String name;
private int number;
demo(String name, int number) {
this.name = name;
this.number = number;
}
@Override
public bolean equals(Object obj) {
if (obj == null) { return false;}
if (getClass() != obj.getClass()) { return false;}
return true;
}
@Override
public int hashCode() { return number;}
}
如果希望收集物件的方式是用佇列
也就是物件會從佇列尾端開始放入,由前端開始取出,則可以使用實作Queue介面的物件
例如LinkedList除了實作List介面外,也實作了Queue的子介面Deque,所以也可以當佇列使用
Queue繼承了add()、remove()、element()等方法,但也另外定義了offer()、poll()、peek()等方法
兩者的差別在於 add()、remove()等在操作失敗時會拋出例外,Queue介面定義的方法在失敗時回傳特定值
所以打算使用Queue,且佇列長度有所限制時,建議使用offer()、poll()、peek()
offer()會在佇列尾端加入物件,且成功時回傳true,失敗則回傳false
poll()用來取出佇列前端物件,如果佇列裡沒有物件則回傳 null
peek()則是取得,但不取出佇列前端物件,如果佇列裡沒有物件則回傳 null
Collection介面中定義了Iterator,所以無論是List、Set、Queue都可以取得Iterator
透過Iterator的 hasNext()可以判斷是否有下一個物件,有的話再透過 next() 取得
依這樣的操作,可以繞遍容器中的每個物件並做處理
ArrayList < Integer > al = new ArrayList < Integer > ();
al.add(1);al.add(3);al.add(5);
Iterator < Integer > i = al.iterator();
while (i.hasNext()) {
System.out.println(i.next());
}
在JDK5有增強式for迴圈後,也可以利用這個語法糖少寫一些程式
編譯時JVM在底層一樣會展開成上面的形式
for(int num : al){
System.out.println(num);
}
排序也是容器的重要功能之一,java.util.Collection本身就有sort() method 可以用
但若物件不是基本型別或排序的規則不符我們的需求
則需另外讓物件實作Comparable介面、或建立Comparator物件後讓sort()引用
class demoObj implements Comparable {
private int value;
....
@Override
public int comparaTo(Object o) {
demoObj other = (demoObj) o;
return this.value - other.value
}
}
Collections.sort(arraylist, new Comparator() {
public int compare(Object o1, Object o2) {
HashMap m1 = (HashMap) o1;
HashMap m2 = (HashMap) o2;
return Integer.parseInt(m2.get(rank).toString()) - Integer.parseInt(m1.get(rank).toString());
}
});
Map的主要目的就是快速的查詢物件,下述例子以HashMap為例解釋Map的運作方式
HashMap<String, Integer> hm = new HashMap<>();
hm.put("1st", 1);hm.put("2nd", 2);
使用put()放入方便查詢的key以及儲存用的value
儲存時Map物件會比對hashCode()和equals()兩個方法,確保在Map中絕對不會有重複的key
java.util..Properties則是另一個常用的Map子類別,常用於存取設定檔的資料
在國際化、資料庫的部分幾乎確定會再用到它
建立一個.properties 副檔名的檔案,並在其中寫入資料,如:
paramB=2
定義一個專門處理properties檔的類別
public class PropertiesOperater {
private Properties prop;
public boolean loadProperties(String filePath) {
prop = new Properties();
try {
prop.load(new FileInputStream(filePath)); //load結束後會自動關閉InputStream,JDK7 auto closable
} catch (FileNotFoundException e) {
e.printStackTrace();
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
public boolean saveProperties(String filePath) {
try {
prop.store(new FileOutputStream(filePath), null);
} catch (IOException e) {
e.printStackTrace();
return false;
}
prop.clear();
return true;
}
public String getProperties(String key) {
return prop.getProperty(key);
}
public void setProperties(String key, String value) {
prop.setProperty(key, value);
}
public void removeProperties(String key) {
prop.remove(key);
}
public Map getPropertiesMaps() {
return prop;
}
}
實際使用:
PropertiesOperater po = new PropertiesOperater();
if (po.loadProperties("D:\\demo.properties")) {
Map < String, String > map = po.getPropertiesMaps();
for (Map.Entry < String, String > m: map.entrySet()) {
out.print(m.getKey() + " " + m.getValue() + "<br />");
}
}
/*output:
**paramB 2
**paramA 1
*/
想走訪完Map裡的每一個物件,可以使用entrySet() 取得Set物件
entrySet()是效率較keySet()好的方法,因為他只在取出的時候判斷一次型別
取出的每個元素都是Map.Entry的Instance,可以呼叫getKey()取得Key,或getValue()取得value
如下範例:
for (Map.Entry < Integer, String > m : map.entrySet()) {
out.print(m.getKey() + " " + m.getValue() + "<br />");
}
如果要排序Map,最簡單的方式是建立一個TreeMap
TreeMap再放入資料時便會依照Key進行排序,之後取出entrySet就可以看到依Key順序走訪
如果排序的基準與Key無關,則需要將它轉型成LinkedList後,再重新排序放入LinkedHashMap
例如以下示範資料依 Value 重新排序:
List < Map.Entry < String, String >> list = new LinkedList < Map.Entry < String, String >> (result.entrySet());
Collections.sort(list, new Comparator < Map.Entry < String, String >> () {
public int compare(Map.Entry < String, String > m1, Map.Entry < String, String > m2) {
String s1 = m1.getValue();
String s2 = m2.getValue();
return s1.compareTo(s2);
}
});
Map < String, String > temp = new LinkedHashMap < String, String > ();
for (Iterator < Map.Entry < String, String >> it = list.iterator(); it.hasNext();) {
Map.Entry < String, String > entry = it.next();
temp.put(entry.getKey(), entry.getValue());
}
return temp;
1.Collection -
收集物件並形成一個具有相同處理規範的物件集合
List 在收集物件時會記錄其索引順序,所以可藉由索引取回物件
Set 會過濾掉已經收集過的物件,形成一組不重複的物件集合
Queue 以佇列的形式收集物件,對於佇列兩端的物件有較方便的操作
2.Map -
Map是一群成對的key-value物件,讓使用者可以透過另外一個物件查詢目標值
對於物件集合,提供了搜尋的方便性
java.util.Collection 介面定義了 add()、remove()等method
另外其子類別容器也都要實作 java.lang.Iterable 介面,所以容器中的物件也都可以逐一被處理
ArrayList實作時使用Object陣列來保存收的物件
陣列在記憶體中是連續的線性空間
根據索引進行隨機存取的速度較快,但對調整索引順序的處理效率則較差
此外,因使用連續空間,陣列的長度固定也需要考量
ArrayList內部陣列長度不夠時會建立新陣列,並將舊陣列的參考指定給新陣列
如果大致知道需要的空間,事先建立足夠長度的內部陣列可以節省建立新陣列的成本
相關可以看物件容器容量大小的調整一文
LinkedList使用了Link結構,只有在加入新物件時才會耗費成本
但Link結構找物件時都必須從第一個Node開始
以指定索引隨機存取物件的情況來說效率較差
相對的在調整索引順序再有較好的表現
set的目的則是不收集重複的物件
例如HashSet的運作原理是在加入物件時,會先呼叫物件的hashCode()取得雜湊碼
並將其放入相對應雜湊碼的雜湊桶(Hash bucket)
若裡面已事先有物件則再呼叫equals()進行比較
只有equals()為false表示兩個並非重複物件時才可以收藏
實際上許多Java判斷物件是否重複的方法都會呼叫hashCode()和equals()
Java的規格書建議兩個方法必須同時實作,如:
class demo {
private String name;
private int number;
demo(String name, int number) {
this.name = name;
this.number = number;
}
@Override
public bolean equals(Object obj) {
if (obj == null) { return false;}
if (getClass() != obj.getClass()) { return false;}
return true;
}
@Override
public int hashCode() { return number;}
}
如果希望收集物件的方式是用佇列
也就是物件會從佇列尾端開始放入,由前端開始取出,則可以使用實作Queue介面的物件
例如LinkedList除了實作List介面外,也實作了Queue的子介面Deque,所以也可以當佇列使用
Queue繼承了add()、remove()、element()等方法,但也另外定義了offer()、poll()、peek()等方法
兩者的差別在於 add()、remove()等在操作失敗時會拋出例外,Queue介面定義的方法在失敗時回傳特定值
所以打算使用Queue,且佇列長度有所限制時,建議使用offer()、poll()、peek()
offer()會在佇列尾端加入物件,且成功時回傳true,失敗則回傳false
poll()用來取出佇列前端物件,如果佇列裡沒有物件則回傳 null
peek()則是取得,但不取出佇列前端物件,如果佇列裡沒有物件則回傳 null
Collection介面中定義了Iterator,所以無論是List、Set、Queue都可以取得Iterator
透過Iterator的 hasNext()可以判斷是否有下一個物件,有的話再透過 next() 取得
依這樣的操作,可以繞遍容器中的每個物件並做處理
ArrayList < Integer > al = new ArrayList < Integer > ();
al.add(1);al.add(3);al.add(5);
Iterator < Integer > i = al.iterator();
while (i.hasNext()) {
System.out.println(i.next());
}
在JDK5有增強式for迴圈後,也可以利用這個語法糖少寫一些程式
編譯時JVM在底層一樣會展開成上面的形式
for(int num : al){
System.out.println(num);
}
排序也是容器的重要功能之一,java.util.Collection本身就有sort() method 可以用
但若物件不是基本型別或排序的規則不符我們的需求
則需另外讓物件實作Comparable介面、或建立Comparator物件後讓sort()引用
class demoObj implements Comparable {
private int value;
....
@Override
public int comparaTo(Object o) {
demoObj other = (demoObj) o;
return this.value - other.value
}
}
Collections.sort(arraylist, new Comparator() {
public int compare(Object o1, Object o2) {
HashMap m1 = (HashMap) o1;
HashMap m2 = (HashMap) o2;
return Integer.parseInt(m2.get(rank).toString()) - Integer.parseInt(m1.get(rank).toString());
}
});
Map的主要目的就是快速的查詢物件,下述例子以HashMap為例解釋Map的運作方式
HashMap<String, Integer> hm = new HashMap<>();
hm.put("1st", 1);hm.put("2nd", 2);
使用put()放入方便查詢的key以及儲存用的value
儲存時Map物件會比對hashCode()和equals()兩個方法,確保在Map中絕對不會有重複的key
java.util..Properties則是另一個常用的Map子類別,常用於存取設定檔的資料
在國際化、資料庫的部分幾乎確定會再用到它
建立一個.properties 副檔名的檔案,並在其中寫入資料,如:
demo.properties======
paramA=1paramB=2
定義一個專門處理properties檔的類別
public class PropertiesOperater {
private Properties prop;
public boolean loadProperties(String filePath) {
prop = new Properties();
try {
prop.load(new FileInputStream(filePath)); //load結束後會自動關閉InputStream,JDK7 auto closable
} catch (FileNotFoundException e) {
e.printStackTrace();
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
public boolean saveProperties(String filePath) {
try {
prop.store(new FileOutputStream(filePath), null);
} catch (IOException e) {
e.printStackTrace();
return false;
}
prop.clear();
return true;
}
public String getProperties(String key) {
return prop.getProperty(key);
}
public void setProperties(String key, String value) {
prop.setProperty(key, value);
}
public void removeProperties(String key) {
prop.remove(key);
}
public Map getPropertiesMaps() {
return prop;
}
}
實際使用:
PropertiesOperater po = new PropertiesOperater();
if (po.loadProperties("D:\\demo.properties")) {
Map < String, String > map = po.getPropertiesMaps();
for (Map.Entry < String, String > m: map.entrySet()) {
out.print(m.getKey() + " " + m.getValue() + "<br />");
}
}
/*output:
**paramB 2
**paramA 1
*/
想走訪完Map裡的每一個物件,可以使用entrySet() 取得Set物件
entrySet()是效率較keySet()好的方法,因為他只在取出的時候判斷一次型別
取出的每個元素都是Map.Entry的Instance,可以呼叫getKey()取得Key,或getValue()取得value
如下範例:
for (Map.Entry < Integer, String > m : map.entrySet()) {
out.print(m.getKey() + " " + m.getValue() + "<br />");
}
如果要排序Map,最簡單的方式是建立一個TreeMap
TreeMap再放入資料時便會依照Key進行排序,之後取出entrySet就可以看到依Key順序走訪
如果排序的基準與Key無關,則需要將它轉型成LinkedList後,再重新排序放入LinkedHashMap
例如以下示範資料依 Value 重新排序:
List < Map.Entry < String, String >> list = new LinkedList < Map.Entry < String, String >> (result.entrySet());
Collections.sort(list, new Comparator < Map.Entry < String, String >> () {
public int compare(Map.Entry < String, String > m1, Map.Entry < String, String > m2) {
String s1 = m1.getValue();
String s2 = m2.getValue();
return s1.compareTo(s2);
}
});
Map < String, String > temp = new LinkedHashMap < String, String > ();
for (Iterator < Map.Entry < String, String >> it = list.iterator(); it.hasNext();) {
Map.Entry < String, String > entry = it.next();
temp.put(entry.getKey(), entry.getValue());
}
return temp;
留言
張貼留言