經過不斷的學習
博主更新了Java進階高級第二天的知識
歡迎大家與我一起交流學習哦
目錄
3.2 Comparable和Comparator兩個接口的區別
1. List集合
java.util.List
接口繼承自 Collection
接口,是單列集合的一個重要分支,習慣性地會將實現了 List
接口的對象稱爲 List
集合。在 List
集合中允許出現重複的元素,所有的元素是以一種線性方式進行存儲的,在程序中可以通過索引來訪問集合中的指定元素。另外, List
集合還有一個特點就是元素有序,即元素的存入順序和取出順序一致。
List
接口特點:
-
它是一個元素存取有序的集合。
-
它是一個帶有索引的集合,通過索引就可以精確的操作集合中的元素。
-
集合中可以有重複的元素,通過元素的
equals
方法,來比較是否爲重複的元素。
List
常用方法:
-
public void add(int index, E element)
: 將指定的元素,添加到該集合中的指定位置上。 -
public E get(int index)
:返回集合中指定位置的元素。 -
public E remove(int index)
: 移除列表中指定位置的元素, 返回的是被移除的元素。 -
public E set(int index, E element)
:用指定元素替換集合中指定位置的元素,返回值的更新前的元素。
1.1 ArrayList集合
java.util.ArrayList
集合數據存儲的結構是數組結構。元素增刪慢,查找快,由於日常開發中使用最多的功能爲查詢數據、遍歷數據,所以 ArrayList
是最常用的集合。
1.2 LinkedList集合
java.util.LinkedList
集合數據存儲的結構是鏈表結構。方便元素添加、刪除的集合。
LinkedList
常用方法:
-
public void addFirst(E e)
:將指定元素插入此列表的開頭。 -
public void addLast(E e)
:將指定元素添加到此列表的結尾。 -
public E getFirst()
:返回此列表的第一個元素。 -
public E getLast()
:返回此列表的最後一個元素。 -
public E removeFirst()
:移除並返回此列表的第一個元素。 -
public E removeLast()
:移除並返回此列表的最後一個元素。 -
public E pop()
:從此列表所表示的堆棧處彈出一個元素。 -
public void push(E e)
:將元素推入此列表所表示的堆棧。 -
public boolean isEmpty()
:如果列表不包含元素,則返回true。
1.3 List集合元素替換
代碼實現: List
集合元素替換
public class ListTest {
public static void main(String[] args) {
// 創建List集合對象
List<String> list = new ArrayList<>();
// 存入數據
list.add("張三");
list.add("李四");
list.add("王五");
list.add("二麻子");
list.add("老王");
// 遍歷集合,找到"老王",將其替換爲"隔壁老王"
// 利用普通for循環遍歷List集合
for(int i = 0;i<list.size();i++) {
// 獲取當前元素
String thisName = list.get(i);
// 如果當前元素是"老王"
if("老王".equals(thisName)) {
// 將其改爲"隔壁老王"
list.set(i, "隔壁老王");
}
}
System.out.println(list);
}
}
2. Set接口
java.util.Set
接口和 java.util.List
接口一樣,同樣繼承自 Collection
接口,它與 Collection
接口中的方法基本一致,並沒有對 Collection
接口進行功能上的擴充,只是比 Collection
接口更加嚴格了。與 List
接口不同的是, Set
接口中元素無序,並且都會以某種規則保證存入的元素不出現重複。
Set
集合有多個子類,這裏我們介紹其中的 java.util.HashSet
、 java.util.LinkedHashSet
這兩個集合。
2.1 HashSet集合
java.util.HashSet
是 Set
接口的一個實現類,它所存儲的元素是不可重複的,並且元素都是無序的(即存取順序不一致)。 java.util.HashSet
底層的實現其實是一個 java.util.HashMap
支持。
HashSet
是根據對象的哈希值來確定元素在集合中的存儲位置,因此具有良好的存取和查找性能。保證元素唯一性的方式依賴於: hashCode
與 equals
方法。
2.2 HashSet集合存儲結構(哈希表)
在JDK1.8之前,哈希表底層採用【數組+鏈表】實現,即使用鏈表處理衝突,同一 hash
值的鏈表都存儲在一個鏈表裏。但是當位於一個桶中的元素較多,即 hash
值相等的元素較多時,通過 key
值依次查找的效率較低。而JDK1.8中,哈希表存儲採用【數組+鏈表+紅黑樹】實現,當鏈表長度超過閾值8時,將鏈表轉換爲紅黑樹,這樣大大減少了查找時間。 如下圖:
2.3 HashSet存儲自定義類型元素
給 HashSet
中存放自定義類型元素時,需要重寫對象中的 hashCode
和 equals
方法,建立自己的比較方式,才能保證 HashSet
集合中的對象唯一。
代碼實現:重寫 equals
方法和 hashCode
方法
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
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;
}
// 重寫equals()方法
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Student student = (Student) o;
return age == student.age &&
Objects.equals(name, student.name);
}
// 重寫hashCode()方法
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
2.4 LinkedHashSet類
在 HashSet
下面有一個子類 java.util.LinkedHashSet
,它是鏈表和哈希表組合的一個數據存儲結構。能夠保證存放進去的元素有序且唯一。
代碼實現:使用 LinkedHashSet
子類實例
public class LinkedHashSetTest {
public static void main(String[] args) {
// 創建LinkedHashSet
LinkedHashSet<String> Set = new LinkedHashSet<String>();
// 使用add方法添加元素到LinkedHashSet
Set.add("玩家1");
Set.add("玩家1");
Set.add("玩家2");
Set.add("玩家1");
Set.add("玩家3");
Set.add("玩家4");
// 使用迭代器獲取LinkedHashSet中的元素
Iterator<String> iterator = Set.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
// 使用增強for獲取LinkedHashSet中的元素
for (String string : Set) {
System.out.println(string);
}
}
}
2.5 可變參數
在JDK1.5之後,如果我們定義一個方法需要接受多個參數,並且多個參數類型一致,我們可以對其簡化成如下兩種格式:
修飾符 返回值類型 方法名(參數類型... 形參名){ }
修飾符 返回值類型 方法名(參數類型[] 形參名){ }
3. Collections
java.utils.Collections
是集合工具類,用來對集合進行操作。部分方法如下:
-
public static <T> boolean addAll(Collection<T> c, T... elements)
:往集合中添加一些元素。 -
public static void shuffle(List<?> list)
:打亂集合順序。 -
public static <T> void sort(List<T> list)
:將集合中元素按照默認規則排序。 -
public static <T> void sort(List<T> list,Comparator<? super T> )
:將集合中元素按照指定規則排序。
3.1 Comparator比較器
public static <T> void sort(List<T> list)
:將集合中元素按照默認規則排序。
說到排序了,簡單的說就是兩個對象之間比較大小,那麼在JAVA中提供了兩種比較實現的方式,一種是比較死板的採用 java.lang.Comparable
接口去實現,一種是靈活的當我需要做排序的時候在去選擇的 java.util.Comparator
接口完成。
代碼實現:使用 Comparator
接口排序字符串
public class CollectionsDemo {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("cba");
list.add("aba");
list.add("sba");
list.add("nba");
//排序方法
Collections.sort(list);
System.out.println(list);
}
}
public int compare(String o1, String o2)
:比較其兩個參數的順序。
兩個對象比較的結果有三種:大於,等於,小於。
如果要按照升序排序,則o1 小於o2,返回(負數),相等返回0,o1大於o2返回(正數)
如果要按照降序排序,則o1 小於o2,返回(正數),相等返回0,o1大於o2返回(負數)
代碼實現:使用 compare
方法排序字符串
public class CollectionsDemo {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("cba");
list.add("aba");
list.add("sba");
list.add("nba");
// 排序方法:按照單詞的第一個字母降序排列
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o2.charAt(0) - o1.charAt(0);
}
});
System.out.println(list);
}
}
3.2 Comparable和Comparator兩個接口的區別
Comparable:強行對實現它的每個類的對象進行整體排序。這種排序被稱爲類的自然排序,類的 compareTo
方法被稱爲它的自然比較方法。只能在類中實現 compareTo()
一次,不能經常修改類的代碼實現自己想要的排序。實現此接口的對象列表(和數組)可以通過 Collections.sort
或 Arrays.sort
進行自動排序,對象可以用作有序映射中的鍵或有序集合中的元素,無需指定比較器。
Comparator:強行對某個對象進行整體排序。可以將 Comparator
傳遞給 sort
方法(如 Collections.sort
或 Arrays.sort
),從而允許在排序順序上實現精確控制。還可以使用 Comparator
來控制某些數據結構(如有序 set
或有序映射)的順序,或者爲那些沒有自然順序的對象 collection
提供排序。
4. Map集合
現實生活中,我們常會看到這樣的一種集合:IP地址與主機名,身份證號與個人,系統用戶名與系統用戶對象等,這種一一對應的關係,就叫做映射。Java提供了專門的集合類用來存放這種對象關係的對象,即 java.util.Map
接口。
通過查看 Map
接口描述,發現 Map
接口下的集合與 Collection
接口下的集合,它們存在的不同如下:
-
Collection
中的集合,元素是孤立存在的(理解爲單身),向集合中存儲元素採用一個個元素的方式存儲。 -
Map
中的集合,元素是成對存在的(理解爲夫妻)。每個元素由鍵與值兩部分組成,通過鍵可以找對所對應的值。 -
Collection
中的集合稱爲單列集合,Map
中的集合稱爲雙列集合。 -
Map
中的集合不能包含重複的鍵,值可以重複;每個鍵只能對應一個值。
4.1 Map常用子類
-
HashMap<K,V>:存儲數據採用的哈希表結構,元素的存取順序不能保證一致。由於要保證鍵的唯一、不重複,需要重寫鍵的
hashCode()
方法與equals()
方法。 -
LinkedHashMap<K,V>:
HashMap
下有個子類LinkedHashMap
,存儲數據採用的哈希表結構+鏈表結構。通過鏈表結構可以保證元素的存取順序一致;通過哈希表結構可以保證的鍵的唯一、不重複,需要重寫鍵的hashCode()
方法、equals()
方法。
4.2 Map接口中的常用方法
Map
接口中定義了很多方法,常用的如下:
-
public V put(K key, V value)
: 把指定的鍵與指定的值添加到Map
集合中。 -
public V remove(Object key)
: 把指定的鍵所對應的鍵值對元素 在Map
集合中刪除,返回被刪除元素的值。 -
public V get(Object key)
:根據指定的鍵,在Map
集合中獲取對應的值。 -
boolean containsKey(Object key)
:判斷集合中是否包含指定的鍵。 -
public Set<K> keySet()
: 獲取Map
集合中所有的鍵,存儲到Set
集合中。 -
public Set<Map.Entry<K,V>> entrySet()
: 獲取到Map
集合中所有的鍵值對對象的集合(Set
集合)。
4.3 Map集合遍歷鍵找值方式
鍵找值方式:即通過元素中的鍵,獲取鍵所對應的值。步驟如下:
-
獲取
Map
中所有的鍵,由於鍵是唯一的,所以返回一個Set
集合存儲所有的鍵。方法提示:keyset()
-
遍歷鍵的
Set
集合,得到每一個鍵。 -
根據鍵,獲取鍵所對應的值。方法提示:
get(K key)
代碼實現: Map
集合遍歷鍵找值方式
public class MapDemo {
public static void main(String[] args) {
// 創建Map集合對象
HashMap<String, String> map = new HashMap<String,String>();
// 添加元素到集合
map.put("1529***5693", "玩家1");
map.put("1624***9642", "玩家2");
map.put("1486***5682", "玩家3");
// 獲取所有的鍵、鍵集
Set<String> keys = map.keySet();
// 遍歷鍵集,得到每一個鍵
for (String key : keys) {
String value = map.get(key);
System.out.println(key+"的對應值是:"+value);
}
}
}
4.4 Entry鍵值對對象
Map
中存放的是兩種對象,一種稱爲key(鍵),一種稱爲value(值),它們在 Map
中是一一對應關係,這一對對象又稱做 Map
中的一個 Entry(項)
。 Entry
將鍵值對的對應關係封裝成了對象。即鍵值對對象,這樣我們在遍歷 Map
集合時,就可以從每一個鍵值對 (Entry)
對象中獲取對應的鍵與對應的值。獲取對應鍵和對應值得方法:
-
public K getKey()
:獲取Entry
對象中的鍵。 -
public V getValue()
:獲取Entry
對象中的值。 -
public Set<Map.Entry<K,V>> entrySet()
: 獲取到Map
集合中所有的鍵值對對象的集合(Set
集合)。
4.5 Map集合遍歷鍵值對方式
鍵值對方式:即通過集合中每個鍵值對 (Entry)
對象,獲取鍵值對 (Entry)
對象中的鍵與值。操作步驟如下:
-
獲取
Map
集合中,所有的鍵值對(Entry)
對象,以Set
集合形式返回。方法提示:entrySet()
-
遍歷包含鍵值對
(Entry)
對象的Set
集合,得到每一個鍵值對(Entry)
對象。 -
通過鍵值對
(Entry)
對象,獲取(Entry)
對象中的鍵與值。 方法提示:getkey() getValue()
代碼實現:獲取鍵值對 (Entry)
對象中的鍵與值
public class MapDemo {
public static void main(String[] args) {
// 創建Map集合對象
HashMap<String, String> map = new HashMap<String,String>();
// 添加元素到集合
map.put("1685***5203", "玩家1");
map.put("1695***7512", "玩家2");
map.put("1575***5623", "玩家3");
// 獲取所有的entry對象
Set<Entry<String,String>> entrySet = map.entrySet();
// 遍歷得到每一個entry對象
for (Entry<String, String> entry : entrySet) {
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key+"的對應值是:"+value);
}
}
}
4.6 LinkedHashMap
-
當給
HashMap
中存放自定義對象時,如果自定義對象作爲key
存在,這時要保證對象唯一,必須複寫對象的hashCode
和equals
方法。 -
如果要保證
map
中存放的key
和取出的順序一致,可以使用java.util.LinkedHashMap
集合來存放。
5. 異常
-
異常 :指的是程序在執行過程中,出現的非正常的情況,最終會導致JVM的非正常停止。
在Java等面向對象的編程語言中,異常本身是一個類,產生異常就是創建異常對象並拋出了一個異常對象。Java處理異常的方式是中斷處理。
5.1 異常體系
異常機制其實是幫助我們找到程序中的問題,異常的根類是 java.lang.Throwable
,其下有兩個子類: java.lang.Error
與 java.lang.Exception
,平常所說的異常指 java.lang.Exception
。
Throwable體系:
-
Error:嚴重錯誤
Error
,無法通過處理的錯誤,只能事先避免。 -
Exception:表示異常,異常產生後程序員可以通過代碼的方式糾正,使程序繼續運行,是必須要處理的。
Throwable中的常用方法:
-
public void printStackTrace()
:打印異常的詳細信息。包含了異常的類型,異常的原因,還包括異常出現的位置,在開發和調試階段,都得使用
printStackTrace()
。 -
public String getMessage()
:獲取發生異常的原因。提示給用戶的時候,就提示錯誤原因。
-
public String toString()
:獲取異常的類型和異常描述信息。
5.2 異常分類
-
編譯時期異常:
checked
異常。在編譯時期,就會檢查,如果沒有處理異常,則編譯失敗。(如日期格式化異常) -
運行時期異常:
runtime
異常。在運行時期,檢查異常.在編譯時期,運行異常不會編譯器檢測(不報錯)。(如數學異常)
5.3 拋出異常throw
在java中,提供了一個 throw
關鍵字,它用來拋出一個指定的異常對象。那麼,拋出一個異常具體如何操作呢?
-
創建一個異常對象。封裝一些提示信息(信息可以自己編寫)。
-
需要將這個異常對象告知給調用者。
throw
異常對象。並且throw
用在方法內,用來拋出一個異常對象,將這個異常對象傳遞到調用者處,並結束當前方法的執行。
格式如下:
throw new 異常類名(參數);
代碼實現:方法體中 throw
的使用
public static int getElement(int[] arr,int index){
// 判斷:索引是否越界
if(index<0 || index>arr.length-1){
// 如果條件滿足,執行完throw拋出異常後,方法無法繼續運算
throw new ArrayIndexOutOfBoundsException("角標越界!");
}
int element = arr[index];
return element;
}
5.4 Objects非空判斷
public static <T> T requireNonNull(T obj)
:查看指定引用對象不是null。
代碼實現:對爲null的進行了拋出異常操作
public static <T> T requireNonNull(T obj) {
if (obj == null)
throw new NullPointerException();
return obj;
}
5.5 聲明異常throws
聲明異常:將問題標識出來,報告給調用者。如果方法內通過 throw
拋出了編譯時異常,而沒有捕獲處理,那麼必須通過 throws
進行聲明,讓調用者去處理。關鍵字 throws
運用於方法聲明之上,用於表示當前方法不處理異常,而是提醒該方法的調用者來處理異常(拋出異常)。
聲明異常格式:
修飾符 返回值類型 方法名(參數) throws 異常類名1,異常類名2…{ }
5.6 throw與throws的區別
throw
關鍵字通常用在方法體中,並且拋出一個異常對象。程序在執行到 throw
語句時立即停止,它後面的語句都不執行。
throws
關鍵字通常被應用在聲明方法時,用來指定可能拋出的異常。多個異常可以使用逗號隔開。當在主函數中調用該方法時,如果發生異常,就會將異常對象拋給方法調用處。
5.7 捕獲異常try…catch
如果異常出現的話,會立刻終止程序,所以我們得處理異常:
-
該方法不處理,而是聲明拋出,由該方法的調用者來處理
(throws)
。 -
在方法中使用
try-catch
的語句塊來處理異常。
try-catch
的方式就是捕獲異常。捕獲異常:Java中對異常有針對性的語句進行捕獲,可以對出現的異常進行指定方式的處理。
捕獲異常語法如下:
try{
編寫可能會出現異常的代碼
}catch(異常類型 e){
處理異常的代碼
//記錄日誌/打印異常信息/繼續拋出異常
}
try:該代碼塊中編寫可能產生異常的代碼。
catch:用來進行某種異常的捕獲,實現對捕獲到的異常進行處理。
5.8 finally 代碼塊
finally:有一些特定的代碼無論異常是否發生,都需要執行。另外,因爲異常會引發程序跳轉,導致有些語句執行不到。而 finally
就是解決這個問題的,在 finally
代碼塊中存放的代碼都是一定會被執行的。
代碼實現:實現 try-catch-finally
操作參考
public class TryCatchDem {
public static void main(String[] args) {
try {
read("a.txt");
} catch (FileNotFoundException e) {
// 抓取到的是編譯期異常,拋出去的是運行期異常
throw new RuntimeException(e);
} finally {
System.out.println("不管程序怎樣,finally中程序都會被執行。");
}
System.out.println("結束!");
}
public static void read(String path) throws FileNotFoundException {
if (!path.equals("a.txt")) {
// 如果不是a.txt這個文件,拋出異常
throw new FileNotFoundException("文件不存在!");
}
}
}
5.9 自定義異常
異常類如何定義:
-
自定義一個編譯期異常: 自定義類 並繼承於
java.lang.Exception
。 -
自定義一個運行時期的異常類:自定義類 並繼承於
java.lang.RuntimeException
。
多個異常使用捕獲又該如何處理呢?
-
多個異常分別處理。
-
多個異常一次捕獲,多次處理。
-
多個異常一次捕獲一次處理。
一般處理方式的格式如下:
try{
編寫可能會出現異常的代碼
}catch(異常類型A e){ // 當try中出現A類型異常,就用該catch來捕獲
處理異常的代碼
// 記錄日誌/打印異常信息/繼續拋出異常
}catch(異常類型B e){ // 當try中出現B類型異常,就用該catch來捕獲
處理異常的代碼
// 記錄日誌/打印異常信息/繼續拋出異常
}
-
運行時異常被拋出可以不處理。即不捕獲也不聲明拋出。
-
如果
finally
有return
語句,永遠返回finally
中的結果,避免該情況。 -
如果父類拋出了多個異常,子類重寫父類方法時,拋出和父類相同的異常或者是父類異常的子類或者不拋出異常。
-
父類方法沒有拋出異常,子類重寫父類該方法時也不可拋出異常。此時子類產生該異常,只能捕獲處理,不能聲明拋出。
歡迎關注博主,歡迎互粉,一起學習!
感謝您的閱讀,不足之處歡迎指正!