迭代器的應用和集合進階List&Set
集合進階
迭代器
Iterable:可迭代的。
1. 為什麼要有Iterable:每種集合,底層資料結構不同,取出方式不同,為了能以統一的一種方式取出所有集合的元素,定義迭代器。
2. 為什麼Iterable是一個介面:介面的抽象方法,是一個標準,其實現類必須實現。保證所有的實現類實現了自己特有的迭代方法。
3. 為什麼Iterable不做成一個抽象類:因為介面是多實現的,而抽象類是單繼承的。
4. Iterable:它的所有的實現類都是可以被迭代輸出的。
List<String> list = new ArrayList<String>();
list.add("one" );
list.add("two");
list.add("three");
list.add("four");
list.add("five");
// Iterable的抽象方法返回Iterator
Iterator<String> it = list.iterator();// 迭代器
while(it.hasNext()){// one two three four five
System.out.println(it.next());
}
5. Iterator相當於一個游標,開始指向開始的地方,當迭代器迭代一次之後,游標指向最後一個值,不能二次迭代。
List<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");
Iterator<String> it = list.iterator(); while(it.hasNext()){// one two three four five
String str = it.next();
System.out.print(it.next());
}
while(it.hasNext()){// 無輸出
String str = it.next();
System.out.println("2:" +str);
}
6. ListIterator
ConcurrentModificationException:併發修改異常
在使用迭代器迭代的過程中,如果使用list增加、刪除或修改元素,則會報併發修改異常。
List<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");
Iterator<String> it = list.iterator();
while(it.hasNext()){
String str = it.next();
if(str.equals("one")){
// ConcurrentModificationException
list.add("list");
}
}
System.out.println(list);
Iterator的子介面:ListIterator,專門用於List集合,提供了add和remove方法解決迭代過程中併發修改異常。
List<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");
ListIterator<String> it = list.listIterator();
while(it.hasNext()){
String str = it.next();
if(str.equals("one")){
it.add("list");
}
}
// [one, list, two, three, four, five]
System.out.println(list);
ListIterator還提供了逆序迭代:
List<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");
// 逆序迭代輸出
ListIterator<String> it = list.listIterator(list.size());
while(it.hasPrevious()){// five four three two one
String str = it.previous();
System.out.println(str);
}
迭代器的簡化應用——foreach的使用
List<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");
// one two three four five
for(String str :list){
System.out.println(str);
}
List&Set
1. List&Set
List:
- 元素存入順序和取出順序一致(有序)
- 元素可以重複
- 可以使用get(i)的方式將元素取出
- List中刪除、查詢、判斷是否包含依據是equals()方法
Set:hash(雜湊,雜湊)演算法 底層HashMap
- 元素存入順序和取出順序不一致(無序),注意無序不是隨機順序
- 元素會自動去重,不可以重複
- 沒有get方法用於取出單個元素
- HashSet中去重依據的是hashCode()方法和equals()方法
- TreeSet:底層是二叉樹
2. ArrayList和LinkedList的區別?
ArrayList、Vector、LinkedList都是List集合。
- ArrayList和Vector底層是陣列,而LinkedList底層是雙向連結串列。最多使用的是ArrayList
- 陣列:新增元素非常耗時,查詢元素比較快。
- 連結串列:查詢耗時,新增元素比較快。
- 底層結構的不同決定了使用場景的不同
3. HashSet
在HashSet新增元素的過程中,先比較元素的hashCode()方法,如果hashCode()不同,則認為是兩個物件,則儲存。
如果hashCode()相同,則比較equals()方法,如果equals()不同,則認為是兩個物件,則儲存。
如果hashCode()相同,equals()也相同,則認為是同一個物件,則不儲存。
- Java官方規定,重寫equals,必須重寫hashCode
- 如果兩個物件的equals相等,則他們的hashCode一定相等,反之不成立。
- hashCode equals toString :Object的三大重寫
4. TreeSet
set的特點:
- 元素存入順序和取出順序不一致
- 會自動將元素按照字典順序進行排序
- 排序依據的是compareTo方法
物件想要放入TreeSet中,需要具有可比較性。如何具有可比較性?
- 1、類實現Comparable介面,提供comparTo方法,方法中定義排序的規則。 這裡的方法返回值int:如果等於0,則認為是同一個物件,如果大於0,則排後面,如果小於0,在排前面。
- 2、在TreeSet中提供一個Comparator比較器的實現類,重寫compare方法。優先選擇本方案,比較靈活,可以使用在多個比較的場景。
牛刀小試
public class Person implements Comparable<Person>{
private String name;
private int age;
......
@Override
public int compareTo(Person o) {// 重寫comparTo方法定義比較規則
if(this.getAge() != o.getAge()){
return this.getAge()-o.getAge();// 年齡從小到大,主碼
}else {
return this.getName().compareTo(o.getName());//名字的字典順序
}
}
// 測試類中程式碼
Set<Person> set = new TreeSet<Person>();
Person p1 = new Person("zhangsan",20);
Person p2 = new Person("lisi",18);
Person p3 = new Person("wangwu",20);
Person p4 = new Person("zhaoliu",19);
Person p5 = new Person("tianqi",20);
Person p6 = new Person("zhangsan",20);
set.add(p1);
set.add(p2);
set.add(p3);
set.add(p4);
set.add(p5);
set.add(p6);
for (Person person : set) {
System.out.println(person);
}
//Person [name=lisi, age=18]
//Person [name=zhaoliu, age=19]
//Person [name=tianqi, age=20]
//Person [name=wangwu, age=20]
//Person [name=zhangsan, age=20]