1、集合分四類:set,map,list,queue
位於java.util包下.
集合類和數組的區別,數組可以保存基本類型的值或者是對象的引用,而集合里只能保存對象的引用.
集合類主要由兩個接口派生而出:Collection和Map
collection集合里面一共10個可用的類.
其中,
set里面4個: EnumSet, TreeSet, HashSet, LinkedHashSet
Queue里面2個: ArrayDeque, PriorityQueue,
List里面3個: ArrayList, Vector, Stack
同時實現Queue和List的一個: LinkedList
常用的有5個.
Map中實現類一共9個,常用的是HashMap, TreeMap
collection中方法,也就是Set, Queue, List共同的方法.
所有的collection的實現類都從寫了toString()方法,該方法可一次性輸出集合中所有元素.
包括:
求並集(添加元素或集合):
求補集(刪除某元素或集合):
求交集:
是否包含某元素或集合:
是否為空:
遍歷集合:
books.forEach(obj -> System.out.println("迭代集合元素:"+obj));
或者如下:
Iterator<String> it = books.iterator(); //這種形式遍歷可以用it.remove()來刪除元素,其他的方式都不可以,會引發異常. while(it.hasNext()){ System.out.println(it.next()); }
或者如下:
for(String book : books){ System.out.println(book); }
清空集合:
元素個數:
轉成數組:
2、用java8增強的Iterator遍歷集合元素
Iterator接口里定義了4個方法:
boolean hasNext(): 如果被迭代的集合元素還沒有被遍歷完,則返回true
Object next(): 返回集合里的下一個元素
void remove(): 刪除集合里上一次next方法返回的元素
void forEachRemaining(Consumer action),這是java8為Iterator新增的默認方法,可使用Lambda表達式來遍歷集合元素.
Iterator<String> it = books.iterator();
it.forEachRemaining(obj -> System.out.println("迭代集合元素:"+obj));
8.2.5 使用Java8 新增的predicate操作集合
打印長度小於10的元素:
books.removeIf(ele -> ((String)ele).length() <10);
System.out.println(books);
返回符合條件的元素的個數:
public static void main(String[] args){ System.out.println(callAll(books,ele -> ((String)ele).contains("瘋狂"))); } public static int callAll(Collection<String> books, Predicate<Object> p){ int total = 0; for(Object obj :books){ if(p.test(obj)){ total ++; } } return total; }
8.2.6 Java8新增的Stream操作集合
java8新增了Stream,IntStream,LongStream等,其中Stream是一個通用的流接口.還為每個流式Api提供了對應的Builder,例如Stream.Builder,開發者可以通過這些Builder來創建對應的流.
獨立使用Stream的步驟如下:
1.使用Stream或XxxStream的builder()類方法創建改Stream對應的Builder.
2.重復調用Builder的add()方法向該流中添加多個元素.
3.調用Builder的build()方法獲取對應的Stream.
4.調用Stream的聚集方法.
第4步可以根據需求來調用不同的方法,Stream提供了大量的聚集方法供用戶調用,對應大部分聚集方法而言,每個Stream只能執行一次.
public static void main(String[] args) { IntStream is = IntStream.builder() .add(20) .add(13) .add(-2) .add(18) .build(); // System.out.println("最大值:"+ is.max().getAsInt()); // System.out.println("最小值:"+ is.min().getAsInt()); // System.out.println("總和:"+ is.sum()); // System.out.println("總數:"+ is.count()); // System.out.println("平均值:"+ is.average()); // System.out.println("平方均大於20:"+ is.allMatch(ele -> ele*ele > 20)); // System.out.println("某個元素平方大於20:"+ is.anyMatch(ele -> ele*ele > 20)); //將is映射成一個新的Stream,新Stream的每個元素是原Stream元素的2倍+1 IntStream newIs = is.map(ele -> ele * 2 +1); // //使用方法引用的方式來遍歷集合元素 newIs.forEach(System.out::println); }
因為collection有Stream接口,所以,用Stream方法來重寫上面的"返回符合條件的元素的個數"
public static void main(String[] args) { Collection<String> books = new HashSet<>(); books.add("123241232"); books.add("wdw12ddw"); books.add("es23d"); System.out.println(books.stream() .filter(ele -> ((String) ele).contains("123")).count()); }
8.3 Set集合
HashSet的特點:
1.不能保證元素的排列順序
2.不是同步的,如果多線程訪問,必須通過代碼來保證其同步
3.集合元素之可以是null
比較的規則是,equals()方法和HashCode()方法返回的值都相等,那么set認為是同一個對象.
所以,當把一個對象放到HashSet中時,如果需要重寫該對象對應類的equals()方法,那么也要重寫其hashCode()方法.
因此,當程序把可變對象添加到HashSet中之后,盡量不要去修改該集合元素中參與計算hashCode(),equals()的實例變量,否則會導致HashSet無法正確操作這些集合元素.
8.3.2 LinkedHashSet類
LinkedHashSet集合也是根據元素的hashCode值來決定元素的存儲位置,但它同時使用鏈表維護元素的次序,這樣使得元素看起來是以插入的順序保存的,也就是說,當遍歷LinkedHash集合里的元素時,LinkedHashSet將會元素的添加順序來訪問集合里的元素.
LinkedHashSet需要維護元素的插入順序,因此新呢過略低於HashSet的性能,但在迭代訪問Set里的全部元素時將有很好的性能,因為天以鏈表來維護內部順序.
LinkedHashSet<String> books = new LinkedHashSet<>();
8.3.3 TreeSet 類
TreeSet是SortedSet接口的實現類,正如SortedSet名字所暗示的,TreeSet可以確保集合元素處於排序狀態.與HashSet集合相比,TreeSet還提供了如下幾個額外的方法.
訪問前一個,后一個,第一個,最后一個元素的方法,並提供了三個從TreeSet中截取子TreeSet的方法,以及一個Comparator()來返回該TreeSet的定制的排序方法.默認使用自然排序,即從小的到大的順序.
public static void main(String[] args) { // TODO Auto-generated method stub TreeSet nums = new TreeSet<>(); nums.add(5); nums.add(2); nums.add(6); nums.add(-4); System.out.println(nums); }
如果試圖把一個對象添加到TreeSet時,則改對象的類必須實現Comparable接口,否則程序將會拋出ClassCastException異常.不過java一些常用類已經實現了Comparable接口,並提供了比較大小的標准.
另外一點:大部分類在實現compareTo(Object obj)方法時,都需要將被比較對象obj強制類型轉換成相同的類型,因為只有相同類的兩個實例才會比較大小.所以向TreeSet中添加的應該是同一個類(或者有繼承關系)的對象.
為了讓程序更加健壯,推薦不要修改放入HashSet和TreeSet集合中元素的關鍵實例變量.
2.定制排序
兩種方法,一個是要比較的類,需要實現Comparator接口,一個是創建TreeSet時使用Lambda表達式.
8.3.4EnumSet類
EnumSet是一個專為枚舉類設計的集合類,EnumSet中的所有元素都必須是指定枚舉類型的枚舉值,該枚舉類型在創建EnumSet時顯示或隱式地指定.EnumSet的集合元素也是有序的,EnumSet以枚舉值在Enum類內的定義順序來決定集合元素的順序.
EnumSet在內部以位向量的形式存儲,這種存儲形式非常緊湊,高效,因此EnumSet對象占用內存很小,而且運行效率也很好,尤其是進行批量操作(如調用containsAll()和retainAll()方法時),如果其參數也是Enumset機會,則該批量操作的執行速度非常快.
EnumSet機會不允許加入null元素.
8.3.5 各Set實現類的性能分析
EnumSet性能最好,但只能保存同一個枚舉類
HashSet很快,通常用它.
LinkedSet保持了存入順序,一般操作比HashSet慢,但遍歷時比HashSet快.
TreeSet,只有當需要一個保持排序的Set時,才應該使用TreeSet.
另外,這四個類都是現場不安全的,如果多線程調用,需要用synchronizedSortedSet方法包裝起來.
SortedSet<String> s = Collections.synchronizedSortedSet(new TreeSet<>());
8.4 List集合
List判斷兩個對象相等只要通過equals()方法比較返回true即可.
public static void main(String[] args) { List<Object> books = new ArrayList<>(); // 向books集合中添加4個元素 books.add(new String("輕量級Java EE企業應用實戰")); books.add(new String("瘋狂Java講義")); books.add(new String("瘋狂Android講義")); books.add(new String("瘋狂iOS講義")); // 使用目標類型為Comparator的Lambda表達式對List集合排序 books.sort((o1, o2)->((String)o1).length() - ((String)o2).length()); System.out.println(books); // 使用目標類型為UnaryOperator的Lambda表達式來替換集合中所有元素 // 該Lambda表達式控制使用每個字符串的長度作為新的集合元素 books.replaceAll(ele->((String)ele).length()); System.out.println(books); // 輸出[7, 8, 11, 16] }
public static void main(String[] args) { String[] books = { "瘋狂Java講義", "瘋狂iOS講義", "輕量級Java EE企業應用實戰" }; List<String> bookList = new ArrayList<String>(); for (int i = 0; i < books.length ; i++ ) { bookList.add(books[i]); } ListIterator<String> lit = bookList.listIterator(); while (lit.hasNext()) { System.out.println(lit.next()); lit.add("-------分隔符-------"); } System.out.println("=======下面開始反向迭代======="); while(lit.hasPrevious()) { System.out.println(lit.previous()); } }
public static void main(String[] args) { List<String> fixedList = Arrays.asList("瘋狂Java講義", "輕量級Java EE企業應用實戰"); // 獲取fixedList的實現類,將輸出Arrays$ArrayList System.out.println(fixedList.getClass()); // 使用方法引用遍歷集合元素 fixedList.forEach(System.out::println); // 試圖增加、刪除元素都會引發UnsupportedOperationException異常 fixedList.add("瘋狂Android講義"); fixedList.remove("瘋狂Java講義"); }
8.5 Queue集合
用來模擬隊列,先進先出
8.5.1 PriorityQueue實現類
PriorityQueue保存隊列元素的順序並不是安計入隊列的順序,而是安隊列元素的大小進行重新排序,因此當調用peek()方法或者poll()方法取出隊列中的
元素時,並不是取出最先進入隊列的元素,而是取出隊列中最小的元素.