集合框架的做用:在實際的開發過程當中,咱們常常會對一組相同類型的數據進行統一管理操做,到目前爲止,咱們可使用數組結構、鏈表結構、二叉樹結構來實現。數組最大的問題在於數組中的元素個數是固定的,要實現動態數組,畢竟仍是比較麻煩;本身實現鏈表或二叉樹結構來管理對象更是不方便。因此在JDK1.2版本後,Java完整的提供了類集合的概念,封裝了一組強大的、很是方便的集合框架API,讓咱們在開發中大大的提升了效率前端
集合中分爲三大接口:Collection、Map、Iteratorjava
集合框架的接口和類在java.util包中web
集合框架結構圖:
算法
Collection接口express
Collection層次結構中的根接口。Collection表示一組對象,這些對象也稱爲collection的元素。一些collection容許有重複的元素,而另外一些則不容許。一些collection是有序的,而另外一些則是無序的。JDK不提供此接口的任何直接實現:它提供更具體的子接口(如Set和List)實現。此接口一般用來傳遞collection,並在須要最大廣泛性的地方操做這些collection編程
接口的定義:後端
public interface Collection<E> extends Iterable<E>
List接口:設計模式
Set接口:數組
Map接口緩存
接口的定義:
public interface Map<K, V>
具體的實現類:HashMap、TreeMap、LinkedHashMap和Hashtable
public interface List<E> extends Collection<E> // 有序的 collection(也稱爲序列)。此接口的用戶能夠對列表中每一個元素的插入位置進行精確地控制。用戶能夠根據元素的整數索引(在列表中的位置)訪問元素,並搜索列表中的元素
ArrayList
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable
List接口的大小是可變數組的實現。實現了全部可選列表操做,並容許包括null在內的全部元素。除了實現List接口外,此類還提供了一些方法來操做內部用來存儲列表的數組的大小
示例:
import java.util.ArrayList; import java.util.List; /** * @author xiao兒 * @date 2019/9/1 14:09 * @Description ListDemo * <p> * Collection 接口:用於存儲單個對象的集合 * List接口: * 1.有序的 * 2.容許多個null元素 * 3.具體的實現類:ArrayList、Vector、LinkedList */ public class ArrayListDemo { public static void main(String[] args) { arrayList(); } /** * ArrayList * 1.實現原理:採用動態對象數組實現,默認的構造方法建立了一個空數組 * 2.第一次添加元素,擴充容量爲10,以後的擴充算法:原來數組大小 + 原來數組大小的一半 * 3.不適合進行刪除或者插入操做 * 4.爲了防止數組動態的擴充次數過多,建議建立 ArrayList 時,給定初始容量 * 5.線程不安全,適合在單線程訪問時使用 * JDK1.2開始 */ private static void arrayList() { // 使用集合來存儲多個不一樣類型的元素(對象),那麼在處理時會比較麻煩,在實際開發中,不建議這樣使用 // 在一個集合中存儲相同的類型的對象 List<String> list = new ArrayList<>(); list.add("旺仔"); list.add("真果粒"); list.add("蒙牛"); list.add("銀橋"); // list.add(10); // 遍歷集合 int size = list.size(); for (int i = 0; i < size; i++) { System.out.println(list.get(i)); } System.out.println("旺仔是否存在於list中:" + list.contains("旺仔")); list.remove("銀橋"); System.out.println("list_size:" + list.size()); String[] array = list.toArray(new String[]{}); for (String str : array) { System.out.println(str); } } }
Vector
示例:
import java.util.Vector; /** * @author xiao兒 * @date 2019/9/1 16:46 * @Description VectorDemo */ public class VectorDemo { public static void main(String[] args) { vector(); } /** * Vector * 1.實現原理:採用動態對象數組實現,默認構造方法建立了一個大小爲10的對象數組 * 2.擴充的算法:當增量爲0時,擴充爲原來大小的兩倍,當增量大於0時,擴充爲原來大小+增量 * 3.不適合刪除或插入操做 * 4.爲了防止數組動態擴充次數過多,建議建立 Vector 時給定初始容量 * 5.線程安全,適合在多線程訪問時使用,在單線程下使用效率較低 */ private static void vector() { Vector<String> vector = new Vector<>(); vector.add("旺仔"); vector.add("真果粒"); vector.add("蒙牛"); vector.add("銀橋"); int size = vector.size(); for (int i = 0; i < size; i++) { System.out.println(vector.get(i)); } } }
LinkedList
public class LindedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, Serializable
List接口是鏈表列表實現。實現全部可選的列表的操做,而且容許全部元素(包括null)。除了實現List接口外,LinkedList類還爲在列表的開頭及結尾get、remove和insert元素提供了統一的命名方法
示例:
import java.util.LinkedList; /** * @author xiao兒 * @date 2019/9/1 17:16 * @Description LinkedListDemo */ public class LinkedListDemo { public static void main(String[] args) { linkedList(); } /** * LinkedList * 1.實現原理:採用雙向鏈表結構實現 * 2.適合插入或刪除操做,性能高 * 3.線程不安全 */ private static void linkedList() { LinkedList<String> linkedList = new LinkedList<>(); linkedList.add("旺仔"); linkedList.add("真果粒"); linkedList.add("蒙牛"); linkedList.add("銀橋"); int size = linkedList.size(); for (int i = 0; i < size; i++) { System.out.println(linkedList.get(i)); } } }
如何選擇ArrayList、Vector和LinkedList?
public interface Set<E> extends Collection<E> // 一個不包含重複元素的collection。更確切的說,set不包含知足e1.equals(e2)的元素對e1和e2,而且最多包含一個null元素。正如其名成所暗示的,此接口模仿了數學上的set抽象
HashSet
public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, Serializable
類實現Set接口,有哈希表(其實是一個HashMap實例)支持。它不保證set的迭代順序;特別是它不保證該順序恆久不變。此類容許使用null元素
示例:
// Cat /** * @author xiao兒 * @date 2019/9/1 18:33 * @Description Cat */ public class Cat { private String name; private int age; private int id; public Cat() { } public Cat(String name, int age, int id) { this.name = name; this.age = age; this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public int getId() { return id; } public void setId(int id) { this.id = id; } @Override public String toString() { return "Cat{" + "name='" + name + '\'' + ", age=" + age + ", id=" + id + '}'; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Cat)) return false; Cat cat = (Cat) o; if (age != cat.age) return false; if (id != cat.id) return false; return name != null ? name.equals(cat.name) : cat.name == null; } @Override public int hashCode() { int result = name != null ? name.hashCode() : 0; result = 31 * result + age; result = 31 * result + id; return result; } } // HashSetDemo import java.util.Arrays; import java.util.HashSet; import java.util.Set; /** * @author xiao兒 * @date 2019/9/1 18:03 * @Description HashSetDemo * * Set 接口: * 1.無序的(不保證順序) * 2.不容許重複元素 * 3.能夠存在一個null元素 * 4.具體實現類:HashSet、TreeSet 和 LinkedHashSet */ public class HashSetDemo { public static void main(String[] args) { hashSet(); } /** * HashSet * 1.實現原理:基於哈希表(HashMap)實現 * 2.不容許重複元素,能夠有一個null元素 * 3.不保證順序恆久不變 * 4.添加元素時把元素做爲 HashMap 的key存儲,HashMap的value使用一個固定的Object對象 * 5.排除重複元素是經過equals來檢查對象是否相同 * 6.判斷兩個對象是否相同:先判斷兩個對象的hashCode是否相同(若是兩個對象的hashCode相同,不必定是同一對象,若是不一樣, * 那必定不是同一個對象),若是不一樣則兩個對象不是同一個對象,若是相同,還要進行equals判斷,equals相同則是同一個對象, * 不一樣則不是同一個對象 * 7.自定義對象要認爲屬性值都相同時爲同一個對象,有這種需求時,那麼咱們須要重寫所在類的hashCode和equals方法 * * 小結: * (1)哈希表的存儲結構:數組+鏈表(數組裏的每個元素以鏈表中的形式存儲) * (2)若是把對象存儲到哈希表中,先計算對象的hashCode值,在對數組長度求餘數,來決定對象要存儲在數組中的那個位置 * (3)解決hashSet中的重複值使用的方式是:第6點 */ private static void hashSet() { Set<String> hashSet = new HashSet<>(); hashSet.add("旺仔"); hashSet.add("真果粒"); hashSet.add("蒙牛"); hashSet.add("銀橋"); hashSet.add("旺仔"); System.out.println(hashSet.size()); String[] strings = hashSet.toArray(new String[]{}); for (String s : strings) { System.out.println(s); } System.out.println(Arrays.toString(strings)); Cat cat = new Cat("miaomiao", 5, 1); Cat cat1 = new Cat("huahua", 2, 3); Cat cat2 = new Cat("tom", 4, 2); Cat cat3 = new Cat("miaomiao", 5, 4); Cat cat4 = new Cat("beibei", 3, 3); Set<Cat> catSet = new HashSet<>(); catSet.add(cat); catSet.add(cat1); catSet.add(cat2); catSet.add(cat3); catSet.add(cat4); catSet.add(cat); System.out.println("catSet的長度:" + catSet.size()); for (Cat c : catSet) { System.out.println(c); } System.out.println("cat的hashCode是:" + cat.hashCode() % 16); System.out.println("cat1的hashCode是:" + cat1.hashCode() % 16); System.out.println("cat2的hashCode是:" + cat2.hashCode() % 16); System.out.println("cat3的hashCode是:" + cat3.hashCode() % 16); System.out.println("cat4的hashCode是:" + cat4.hashCode() % 16); } }
hashCode深刻分析:
hashCode()方法,在Object類中定義以下: public native int hashCode(); hashCode()是本地方法,它的實現是根據本地機器相關,固然咱們能夠在本身寫的類中覆蓋hashCode()方法,好比String、Integer、Double...等等這些類都是覆蓋了hashCode()方法的
在Java的集合中,判斷兩個對象是否相等的規則是:
TreeSet
public class TreeSet<E> extends AbstractSet<E> implements NavigableSet<E>, Cloneable, Serializable
基於TreeMap的NavigableSet實現。使用元素的天然順序對元素進行排序,或者根據建立set時提供的Comparator進行排序,具體取決於使用的構造方法
示例:
// CatComparator import java.util.Comparator; /** * @author xiao兒 * @date 2019/9/1 22:05 * @Description CatComparator */ public class CatComparator implements Comparator<Cat> { @Override public int compare(Cat o1, Cat o2) { return o1.getAge() - o2.getAge(); } } // TreeSetDemo import java.util.TreeSet; /** * @author xiao兒 * @date 2019/9/1 21:55 * @Description TreeSetDemo */ public class TreeSetDemo { public static void main(String[] args) { treeSet(); } /** * TreeSet * 1.有序的,基於 TreeMap(二叉樹數據結構),對象須要比較大小,經過對象比較器 Comparator,對象比較器還能夠去除重複元素 * 若是自定義的數據類,沒有實現比較器接口,將沒法添加到 TreeSet 集合中 */ private static void treeSet() { TreeSet<Cat> treeSet = new TreeSet<>(new CatComparator()); Cat cat = new Cat("miaomiao", 5, 1); Cat cat1 = new Cat("huahua", 2, 3); Cat cat2 = new Cat("tom", 3, 2); Cat cat3 = new Cat("miaomiao", 4, 4); Cat cat4 = new Cat("beibei", 3, 3); treeSet.add(cat); treeSet.add(cat1); treeSet.add(cat2); treeSet.add(cat3); treeSet.add(cat4); System.out.println(treeSet.size()); for (Cat c : treeSet) { System.out.println(c); } } }
LinkedHashSet
public class LinkedHashSet<E> extends HashSet<E> implements Set<E>, Cloneable, Serializable
具備可預知迭代順序的Set接口的哈希表和鏈表列表實現。此實現與HashSet的不一樣之處在於,後者維護着一個運行於全部條目的雙重鏈表列表。此連接列表定義了迭代順序,即按照將元素插入到set中的順序(插入順序)進行迭代。注意,插入順序不受在set中從新插入元素的影響。(若是在s.contains(e)返回true後當即調用s.add(e),則元素e會被從新插入到set s中
示例:
import java.util.LinkedHashSet; /** * @author xiao兒 * @date 2019/9/1 22:23 * @Description LinkedHashSetDemo */ public class LinkedHashSetDemo { public static void main(String[] args) { linkedHashSet(); } /** * LinkedHashSet * 1.實現原理:哈希表和鏈表列表實現 */ private static void linkedHashSet() { LinkedHashSet<Cat> cats = new LinkedHashSet<>(); Cat cat = new Cat("miaomiao", 5, 1); Cat cat1 = new Cat("huahua", 2, 3); Cat cat2 = new Cat("tom", 3, 2); Cat cat3 = new Cat("miaomiao", 4, 4); Cat cat4 = new Cat("beibei", 3, 3); cats.add(cat); cats.add(cat1); cats.add(cat2); cats.add(cat3); cats.add(cat4); for (Cat c : cats) { System.out.println(c); } } }<font face="楷體" size=4></font>
如何選擇HashSet、TreeSet和LinkedHashSet?
集合輸出:
示例:
import java.util.*; /** * @author xiao兒 * @date 2019/9/1 23:33 * @Description IteratorDemo */ public class IteratorDemo { public static void main(String[] args) { List<Cat> list = new ArrayList<>(); Cat cat = new Cat("miaomiao", 5, 1); Cat cat1 = new Cat("huahua", 2, 3); Cat cat2 = new Cat("tom", 4, 2); Cat cat3 = new Cat("miaomiao", 5, 4); Cat cat4 = new Cat("beibei", 3, 3); list.add(cat); list.add(cat1); list.add(cat2); list.add(cat3); list.add(cat4); foreach(list); System.out.println("-----------------"); iterator(list); System.out.println("-----------------"); enumeration(); } // foreach(1.5) private static void foreach(Collection<Cat> cats) { for (Cat c : cats) { System.out.println(c); } } // iterator(1.5以前統一的迭代集合方式) private static void iterator(Collection<Cat> cats) { Iterator<Cat> iter = cats.iterator(); while (iter.hasNext()) { System.out.println(iter.next()); } } // enumeartion private static void enumeration() { Vector<String> vector = new Vector<>(); vectorlist.forEach((String s) -> { System.out.println(s); });.add("Tom"); vector.add("Jack"); vector.add("Job"); vector.add("Lily"); Enumeration<String> enumeration = vector.elements(); while (enumeration.hasMoreElements()) { System.out.println(enumeration.nextElement()); } } }
foreach
在使用foreach輸出的時候要注意:建立集合時要指定操做泛型的類型
JDK1.8新特性:
// no.1 list.forEach((String s) -> {System.out.println(s);}); // no.2 list.forEach(s -> {System.out.println(s);}); // no.3 list.forEach(s -> System.out.println(s)); // no.4 list.forEach(System.out::println); // no.5 list.forEach(new MyConsumer());// 本身寫一個類 MyConsumer 實現 Consumer 接口
Consumer<T>接口:消費者接口
import java.util.function.Consumer; /** * @author xiao兒 * @date 2019/9/2 8:31 * @Description ConsumerDemo */ public class ConsumerDemo { public static void main(String[] args) { consumer(); } // 消費者接口 private static void consumer() { strToUpp("xiaoer", str -> System.out.println(str.toUpperCase())); } public static void strToUpp(String str, Consumer<String> consumer) { consumer.accept(str); } }
Function<T,R>接口:表示接受一個參數併產生結果的函數
import java.util.function.Function; /** * @author xiao兒 * @date 2019/9/2 8:21 * @Description FunctionDemo */ public class FunctionDemo { public static void main(String[] args) { function(); } // 表示接受一個參數併產生結果的函數 private static void function() { String s = strToUpp("xiaoer", str -> str.toUpperCase()); System.out.println(s); } public static String strToUpp(String str, Function<String, String> f) { return f.apply(str); } }
Supplier<T>接口:表明結果供應商
import java.util.ArrayList; import java.util.List; import java.util.function.Supplier; /** * @author xiao兒 * @date 2019/9/2 8:40 * @Description SupplierDemo */ public class SupplierDemo { public static void main(String[] args) { supplier(); } // 表明結果供應商 private static void supplier() { List<Integer> list = getNums(10, () -> (int) (Math.random() * 100)); list.forEach((i) -> { System.out.println(i); }); System.out.println("------------"); list.forEach(System.out::println); } public static List<Integer> getNums(int num, Supplier<Integer> supplier) { List<Integer> list = new ArrayList<>(); for (int i = 0; i < num; i++) { list.add(supplier.get()); } return list; } }
Predicate<T>接口:斷言接口
import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.function.Predicate; /** * @author xiao兒 * @date 2019/9/2 8:50 * @Description PredicateDemo */ public class PredicateDemo { public static void main(String[] args) { predicate(); } // 斷言接口 private static void predicate() { List<String> list = Arrays.asList("Lily", "Tom", "Job", "Curly"); List<String> result = filter(list, s -> s.contains("C")); result.forEach(System.out::println); } private static List<String> filter(List<String> list, Predicate<String> predicate) { List<String> result = new ArrayList<>(); for (String s : list) { if (predicate.test(s)) {// 測試是否符合要求 result.add(s); } } return result; } }
什麼是Stream?
咱們能夠把Stream當成一個高級版本的Iterator。原始版本的Iterator,用戶只能一個一個的遍歷元素並對其進行某些操做;高級版本的Stream,用戶只須要對其包含的元素執行什麼操做,好比「過濾掉長度大於10的字符串」、「獲取每一個字符串的首字母」等,具體這些操做如何應用到每一個元素上,就給Stream就行了
示例:
import java.util.Arrays; import java.util.List; import java.util.Optional; import java.util.function.BinaryOperator; import java.util.stream.Collectors; import java.util.stream.Stream; /** * @author xiao兒 * @date 2019/9/2 9:14 * @Description StreamDemo * <p> * Stream接口:不是存儲的數據結構,數據源能夠是一個集合,爲了函數式編程創造 * 惰式執行,數據只能被消費一次 * <p> * 兩種類型的操做方法: * 1.中間操做(生成一個 Stream) * 2.結束操做(執行計算操做) */ public class StreamDemo { public static void main(String[] args) { // foreach方法 Stream<String> stream = Stream.of("good", "good", "study", "day", "day", "up"); // stream.forEach((str) -> { // System.out.println(str); // }); // System.out.println("------------"); // filter // stream.filter((s) -> s.length() > 3).forEach(System.out::println); // System.out.println("----------------"); // distinct // stream.distinct().forEach(s -> System.out.println(s)); // map // stream.map(s -> s.toUpperCase()).forEach(s -> System.out.println(s)); // flatMap // Stream<List<Integer>> num = Stream.of(Arrays.asList(1, 2, 3), Arrays.asList(4, 5)); // num.flatMap(list -> list.stream()).forEach(s -> System.out.println(s)); // reduce // Optional<String> optionalS = stream.reduce((s1, s2) -> s1.length() >= s2.length() ? s1 : s2); // System.out.println(optionalS.get()); // collect List<String> list = stream.collect(Collectors.toList()); list.forEach(s -> System.out.println(s)); // :: 方法的引用 // 引用靜態的方法 Integer::valueOf // 引用對象的方法 list::add // 引用構造方法 Arrayalist::new } }
public interface Map<K, V> // 將鍵映射到值得對象,一個映射不能包含重複的鍵;每一個鍵最多隻能映射到一個值
HashMap
public class HashMap<K, V> extends AbstractMap<K,V> implements Map<K, V>, Cloneable, Serializable
基於哈希表的Map接口的實現。此實現提供全部可選的映射操做,並容許使用null值和null鍵。(除了非同步和容許使用null以外,HashMap類與Hashtable大體相同。)此類不保證映射的順序,特別是它不保證該順序恆久不變
示例:
import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.stream.Stream; /** * @author xiao兒 * @date 2019/9/2 10:00 * @Description HashMapDemo * * Map接口: * 1.鍵值對存儲一組對象 * 2.Key保證惟一,不能重複;Value能夠重複 * 3.具體的實現類:HashMap、TreeMap 和 Hashtable LinkedHashMap */ public class HashMapDemo { public static void main(String[] args) { hashMap(); } /** * HashMap 的實現原理: * 1.基於哈希表(數組+鏈表+二叉樹(紅黑樹)) * 2.默認負載因子:0.75,默認數組大小是16 * 3.把對象存儲到哈希表中,如何存儲? * 把key對象經過hash方法計算哈希值,而後用哈希值對數組長度取餘(默認是16),來決定該key對象在數組中存儲的位置, * 當這個位置有多個對象時,以鏈表存儲,JDK1.8後,當鏈表長度大於8時,鏈表將轉換爲二叉樹(紅黑樹) * 這樣的目的:爲了取值更快,存儲的數據量越大,性能的表現越明顯 * 4.擴充原理:當數組的容量超過了75%,那麼表示該數組須要擴充,如何擴充? * 擴充的算法:當前的數組容量<<1(至關因而乘以2),擴大1倍,擴充次數過多會影響性能,每次擴充表示哈希表從新散列 * (從新計算每一個對象的存儲位置),咱們在開發中儘可能要減小擴充次數帶來的性能問題 * 5.線程不安全,適合在單線程中使用 */ private static void hashMap() { Map<Integer, String> map = new HashMap<>(); map.put(1, "Tom"); map.put(2, "Jack"); map.put(3, "Lily"); map.put(4, "Bin"); System.out.println("size=" + map.size()); // 從map中取值 System.out.println(map.get(1)); System.out.println("------------"); // map的遍歷 Set<Map.Entry<Integer, String>> entrySet = map.entrySet(); for (Map.Entry e : entrySet) { System.out.println(e.getKey() + "->" + e.getValue()); } System.out.println("------------"); // keySet:遍歷鍵,能夠經過鍵查找值 Set<Integer> keys = map.keySet(); for (Integer i : keys) { String value = map.get(i); System.out.println(i + "->" + value); } System.out.println("------------"); // values:遍歷值,不能經過值查找鍵 Collection<String> values = map.values(); for (String s : values) { System.out.println(s); } System.out.println("------------"); // foreach map.forEach((key, value) -> System.out.println(key + "->" + value)); System.out.println(map.containsKey(7)); System.out.println("------------"); // hash Integer key = 1314; int h; int hashCode = (key.hashCode()); int hash = (h = key.hashCode()) ^ (h >>> 16); int count = hash & 15; System.out.println(hashCode); System.out.println(hash); System.out.println(count); } }
TreeMap
public class TreeMap<K, V> extends AbstractMap<K, V> implements NavigableMap<K, V>, Cloneable, Serializable
基於紅黑樹(Red-Black tree)的NavigableMap實現。該映射根據其鍵的天然順序進行排序,或者根據建立映射時提供的Comparator進行排序,具體取決於使用的構造方法
示例:
// Dog /** * @author xiao兒 * @date 2019/9/2 18:13 * @Description Dog */ public class Dog { private int id; private String name; private int age; public Dog() { } public Dog(int id, String name, int age) { this.id = id; this.name = name; this.age = age; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Dog{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}'; } } // DogComparator import java.util.Comparator; /** * @author xiao兒 * @date 2019/9/2 18:17 * @Description DogComparator */ public class DogComparator implements Comparator<Dog> { @Override public int compare(Dog o1, Dog o2) { return o1.getId() - o2.getId(); } } // TreeMapDemo import java.util.Map; import java.util.TreeMap; /** * @author xiao兒 * @date 2019/9/2 18:09 * @Description TreeMapDemo */ public class TreeMapDemo { public static void main(String[] args) { treeMap(); } /** * TreeMap * 1.基於二叉樹的紅黑樹實現 */ private static void treeMap() { Map<String, String> map = new TreeMap<>(); map.put("one", "Lily"); map.put("two", "Tom"); map.put("three", "Bin"); map.forEach((key, value) -> System.out.println(key + "->" + value)); System.out.println("---------------"); Map<Dog, String> dogs = new TreeMap<>(new DogComparator()); dogs.put(new Dog(1, "二哈", 3), "dog1"); dogs.put(new Dog(2, "三哈", 2), "dog2"); dogs.put(new Dog(3, "四哈", 4), "dog3"); dogs.forEach((dog, value) -> System.out.println(dog + "->" + value)); } }
Hashtable
public class Hashtable<K, V> extends Dictionary<K, V> implements Map<K, V>, Cloneable, Serializable
此類實現一個哈希表,該哈希表將鍵映射到相應的值。任何非null對象均可以用做鍵或值。爲了成功地在哈希表中存儲和獲取對象,用做鍵的對象必須實現hashCode方法和equals方法
示例:
import java.util.Hashtable; import java.util.Map; /** * @author xiao兒 * @date 2019/9/2 17:34 * @Description Hashtable */ public class HashtableDemo { public static void main(String[] args) { hashtable(); } /** * Hashtable * 1.JDK1.0開始 * 2.基於哈希表實現(數組+鏈表) * 3.默認數組大小是11,加載因子0.75 * 4.擴充方式:原數組大小<<1(*2) + 1 * 5.線程安全的,用在多線程訪問時 */ private static void hashtable() { Map<String, String> hashtable = new Hashtable<>(); hashtable.put("one", "Lily"); hashtable.put("two", "Tom"); hashtable.put("three", "Bin"); hashtable.forEach((key, value) -> System.out.println(key + "->" + value)); } }
LinkedHashMap
public class LinkedHashMap<K, V> extends HashMap<K, V> implements Map<K, V>
Map接口的哈希表和連接列表實現,具備可預知的迭代順序。此實現與HashMap的不一樣之處在於,後者維護着一個運行於全部條目的雙重連接列表
示例:
import java.util.LinkedHashMap; import java.util.Map; /** * @author xiao兒 * @date 2019/9/2 17:59 * @Description LinkedHashMapDemo */ public class LinkedHashMapDemo { public static void main(String[] args) { linkedHashMap(); } /** * LinkedHashMap * 1.LinkedHashMap 是 HashMap 的子類,因爲 HashMap 不能保證順序恆久不變,此類使用雙重鏈表來維護元素添加的順序 */ private static void linkedHashMap() { Map<String, String> map = new LinkedHashMap<>(); map.put("one", "Lily"); map.put("two", "Tom"); map.put("three", "Bin"); map.forEach((key, value) -> { System.out.println(key + "->" + value); }); } }
JDK1.8Map新特性
Map接口中的新方法:在JDK1.8中新增了許多default方法
示例:
import java.util.HashMap; import java.util.Map; /** * @author xiao兒 * @date 2019/9/2 18:38 * @Description MapNewMethodDemo */ public class MapNewMethodDemo { public static void main(String[] args) { Map<Integer, String> map = new HashMap<>(); map.put(1, "Jack"); map.put(2, "Tom"); map.put(3, "Lily"); String str = map.getOrDefault(4, "null"); System.out.println(str); System.out.println("---------------"); // String val = map.put(3, "Vince"); // 只會添加不存在相同key的值 String val = map.putIfAbsent(3, "Vince"); System.out.println(val); map.forEach((key, value) -> System.out.println(key + "->" + value)); System.out.println("---------------"); // 根據鍵和值都匹配時纔會刪除 boolean b = map.remove(1, "Lily"); System.out.println("是否刪除:" + b); System.out.println("----------------"); // 替換 String string = map.replace(3, "Vince"); System.out.println(string); map.forEach((key, value) -> System.out.println(key + "->" + value)); System.out.println("-----------------"); // 替換 boolean b1 = map.replace(3, "Vince", "Lily"); System.out.println("是否替換成功:" + b1); System.out.println("------------------"); String string1 = map.compute(1, (key, value) -> value + "1"); System.out.println(string1); System.out.println("-------------------"); String string2 = map.computeIfAbsent(4, value -> value + "test"); System.out.println(string2); System.out.println("-------------------"); String string3 = map.merge(1, "888", (oldValue, newValue) -> oldValue.concat(newValue)); System.out.println(string3); } }
排序操做(主要針對List接口相關)
// 反轉指定List集合中元素的順序 reverse(List list); // 對List中的元素進行隨機排序(洗牌) shuffle(List list); // 對List裏的元素根據天然升序排序 sort(List list); // 自定義比較器進行排序 sort(List list, Comparator c); // 將指定List集合中i處的元素和j處元素進行交換 swap(List list, int i, int j); // 將全部元素向右移位指定長度,若是distance等於size那麼結果不變 rotate(List list, int distance);
查找和替換(主要針對Collection接口相關)
// 使用二分搜索法,以得到指定對象在List中的索引,前提是集合已經排序 binarySearch(List list, Object key); // 返回最大元素 max(Collection coll); // 根據自定義比較器,返回最大元素 max(Collection coll, Comparator comp); // 返回最小元素 min(Collection coll); // 根據自定義比較器,返回最小元素 min(Collection coll, Comparator comp); // 使用指定對象填充 fill(List list, Object obj); // 返回指定集合中指定對象出現的次數 frequency(Collection Object o); // 替換 replaceAll(List list, Object old, Object new);
同步控制
設置不可變集合:Collections有三類方法可返回一個不可變集合
// 返回一個空的不可變的集合對象 emptyXxx(); // 返回一個只包含指定對象的,不可變的集合對象 singletonXxx(); // 返回指定集合對象的不可變視圖 unmodifiableXxx();
其餘
// 若是兩個指定collection中沒有相同的元素,則返回true disjoint(Collection<?> c1, Collection<?> c2); // 一種方便的方式,將全部指定元素添加到指定collection中 addAll(Collection<? super T> c, T...a); // 返回一個比較器,它強行反轉指定比較器的順序。若是指定比較器爲null,則此方法等同於reverseOrder()(換句話說,它返回一個比較器,該比較器將強行反轉實現Comparable接口那些對象collection上的天然順序) Comparator<T> reverseOrder(Comparator<T> cmp);
這是一個能夠爲null的容器對象。若是值存在則isPresent()方法會返回true,調用get()方法會返回該對象
// 爲非null的值建立一個Optional of // 爲指定的值建立一個Optional,若是指定的值爲null,則返回一個空的Optional ofNUllable // 若是值存在返回true,不然返回false isPresent // 若是Optional有值則將其返回,不然拋出NoSuchElementException get // 若是Optional實例有值則爲其調用consumer,不然不作處理 ifPresent // 若是有值則將其返回,不然返回指定的其餘值 orElse // orElseGet與orElse方法相似,區別在於獲得的默認值。orElse方法將傳入的字符串做爲默認值,orElseGet方法能夠給接受Supplier接口的實現用來生成默認值 orElseGet // 若是有值則將其返回,不然拋出supplier接口建立的異常 orElseThrow // 若是有值,則對其執行調用mapping函數獲得返回值。若是返回值不爲null,則建立包含mapping返回值的Optional做爲map方法返回值,不然返回空Optional map // 若是有值,爲其執行mapping函數返回Optional類型返回值,不然返回空Optional。flatMap與map(Function)方法相似,區別在於flatMap中的mapper返回值必須是Optional。調用結束時,flatMap不會對結果用Optional封裝 flatMap // 若是有值而且知足斷言條件返回包含該值的Optional,不然返回空Optional filter
示例:
import java.util.Optional; import java.util.stream.Stream; /** * @author xiao兒 * @date 2019/9/3 7:50 * @Description OptionalDemo */ public class OptionalDemo { public static void main(String[] args) { // 建立 Optional 對象的方式 Optional<String> optional = Optional.of("Bin"); Optional<String> optional2 = Optional.ofNullable("Bin"); Optional<String> optional3 = Optional.empty(); System.out.println(optional.isPresent()); System.out.println(optional.get()); optional.ifPresent(value -> System.out.println(value)); System.out.println(optional.orElse("nihao")); System.out.println(optional.orElseGet(() -> "default")); // try { // System.out.println(optional3.orElseThrow(Exception::new)); // } catch (Exception e) { // e.printStackTrace(); // } Optional<String> optional4 = optional.map((value) -> value.toUpperCase()); System.out.println(optional4.orElse("沒有")); Optional<String> optional5 = optional.flatMap((value) -> Optional.of(value.toUpperCase())); System.out.println(optional5.orElse("無")); Optional<String> optional6 = optional.filter((value) -> value.length() > 3); System.out.println(optional6.orElse("長度小於等於3")); } }
Queue
隊列(Queue)是一種特殊的線性表,是一種先進先出(FIFO)的數據結構。它只容許在表的前端front進行刪除操做,而在表的後端rear進行插入操做。進行插入操做的端稱爲隊尾,進行刪除操做的端稱爲對頭。隊列中沒有元素時,稱爲空隊列
示例:
import java.util.LinkedList; import java.util.Queue; /** * @author xiao兒 * @date 2019/9/3 8:14 * @Description QueueDemo * <p> * Queue接口:隊列,是一種先進先出的線性數據結構 * LinkedList 類實現了 Queue 接口 * 請求隊列,消息隊列 */ public class QueueDemo { public static void main(String[] args) { queue(); } private static void queue() { Queue<String> queue = new LinkedList<>(); queue.add("Tom"); queue.add("Lily"); queue.add("Job"); queue.add("Jack"); System.out.println(queue.size()); // 取出對頭,但並不刪除 System.out.println(queue.peek()); System.out.println(queue.size()); // 移除對頭 System.out.println(queue.poll()); System.out.println(queue.size()); System.out.println(queue); } }
Deque
一個線性collection,支持在兩端插入和移除元素。此接口既支持有容量限制的雙端隊列,也支持沒有固定大小限制的雙端隊列
示例:
import java.util.Deque; import java.util.LinkedList; /** * @author xiao兒 * @date 2019/9/3 8:25 * @Description DequeDemo * * Deque接口:雙端隊列 */ public class DequeDemo { public static void main(String[] args) { deque(); } private static void deque() { Deque<String> deque = new LinkedList<>(); deque.add("Tom"); deque.add("Job"); deque.add("Jack"); deque.add("Bin"); System.out.println(deque.size()); System.out.println(deque.getFirst()); System.out.println(deque.getLast()); System.out.println(deque.peekFirst()); System.out.println(deque.peekLast()); } }
Stack
示例:
import java.util.Stack; /** * @author xiao兒 * @date 2019/9/3 8:35 * @Description StackDemo * * Stack類:棧,先進後出的線性數據結構 */ public class StackDemo { public static void main(String[] args) { stack(); } private static void stack() { Stack<String> stack = new Stack<>(); // 壓棧 stack.push("Bin"); stack.push("Jack"); stack.push("Job"); stack.push("Tom"); System.out.println(stack.peek()); System.out.println(stack.size()); System.out.println(stack.pop()); System.out.println(stack.size()); } }
一對多關係示例:
// Teacher類 import java.util.HashSet; /** * @author xiao兒 * @date 2019/9/3 8:53 * @Description Teacher * * one */ public class Teacher { private String name; private int age; private String sex; private HashSet<Student> students = new HashSet<>(); public Teacher() { } public Teacher(String name, int age, String sex) { this.name = name; this.age = age; this.sex = sex; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public HashSet<Student> getStudents() { return students; } public void setStudents(HashSet<Student> students) { this.students = students; } @Override public String toString() { return "Teacher{" + "name='" + name + '\'' + ", age=" + age + ", sex='" + sex + '\'' + '}'; } } // Student類 /** * @author xiao兒 * @date 2019/9/3 8:54 * @Description Student * * many */ public class Student { private String name; private int age; private String sex; private Teacher teacher; public Student() { } public Student(String name, int age, String sex) { this.name = name; this.age = age; this.sex = sex; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public Teacher getTeacher() { return teacher; } public void setTeacher(Teacher teacher) { this.teacher = teacher; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", sex='" + sex + '\'' + '}'; } } // OneToManyDemo /** * @author xiao兒 * @date 2019/9/3 8:53 * @Description OneToManyDemo */ public class OneToManyDemo { public static void main(String[] args) { Teacher teacher = new Teacher("張老師", 18, "女"); Student student = new Student("Tom", 13, "男"); Student student1 = new Student("Job", 12, "男"); Student student2 = new Student("Lily", 11, "女"); // 關聯關係 teacher.getStudents().add(student); teacher.getStudents().add(student1); teacher.getStudents().add(student2); student.setTeacher(teacher); student1.setTeacher(teacher); student2.setTeacher(teacher); print(teacher); } private static void print(Teacher teacher) { System.out.println(teacher.getName()); for (Student student : teacher.getStudents()) { System.out.println(student); } } }
多對多關係:通常以一箇中間類,將一個多對多分解爲兩個一對多關係
Guava工程包含了若干被Google的Java項目普遍依賴的核心庫,例如:集合[collections]、緩存[caching]、原生類型支持[primitives support]、併發庫[concurrency libraries]、通用註解[common annotations]、字符串處理[string processing]、I/O等等
對JDK的擴展:
使用舉例:
示例:
import java.text.SimpleDateFormat; import java.util.*; import com.google.common.base.Function; import com.google.common.base.Functions; import com.google.common.collect.*; import com.google.common.collect.Table.Cell; import org.junit.Test; /** * @author xiao兒 * @date 2019/9/3 10:01 * @Description GuavaDemo */ public class GuavaDemo { /** * 設置只讀 */ @Test public void testGuava1() { System.out.println("test Guava1"); // List<String> list = Arrays.asList("Tom", "Lily", "Bin", "Jack"); // list.add("Job"); List<String> list = new ArrayList<>(); list.add("Jack"); list.add("Tom"); list.add("Lily"); list.add("Bin"); // List<String> readList = Collections.unmodifiableList(list); // readList.add("Vince"); // ImmutableList<String> iList = ImmutableList.of("Jack", "Lily", "Tom", "Bin"); // iList.add("Job"); } /** * 過濾器 */ @Test public void testGuava2() { List<String> list = Lists.newArrayList("Java", "H5", "JavaScript", "Python", "PHP"); Collection<String> result = Collections2.filter(list, (e) -> e.startsWith("J")); result.forEach((value) -> System.out.println(value)); } /** * 轉換 */ @Test public void testGuava3() { Set<Long> timeSet = Sets.newHashSet(20121212L, 20190901L, 20180808L); Collection<String> timeCollection = Collections2.transform(timeSet, (e) -> new SimpleDateFormat("yyyy-MM-dd").format(e)); timeCollection.forEach(System.out::println); } /** * 組合式函數編程 */ @Test public void testGuava4() { List<String> list = Lists.newArrayList("Java", "H5", "JavaScript", "Python", "PHP"); Function<String, String> function = new Function<String, String>() { @Override public String apply(String input) { return input.length() > 4 ? input.substring(0, 4) : input; } }; Function<String, String> function1 = new Function<String, String>() { @Override public String apply(String input) { return input.toUpperCase(); } }; Function<String, String> function2 = Functions.compose(function, function1); Collection<String> collection = Collections2.transform(list, function2); collection.forEach(System.out::println); } /** * 加入約束:非空、長度驗證 */ @Test public void testGuava5() { // Set<String> set = Sets.newHashSet(); // 14版本可用 // Constraint<String> constraint = new Constraint<>() { // @Override // public String checkElement(String element) { // // } // }; // Preconditions.checkArgument(expression); // Preconditions.checkNotNull(reference); } /** * 集合操做:交集、差集、並集 */ @Test public void testGuava6() { Set<Integer> set = Sets.newHashSet(1, 2, 3); Set<Integer> set1 = Sets.newHashSet(3, 4, 5); // 交集 Sets.SetView<Integer> view = Sets.intersection(set, set1); view.forEach(System.out::println); System.out.println("----------------"); // 差集 Sets.SetView<Integer> view1 = Sets.difference(set, set1); view1.forEach(System.out::println); System.out.println("----------------"); // 並集 Sets.SetView<Integer> view2 = Sets.union(set, set1); view2.forEach(System.out::println); } /** * Multiset:無序可重複 */ @Test public void testGuava7() { String s = "good good study day day up"; String[] strings = s.split(" "); HashMultiset<String> hashSet = HashMultiset.create(); for (String str : strings) { hashSet.add(str); } Set<String> set = hashSet.elementSet(); for (String str : set) { System.out.println(str + ":" + hashSet.count(str)); } } /** * Multimap:key能夠重複 */ @Test public void testGuava8() { Map<String, String> map = new HashMap<>(); map.put("Java從入門到放棄", "Bin"); map.put("Android從入門到放棄", "Bin"); map.put("PHP從入門到放棄", "Jack"); map.put("笑看人生", "Job"); Multimap<String, String> multimap = ArrayListMultimap.create(); Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry<String, String> entry = iterator.next(); multimap.put(entry.getValue(), entry.getKey()); } Set<String> keySet = multimap.keySet(); for (String key : keySet) { Collection<String> value = multimap.get(key); System.out.println(key + "->" + value); } } /** * BiMap:雙向Map(bidirectional Map)鍵與值不能重複 */ @Test public void testGuave9() { BiMap<String, String> map = HashBiMap.create(); map.put("finally_test", "1820232384233"); map.put("bin_test", "23234342343"); map.put("tom_test", "4324334234234"); String name = map.inverse().get("4324334234234"); System.out.println(name); System.out.println(map.inverse().inverse() == map); } /** * 雙鍵的Map-->Table-->rowKey + columnKey + value */ @Test public void testGuava10() { Table<String, String, Integer> table = HashBasedTable.create(); table.put("Jack", "Java", 80); table.put("Tom", "Python", 90); table.put("Bin", "PHP", 70); table.put("Lily", "JavaScript", 30); Set<Cell<String, String, Integer>> cells = table.cellSet(); for (Cell c : cells) { System.out.println(c.getRowKey() + "-" + c.getColumnKey() + "-" + c.getValue()); } } }
注意:guava開源包下載地址:guava下載