容器遍歷以及迭代器Iterator Iterable
迭代器
提供一種方法對一個容器中的各個元素進行訪問,而又不暴露物件容器的內部細節。因為容器的內部結構不同,很多時候不知道該如何去遍歷一個容器中的元素,為了方便操作容器內元素,提供迭代器模式。
在這之前先重溫一下對於已知結構的容器的遍歷方式(傳統for迴圈)
陣列使用下標
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
List使用get(角標)方法
for(int i = 0 ; i < list.size() ; i++) {
system.out.println(list.get(i));
}
那麼對於其他容器Set、Map容器內沒有角標,不能使用傳統for迴圈的或者其他不知道內部結構的容器,就需要使用迭代器或者基於迭代器實現的迭代方式。
迭代介面
Iterator介面
public interface Iterator<T>{
boolean hasNext();
AnyType next();
void remove();
}
1 Java的Iterator的方法依賴當前位置,並且只能單向移動
2 使用hasNext()檢查序列中是否還有下一個元素
3 使用next()方法獲取序列的下一個元素
4 使用remove()方法將迭代器新進返回的元素刪除
Iterable介面
public interface Iterable<T> {
Iterator<T> iterator();
}
1 Iterable介面中包含一個iterator()方法,該方法用來返回一個Iterator型別的物件(一個實現Iterator介面的物件)
2 Iterable介面被foreach用來在序列中移動,也就是說如果建立了實現Iterable介面的類,就可以將他應用在foreach語句中
3 Collection物件全部實現了Iterable介面,與foreach一起工作是Collection物件的共性
Iterable和Iterator的關係
1 首先Iterable的實現在於通過iterator方法獲取一個Iterator例項
2 Iterator物件一經建立,只能單向運動,這將意味著如果在其他的位置還要遍歷一遍容器則需要再建立一個Iterator物件,這也是Iterable介面做的事情,每次呼叫iterator()方法便返回一個新的從頭開始的Iterator迭代器,各個迭代器之間互不影響。
3 兩者不是隻能選擇一種實現的關係,而是相輔相成的,實現Iterator介面重新next()等方法對容器內部結構遍歷,實現terable介面,每次呼叫iterator()方法都返回一個新物件。
如果我們需要為類A實現一個自定義的迭代器,首先要
a. 定義一個AIterator類實現Iterator介面,重寫next()等方法
b. 在類A中實現Iterable介面,重寫iterator()方法
public Iterator<T> iterator(){
return new AIterator();
}
這兩者相輔相成,這也是很多地方說,Iterator是迭代類(實現一個基礎的迭代類),Iterable是迭代介面的原因
我們現在知道了兩個介面,一個負責底層邏輯,一個提供操作入口,不存在任何比較關係,那現在就來看看如何使用吧
1 使用iterator方法獲取一個Iterator物件並返回序列的第一個元素
2 使用hasNext()檢查序列中是否還有下一個元素
3 使用next()方法獲取序列的下一個元素
4 使用remove()方法將迭代器新進返回的元素刪除,這個刪除是作用在容器自身的,會刪除掉容器內的元素
這裡對這些方法有一點注意的
Iterator iterator1 = list.iterator();
Iterator iterator2 = list.iterator();
//呼叫iterator()返回新的迭代器
List<Integer> list = Arrays.asList(new Integer[]{1,2,3,4,5});
Iterator iterator = list.iterator();
while(iterator.hasNext()) {
if(!iterator.next().equals(5)){
System.out.println(iterator.next());
}
}
//此處輸出2
//因為我們再if(!iterator.next().equals(5))以及呼叫了一次iteartor.next()迭代器已經前進一位
//再輸出iteartor.next()又前進一位,輸出2
//iterator.next()是動態的,並不是在一次遍歷中就固定不動代表一個元素的
//如果需要判斷輸出,要拿變數儲存
List<Integer> list = Arrays.asList(new Integer[]{1,2,3,4,5});
Iterator iterator = list.iterator();
while(iterator.hasNext()) {
Integer i = (Integer) iterator.next();
if(!i.equals(5)){
System.out.println(i);
}
}
//輸出1
List<Integer> list = new ArrayList<Integer>(Arrays.asList(new Integer[]{1,2,3,4,5}));
System.out.println(list);
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
Integer i = (Integer) iterator.next();
if(i.equals(3)){
iterator.remove();
}
}
System.out.println(list);
//輸出:[1, 2, 3, 4, 5]
// [1, 2, 4, 5]
//remove方法是作用的容器本身的
如何自定義一個迭代器
1 定義一個AIterator類實現Iterator介面,重寫next()等方法
private class AIterator implements Iterator<T>{
public boolean hasNest(){
xxxx;
}
public T next() {
xxx;
}
public void remove() {
xxx;
}
}
2 在類A中實現Iterable介面,重寫iterator()方法
public class A implements Iterable<T> {
public Iterator<T> iterator(){
return new AIterator();
}
}
Collection集合中基於迭代器的遍歷方法
Collection中通用的迭代器遍歷 和 foreach
Iterator iterator = list.iterator();
while(iterator.hasNext()){
int i = (Integer) iterator.next();
System.out.println(i);
}
for (Object object : list) {
System.out.println(object);
}
集合中其他遍歷方法
List
1 基於角標的get方法(不是迭代器實現的),只是在這裡提醒自己一下
Set
無,就是迭代器 + foreach
Map
Map是基於鍵值對的,所以它的迭代器實現比較特殊
就算使用迭代器通用方法也要先通過Map.entrySet拿出所有的鍵值對
Map類提供了一個稱為entrySet()的方法,這個方法返回一個Map.Entry例項化後的物件集,可以得到Map中所有的資料資訊。
1 非entrySet,一次一次get(key)
for (Integer in : map.keySet()) { //map.keySet(); //得到所有key的集合
String str = map.get(in);//得到每個key多對用value的值
}
2 非entrySet + foreach遍歷value,但是不能得到可以值
for (String v : map.values()) {//map.values(); //得到所有value的集合
System.out.println("value= " + v);
}
3 entrySet + Iterator
Iterator<Map.Entry<Integer, String>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<Integer, String> entry = it.next();
System.out.println( entry.getKey() + entry.getValue());
}
4 entrySet + foreach(推薦 尤其是資料大時)
for (Map.Entry<Integer, String> entry : map.entrySet()) {
System.out.println(entry.getKey() + entry.getValue());
}