java核心技術第六篇之斷言、日誌、包裝類型和工具類

来源:https://www.cnblogs.com/haizai/archive/2019/08/04/11297587.html
-Advertisement-
Play Games

JDK1.5新特性: 1.自動拆裝箱. 2.泛型 3.可變參數 4.靜態導入 5.增強for迴圈 6.互斥鎖 7.枚舉 8.註解 JDK1.6新特性: 1.Desktop類和SystemTray類 2.使用JAXB2來實現對象與XML之間的映射 3.StAX 4.使用Compiler API 5.輕 ...


JDK1.5新特性:
1.自動拆裝箱.
2.泛型
3.可變參數
4.靜態導入
5.增強for迴圈
6.互斥鎖
7.枚舉
8.註解

JDK1.6新特性:

1.Desktop類和SystemTray類
2.使用JAXB2來實現對象與XML之間的映射
3.StAX
4.使用Compiler API
5.輕量級Http Server API
6.插入式註解處理API(Pluggable Annotation Processing API)
7.用Console開發控制台程式
8.對腳本語言的支持
9.Common Annotations

JDK1.7新特性:

1 對集合類的語言支持;
2 自動資源管理;
3 改進的通用實例創建類型推斷;
4 數字字面量下劃線支持;
5 switch中使用string;
6 二進位字面量0b001;
7 簡化可變參數方法調用。
8 泛型簡化,出現菱形泛型
9 異常的多個catch合併,每個異常用或|
10 try-with-resources 語句

JDK1.8 新特性:
一、介面的預設方法:Java 8允許我們給介面添加一個非抽象的方法實現,只需要使用 default關鍵字即可,這個特征又叫做擴展方法,
二、Lambda 表達式:Collections.sort(names, (a, b) -> b.compareTo(a));Java編譯器可以自動推導出參數類型,所以你可以不用再寫一次類型。
三、函數式介面:每一個lambda表達式都對應一個類型,通常是介面類型。而“函數式介面”是指僅僅只包含一個抽象方法的介面,每一個該類型的lambda表達式都會被匹配到這個抽象方法。
因為 預設方法 不算抽象方法,所以你也可以給你的函數式介面添加預設方法。
四、方法與構造函數引用:Java 8 允許你使用 :: 關鍵字來傳遞方法或者構造函數引用,上面的代碼展示瞭如何引用一個靜態方法,我們也可以引用一個對象的方法:
五、Lambda 作用域:在lambda表達式中訪問外層作用域和老版本的匿名對象中的方式很相似。你可以直接訪問標記了final的外層局部變數,或者實例的欄位以及靜態變數。
六、訪問局部變數:lambda表達式中訪問外層的局部變數
七、訪問對象欄位與靜態變數:lambda內部對於實例的欄位以及靜態變數是即可讀又可寫。該行為和匿名對象是一致的:
八、訪問介面的預設方法:Lambda表達式中是無法訪問到預設方法的
九、Date API:Java 8 在包java.time下包含了一組全新的時間日期API。新的日期API和開源的Joda-Time庫差不多,但又不完全一樣
十、Annotation 註解:在Java 8中支持多重註解了,Java 8允許我們把同一個類型的註解使用多次,只需要給該註解標註一下@Repeatable即可,

斷言的使用方式:
斷言是一種測試和調測階段所使用的戰術工具.
斷言的初衷:在一個具有自我保護能力的程式中,斷言很常用.假設確信某個屬性符合要求,並且代碼的執行依賴於這個屬性.例如,需要計算
double y = Math.sqrt(x);
我們確信,這裡的x是一個非負數的值.原因是:是另外一個計算的結果,而這個結果不可能是負值;或者x是一個方法的參數,而這個方法要求它的調用者只能提供一個正整數.
然而,還是希望進行檢查,以避免讓"不是一個數"的數值參與計算操作.當然,也可以拋出一個異常:
if(x<0) throw new IllegalArgumentException("x<0");
但是需要註意的是,這段代碼會一直保留在程式中,即使測試完畢也不會自動的刪除.如果在程式中包含有大量的這種檢查,程式運行起來會相當慢.
斷言機制允許在測試期間向代碼中插入一些檢查語句.當代碼發佈時,這些插入的檢查語句將會被自動的移走.


開啟斷言:2.在myEclipse中,Windows -> Preferences ->Java ->Installed JREs ->點擊正使用的JDK ->Edit ->Default VM Arguments文本框中輸入:-ea或者-enableassertions
斷言的格式:
java中語音引入關鍵字assert.這個關鍵字有兩種表現形式:
1.assert 條件: 例如:assert x>=0; 想要斷言x是一個非負數值,只需要簡單的使用這條語句.
2.assert 條件:表達式; 例如:assert x>=0 : x; 或者將x的實際值傳遞給AssertionError對象,從而可以在後面顯示出來.
這兩個格式都會對條件進行檢測,如果結果為false,則拋出一個AssertionError異常.
在第二種格式中,表達式將被傳入AssertionEeror的構造器,並轉換成一個消息字元串.
註釋:"表達式"部分的唯一目的是產生一個消息字元串.AssertionErro對象並不存儲表達式的值,因此,不可能在以後得到它.正如JDK文檔所描述的那樣:如果使用表達式的值,
就會鼓勵程式員試圖從斷言中恢復程式的運行,這不符合斷言機制的初衷.


啟用和禁用斷言

在預設情況下,斷言是被禁用的。可以在程式運行時用-enableassertions或-ea選項啟用它:
java -enableassertions MyApp
啟用或者禁用斷言不必重新編譯程式。啟動或者禁用斷言是類載入器的功能。當斷言被禁用時,類載入器將跳過斷言代碼,因此,不會降低程式的運行速度。
也可以在某個類或者某個包中使用斷言,例如:
java -ea:MyClass -ea:com.mycompany.mylib... MyApp
這條命令將開啟MyClass類以及在com.mycompany.mylib包和它的子包中的所有類的斷言。選項-ea將開啟預設包中的所有類的斷言。
也可以使用-disableassertions或-da禁用某個特定的類和包的斷言:
java -ea:... -da:MyClass MyApp
有些類不是由類載入器載入,而是直接由虛擬機載入。可以使用這些開關有選擇地啟用或禁用哪些類中的斷言。
然而,啟用和禁用所有斷言的-ea和-da開關並不能應用到那些沒有類載入器的“系統類”上。對於這些系統類而言,需要使用-enablesystemassertions/-esa開關啟動斷言。
使用斷言完成參數檢查

API:java.long.ClassLoader 1.0 子類MLet
void setDefaultAssertionStatus(Boolean b) //1.4
對於通過類載入器載入的所有類來說,如果沒有顯示的說明類或者包的斷言 狀態,就啟用或禁用斷言.
void setClassAssertionSatus(String className,boolean b) //1.4
對於給定的類和它的內部類,啟用或禁用斷言.
void setPackageAssertionStatus(String packageName,boolean b) //1.4
對於給定包和其子包中的所有類,啟用或禁用斷言.
void clearAssertionStatus() //1.4
移去所有類和包的顯示斷言狀態設置,並禁用所有通過這個類載入器載入的類的斷言.

java中的3中處理系統錯誤的機制:
拋出一個異常
日誌
使用斷言
什麼時候應該使用斷言呢?
斷言失敗是致命的、不可恢復的錯誤
斷言檢查只用於開發和測試階段
因此,不應該使用斷言向程式的其他部分通告發生了可恢復性的錯誤,或者,不應該作為程式向用戶通告問題的手段。斷言只應該是在測試階段確定程式內部錯誤的位置。
斷言是一種測試和調試階段所使用的戰術性工具;而日誌記錄是一種在程式的整個生命周期都可以使用的策略性工具。
public class App
{
public static void main( String[] args )
{
int a = -1;
assert a > 0 : "liuni是笨蛋";
System.out.println( "Hello World!" );
}
}

程式中記錄日誌一般有兩個目的:Troubleshooting和顯示程式運行狀態。好的日誌記錄方式可以提供我們足夠多定位問題的依據。日誌記錄大家都會認為簡單,但如何通過日誌可以高效定位問題並不是簡單的事情。這裡列舉下麵三個方面的內容,輔以代碼示例,總結如何寫好日誌,希望對他人有所啟發和幫助:

 


怎樣記日誌可以方便Troubleshooting
程式運行狀態可以記哪些
應該避免怎樣的日誌方式
怎樣記日誌可以方便Troubleshooting?
1. 對外部的調用封裝

程式中對外部系統與模塊的依賴調用前後都記下日誌,方便介面調試。出問題時也可以很快理清是哪塊的問題

[java] view plain copy
LOG.debug("Calling external system:" + parameters);
Object result = null;
try {
result = callRemoteSystem(params);
LOG.debug("Called successfully. result is " + result);
} catch (Exception e) {
LOG.warn("Failed at calling xxx system . exception : " + e);
}

2.狀態變化

程式中重要的狀態信息的變化應該記錄下來,方便查問題時還原現場,推斷程式運行過程

[java] view plain copy
boolean isRunning;

isRunning = true;
LOG.info("System is running");

//...

isRunning = false;
LOG.info("System was interrupted by " + Thread.currentThread().getName());

3.系統入口與出口:

這個粒度可以是重要方法級或模塊級。記錄它的輸入與輸出,方便定位

[java] view plain copy
void execute(Object input) {
LOG.debug("Invoke parames : " + input);
Object result = null;

//business logic

LOG.debug("Method result : " + result);
}

4.業務異常:

任何業務異常都應該記下來:

[java] view plain copy
try {
//business logical
} catch (IOException e) {
LOG.warn("Description xxx" , e);
} catch (BusinessException e) {
LOG.warn("Let me know anything");
} catch (Exception e) {
LOG.error("Description xxx", e);
}

5.非預期執行:

為程式在“有可能”執行到的地方列印日誌。如果我想刪除一個文件,結果返回成功。但事實上,那個文件在你想刪除之前就不存在了。最終結果是一致的,但程式得讓我們知道這種情況,要查清為什麼文件在刪除之前就已經不存在

[java] view plain copy
int myValue = xxxx;
int absResult = Math.abs(myValue);
if (absResult < 0) {
LOG.info("Original int " + myValue + "has nagetive abs " + absResult);
}

6.很少出現的else情況:

else可能吞掉你的請求,或是賦予難以理解的最終結果

[java] view plain copy
Object result = null;
if (running) {
result = xxx;
} else {
result = yyy;
LOG.debug("System does not running, we change the final result");
}

日誌記錄:

程式運行狀態可以記哪些?
程式在運行時就像一個機器人,我們可以從它的日誌看出它正在做什麼,是不是按預期的設計在做,所以這些正常的運行狀態是要有的。

1. 程式運行時間:

[java] view plain copy
long startTime = System.currentTime();

// business logical

LOG.info("execution cost : " + (System.currentTime() - startTime) + "ms"); 

2. 大批量數據的執行進度:

[java] view plain copy
LOG.debug("current progress: " + (currentPos * 100 / totalAmount) + "%");

3.關鍵變數及正在做哪些重要的事情:

執行關鍵的邏輯,做IO操作等等

[java] view plain copy
String getJVMPid() {
String pid = "";
// Obtains JVM process ID
LOG.info("JVM pid is " + pid);
return pid;
}

void invokeRemoteMethod(Object params) {
LOG.info("Calling remote method : " + params);
//Calling remote server
}


應該避免怎樣的日誌方式?
1. 混淆信息的Log

日誌應該是清晰準確的: 當看到日誌的時候,你知道是因為連接池取不到連接導致的問題麽?

[java] view plain copy
Connection connection = ConnectionFactory.getConnection();
if (connection == null) {
LOG.warn("System initialized unsuccessfully");
}

2. 記錯位置

產品代碼中,使用console記錄日誌,導致沒有找到日誌。

[java] view plain copy
} catch (ConfigurationException e) {
e.printStackTrace();
}


3. 記錯級別

記錯級別常常發生,常見的如:混淆代碼錯誤和用戶錯誤,如登錄系統中,如果惡意登錄,那系統內部會出現太多WARN,從而讓管理員誤以為是代碼錯誤。可以反饋用戶以錯誤,但是不要記錄用戶錯誤的行為,除非想達到控制的目的。

[java] view plain copy
LOG.warn("Failed to login by "+username+");

4. 遺漏信息

這裡可能包含兩種情況:(1)用戶自己少寫了信息,導致毫無參考價值;(2)用戶調用log的方式導致丟失信息,如下例,沒有stack trace.


[java] view plain copy
} catch (Exception ex) {
log.error(ex);
}
*/
----------String--------------

構造:
String(String original):把字元串數據封裝成字元串對象

String(char[] value):把字元數組的數據封裝成字元串對象

String(char[] value, int index, int count):把字元數組中的一部分數據

方法:
判斷功能:

boolean equals(Object obj):比較字元串的內容是否相同

boolean equalsIgnoreCase(String str):比較字元串的內容是否相同,忽略大小寫

boolean startsWith(String str):判斷字元串對象是否以指定的str開頭

boolean endsWith(String str):判斷字元串對象是否以指定的str結尾

 

獲取功能:

int length():獲取字元串的長度,其實也就是字元個數

char charAt(int index):獲取指定索引處的字元

int indexOf(String str):獲取str在字元串對象中第一次出現的索引

String substring(int start):從start開始截取字元串

String substring(int start,int end):從start開始,到end結束截取字元串。包括start,不包括end

 

轉換功能:

char[] toCharArray():把字元串轉換為字元數組

String toLowerCase():把字元串轉換為小寫字元串

String toUpperCase():把字元串轉換為大寫字元串

String replace(char oldChar, char newChar)通過用 newChar 替換此字元串中出現的所有 oldChar ,返回處理後的字元串。



其它功能:

String trim():去除字元串兩端空格

String[] split(String str):按照指定符號分割字元串


--------StringBuider(可變字元串)------------
構造:
就一個

方法:
public int capacity():返回當前容量 (理論值)

public int length():返回長度(已經存儲的字元個數)

public StringBuilder append( 任意類型 ):添加數據,並返回添加的數據

public StringBuilder reverse():反轉功能

StringBuilder replace(int start, int end, String str) 使用給定 String 中的字元替換此序列的子字元串中的字元。

 

--------Integer(包裝類)---------------
構造:
不需要,直接類名.方法名調用,如下

方法:
Integer.parseInt(String str):將字元串轉int類型(只能數字內容的字元串,不然報錯)

 

---------ArrayList(集合)-------------------
構造:
ArrayList();就學了空參創建

方法:
public boolean add(E e):添加元素,成功返回true,就業班學false
public void add(int index,E element):在指定的索引處添加一個元素

public E get(int index):返回指定索引處的元素

public E set(int index,E element):修改指定索引處的元素,返回被修改的元素

public int size():返回集合中的元素的個數

public boolean remove(Object o):刪除指定的元素,返回刪除是否成功
E remove(int index) 移除此列表中指定位置上的元素,並返回刪除的數據。


---------FileWriter(輸出普通流)-----------
構造:
FileWriter(String fileName); 傳入一個文件的路徑

方法:
void write(int c) 寫入一個字元,int類型傳入
void write(String str) 寫入一個字元串
void write(String str, int startIndex, int len) 寫入字元串的一部分
void write(char[] cbuf) 寫入一個字元數組
void write(char[] cbuf, int startIndex, int len)寫入字元數組的一部分

void flush() 將記憶體中的數據刷新到文件中

void close() 數據刷新到文件中,關流釋放系統底層資源(關閉後永久關閉,直到下次程式運行)


---------BufferedWriter(輸出緩衝流)-----------
構造:
BufferedWriter(new FileWriter(String fileName));傳入一個FileWriter對象,FileWriter包含一個文件的路徑


方法 (同FileWriter,多了一個方法):
void newLine() 寫入換行(\r\n)

---------FileReader(輸入普通流)-----------
構造:
FileReader(String fileName); 傳入一個文件的路徑

方法:
int read() 讀取單個字元,若是讀取成功返回參數的int類型表現形式,若讀取失敗,返回-1
int read(char[] cbuf) 讀取指定char數組長度個字元,並存入char數組,若是讀到文件尾部,則停止讀取,並返回讀取字元的個數(不是char數組長度),若是一個都沒讀到,返回-1。
int read(char[] cbuf, int startIndex, int len) 讀取 startIndex 索引開始, len 個字元(length簡拼)

void reset() 重置流(刪除前面讀的記錄)

---------BufferedReader(輸入緩衝流)-----------
構造:
FileReader(String fileName); 傳入一個文件的路徑


方法 (同FileReader,多了一個方法)
String ReadLine() 一次讀一行的內容,返回讀到的內容,沒讀到返回null

-----------Arrays(工具類,考試不推薦使用)-----------------
構造:
不需要構造,因為該類不需要創建對象

方法:
String toString(各種數組,集合不行) 返回該數組的全部內容的特定格式(遍曆數組)



方法重載:
1.方法名相同
2.參數列表不同(數量、類型、順序)

方法覆蓋:
1.訪問修飾符相同或更寬
2.返回值類型相同
3.方法名相同
4.參數表相同
5.static 靜態只能覆蓋靜態 非靜態只能覆蓋非靜態
6.子類方法不能拋出比父類更多的異常

三大修飾符:

static

可以修飾屬性、方法和初始化代碼塊,不可以修飾局部變數

1. 靜態屬性、方法為全類所有,可通過類名直接調用
2. 靜態初始化代碼塊在類載入時執行,僅執行一次

final

可以修飾局部變數、成員變數、方法和類

1. final修飾的變數一旦被賦值,就不能改變
2. final修飾的方法不可以被覆蓋
3. final修飾的類不能被繼承

abstract

可以修飾類和方法

1. 抽象類只能聲明引用,不能創建對象
2. 抽象方法只有聲明,沒有實現(不寫代碼塊)
3. 如果一個類中有抽象方法,那這個類必須是抽象類
4. 子類繼承一個抽象類,如果不希望子類變成抽象類,那子類必須實現父類中的全部抽象方法


PS:多個修飾符修飾同一方法、類時的使用問題

1. abstract 不能與 final 一起修飾方法、類

抽象類、方法需要被繼承、覆蓋才可使用,final修飾的類、方法不可被繼承、覆蓋

2. abstract 不能與 private 一起修飾方法(private只能修飾內部類)

理由同上,私有方法不能被繼承

3. abstract 不能與 static 一起修飾方法(static只能修飾類的成員,不能修飾類本身)

抽象類需要有子類的實現類才能調用內部方法,而靜態類可以直接通過本類名調用內部方法

4. private 與 static 與 final 可以連用(屬性、方法都可以)


許可權修飾符:private default protect public 可以修飾方法
public default 可以修飾類


介面:interface

1. 介面是特殊的抽象類(interface 代替了 abstract class)
2. 介面中所有屬性都是公開靜態常量
3. 介面中所有方法都是公開抽象方法
4. 一個介面可以繼承多個介面(extends 多個介面,介面之間用逗號隔開)
5. 一個類只可以繼承一個父類,但是可以實現多個介面

PS: 抽象類與介面的不同點

1. 抽象類可以有構造方法,介面不可以有構造方法

2. 抽象類不可以多繼承,介面可以多繼承

介面的實現(被子類繼承):implements

1. 一個類實現介面,如果不希望作為抽象類,就必須實現介面中全部方法

介面的作用;

1. 介面與多繼承

1. 可以讓子類繼承主要類型,讓次要類型作為一個介面讓子類實現.
2. 單繼承具備簡單性(相對於多繼承),使用介面實現的多繼承並不會破壞其簡單性

2. 介面與解耦合

介面抽象出子類中的共性,利用多態來解耦合

3. 介面回調

實現某些介面,由函數庫中方法自動調用。

例:
定義實體類是實現Comrparable<E>介面(中的comepareTo方法,返回值為int)
在調用java.util.Arrays.sort數組排序方法時,可以排序存放實體類的數組

Object類:

Object是所有類的父類,如果一個類沒有定義直接繼承的父類,就會直接繼承Object類(自動加上extends Object)

所有的類都會繼承Object類中的全部公開方法。

Obeject類中的全部方法:

1. finalize

該方法在垃圾回收時,被垃圾回收器調用

(什麼是垃圾? -- 沒有引用指向的對象)

1. JVM中有自動垃圾回收機制,程式員只需要創建對象、分配空間,不需要回收垃圾

2. JVM只有在記憶體不夠用的時候才會進行垃圾回收
(可能會浪費空間,但減少了垃圾回收對CPU的占用)

2. getClass

作用:得到對象的"實際"類型

補充:instanceof 可看做是不是: 引用 instanceof 類型
該引用的實際類型 是不是 某類型

比較兩個對象的實際類型是不是相等:

1. 使用 instanceof 只能得出某對象的實際樂行是不是某類型的子類

2. 可以使用getClass得到 對象的實際類型

語法:m1.getClass() == m2.getClass()

3. equals

作用: 比較兩個對象

1. 可以在子類中覆蓋equals方法,作用為使兩個對象可以使用自定義的標準相互比較

2. 如果不覆蓋equals方法,預設比較兩個對象的地址值(即使用 == 比較兩個引用類型)

3. 字元串類覆蓋了equals方法


覆蓋equals方法的五個步驟:

1. 判斷 this == obj (地址相同直接返回true)

2. 判斷 obj == null (this一定不是null,否則無法調用equals方法)

3. 判斷 兩個對象的實際類型是否相同(使用getClass方法)

4. 強制類型轉換

5. 依次比較兩個對象的屬性是否相等

4. toString

作用:列印

在控制台列印對象時,自動調用該對象的toString方法


包裝類:

將基本數據類型封裝為對象數據類型:

int -- Integer
char -- Character
其他基本數據類型 -- 首字母大寫

int Integer String 之間的相互轉換:

1. Integer ii = new Integer( int i )

Integer ii = new Integer( String s )

2. int i = ii.intValue()

int i = Integer.paresInt( String s )

3. String s = ii.toString()

String s = String.valueOf( int i )


正則表達式:

作用: 使用正則表達式可以匹配出想要的字元串

1. [] [a-zA-Z0-9] [1235] 中括弧可以匹配多個字元,或者範圍內字元,範圍使用-分隔,多組範圍直接連著寫

2. {} {5} {5,10} 限制前一個字元內容長度,或者長度範圍,範圍使用逗號分隔

3. 特殊意義字元: \:轉義字元,想要使用\ 需要使用轉義字元 \\

+:放在字元後面,代表匹配一個或多個該字元,想要使用+,需要使用轉義字元 \\+

.:匹配任意一個字元,使用字元本身,需要轉義 \\.

\\d 匹配任意字母

\\w 匹配任意字母或者數字

( | ) 邏輯或,匹配 | 前面或者後面的字元,例:(J|j)ava 可以匹配 Java 或者 java

^: 代表必須是字元串的開頭,例:^[a-z] 字元串必須以小寫字母開頭

$: 代表前一個字元必須是匹配內容的結尾,例:^[a-z][0-9]$ 字元串必須以數字結尾

\\_ 下劃線

 

內部類:

成員內部類:

1. 成員內部類可以訪問外部類中所有的、靜態的、私有的屬性和方法

2. 成員內部類中不可以定義靜態的屬性和方法

3. 創建成員內部類對象,需要先創建一個外部類對象(依賴於獨立的外部類對象,因此不可以有靜態成員)

創建成員內部類對象:

外部類 out = new 外部類();

外部類.內部類 引用名 = out.new 外部類.內部類();

(類型是 外部類.內部類,作為一個外部類的成員,需要用一個外部類對象來創建)

靜態內部類:

1. 靜態內部類只能訪問外部類中所有的靜態屬性和方法

2. 靜態內部類可以定義普通的和靜態的屬性和方法

3. 創建靜態內部類對象,可以直接使用該類的類型創建(靜態成員不依賴於外部類的對象)

創建靜態內部類對象:

外部類.靜態內部類 引用名 = new 外部類.靜態內部類();

(不依賴外部類對象,直接用類型創建)

局部內部類:

作用同下

匿名內部類:

new 介面名() { 介面的實現代碼 }

用途:

需要一個僅僅使用一次的對象時,直接在方法內部創建、使用,不需要打斷思路,另開一個實現類

缺點:

代碼可讀性差


集合框架:

為什麼使用集合: 數組的擴容、插入、刪除操作十分繁瑣


集合的類型:

Collection<Object> 介面

--> List<Object> 介面

--> Set<Object> 介面

Map<Key, Value> 介面

集合中的方法:

Collecion :

add (Object obj) -- boolean 添加元素

contains (Object obj) -- boolean 查看是否包含某元素

isEmpty() -- boolean 集合是否為空

remove (Object obj) -- boolean 刪除某元素

clear() -- void 清空集合

size() -- int 查看集合中元素個數


List : 元素是對象類型,元素有下標(有順序),元素可以重覆

add (Object obj) / add (int index, Object obj)

添加元素,可以直接添加,或者插入到指定的index

get (int index) set (int index, Object obj)

根據下標,獲取或者修改元素

indexOf (Object obj) -- int

獲取元素下標


Set: 元素是對象類型,元素沒有下標(沒有順序),元素不可以重覆


Set集合沒有自己特有的方法,全部方法繼承自Collection


Map: 元素是鍵值對類型,鍵不可以重覆,值可以重覆

get (Object key) -- Object

根據鍵,獲取對應的值

put (Object key, Object value) -- void

添加一個鍵值對

remove (Object key) -- void

刪除一個鍵值對,根據值

ketSet() -- Set

獲取全部的鍵,放到一個Set裡面返回

values() -- Collection

獲取全部的值,放到一個Collection中返回

containsKey/containsValus

查看Map中是否包含某個Key/Values

size()

查看Map中鍵值對個數

isEmpty()


clear()


entrySet()

獲取全部的鍵值對(Map.Entry類型),放到Set中返回


集合的實現類:

List 的實現類:

ArrayList

1. 使用數組實現

2. 增刪慢,查詢快

LinkedList

1. 使用鏈表實現

2. 增刪快,查詢慢

Vector

1. JDK1.0遺留的產物

2. 重量級,線程安全,速度慢(多線程訪問同一對象時,不會出現同步問題)

Set 的實現類:

HashSet

1. 集合中的元素無序,不重覆(可以用來去除一組元素中重覆的數據)

2. new HashSet() 預設容量16,載入因數0.75

3. newHashSet(int 容量, float )


LinkedHashSet

1. 遍歷時可以保留添加到集合中的順序(Set集合中的元素是無序的)


Set 集合是如何實現不重覆元素的?

添加進Set集合中的元素要想做到不重覆需要:

1. 需要覆蓋 equals() 方法 -- 變成比較元素內容而不是比較元素地址

2. 需要覆蓋 hashCode() 方法 -- 使哈希碼與元素內容有關,

保證相同元素有相同哈希碼,

儘量保證不同元素哈希碼不同,

可節省運算、比較次數

如何實現元素不重覆的?

1. 每個對象都有自己的 hashCode(hashSet使用數組加鏈表實現)

-- hashCode決定對象在集合中的存放位置,

初始hashCode值由對象地址決定

2. 如果兩個對象的hashCode相同,就使用 equals() 方法進行比較,

去掉重覆元素,不重覆的掛到該hashCode對應數組位置中的鏈表裡

3. 如果兩個對象hashCode不同,那麼放入集合的位置就可能不同,

兩個對象就不會進行 equals() 方法比較的過程,因此必須修改hashCode方法

讓內容可能相同的對象hashCode相同,進行比較去重覆。

同時也要儘量保證內容不同的對象的hashCode不同,儘量加快運算速度。


equals方法:

1. 判斷兩個對象地址是否相同(直接等於)

2. 判斷參數對象是否為空

3. 判斷兩個對象類型是否相同(使用getClass方法)

使用 instanceof 有可能遇到父子類的情況

4. 將參數對象類型強轉成本類對象類型

5. 逐個比較兩個對象的屬性

Map 的實現類:

HashMap

1. 鍵不可以重覆,同樣需要覆蓋 equals 方法和 hashCode 方法

2. 允許鍵/值為 null

LinkedHashMap

1. 遍歷時,保留了鍵的放入順序

HashTable

1. 類似於 Vector ,重量級,速度慢,線程安全

2. 當鍵/值為 null 時,會拋出異常


Map 集合的三種遍歷方式:

鍵遍歷:

使用 keySet() 方法,拿到全部鍵的Set,再遍歷 Set 即可(配合 get(key) 方法拿值)

值遍歷:

使用 values() 方法,拿到全部值的Collection

鍵值對遍歷:

1.使用 entrySet() 方法,拿到全部的鍵值對Set

裝有鍵值對的Set的泛型需要註意寫法:

例: Set<Map.Entry<Integer, String>> set = map.entrySet();

鍵值對的類型為:Map.Entry , 例: Map.Entry entry = (Map.Entry)iter.next();

鍵值對的迭代器遍歷時,需要將從Set中取出

的值強轉成 Map.Entry 類型

↑↑以上是JDK5.0之前泛型沒出的時候的做法

加泛型之後,不需要在強轉了

2. 使用Map.Entry類中的 getKey() / getValue() 方法,獲取鍵值對中的鍵和值


PS:用迭代器遍歷集合

Iterator iter = list.iterator(); --> List 和 Set 中有iterator方法,獲取迭代器

//創建一個迭代器對象

while( iter.hasNext() ) {

Object value = iter.next();

//對拿到的value進行需要的操作

}

foreach遍歷

1. foreach封裝了迭代器遍歷

2. 迭代器對與集合長度及變化做了安全監測,

3. 定義了異常:ConcurrentModificationException 併發修改異常

4. 在使集合創建迭代器時,會為變數expectedModCount賦值(賦予當前modCount的值)

5. foreach遍歷集合時,先調用hasNext方法,指針後移,如果索引等於集合長度,

則結束迴圈,如果索引小於集合長度,

則通過next()取出指針指向的集合內對象地址,執行迴圈體。

6. 在next()中進行集合長度及變化的安全監測,如果索引大於集合長度,則說明在

上一次迴圈的迴圈體中,出現了修改集合長度的操作,則直接拋出

併發修改異常;集合之中有一個成員變數modCount,

記錄了集合被增刪元素的次數,next()中會先比較expectedModCount和

modCount的值是否相同,及監測集合有沒有被修改過,如果不同就拋出

併發修改異常

PS: 7. 安全監測是在next方法中進行的,因此若是刪除集合的倒數第二個元素:

在迴圈體執行刪除語句,刪除後集合長度-1,迴圈體結束進入下一次迴圈判斷

hasNext方法:索引長度剛好等於集合長度,結束迴圈,不進入next方法。

所以:可以在foreach遍歷集合中,刪除倒數第二個元素。

8. iterator的remove方法對集合修改安全監測進行了屏蔽處理,

使用iterator中的方法刪除元素,不會拋出異常

結論:Iterator做出了安全監測,集合對象不可以在foreach迴圈遍歷集合中,

做出增加刪除元素的操作,否則拋出併發修改異常。

(除了刪除倒數第二個元素)

集合工具類:

Collections :(靜態方法)

1. Collections.shuffle(list) 打亂一個List集合中元素的排列順序

2. Collections.sort(list) 按照自然順序排序一個List集合內的元素

3. Collections 只能作用於List集合


Properties:持久的屬性集


1. Properties繼承自Map集合

2. Properties中有方法可以將集合中內容保存在文本文件中

3. Properties限定泛型,只能裝String類型數據(name,value)

4. Properties中的常用方法:

1. setProperties(String, String)

2. getProperties(String key)

3. stringPropertyNames(獲取集合中全部的name的 Set 集合)

4. store(OutputStream,String comments) -- 將集合中數據通過輸出流保存在文本文件中

自定義一個輸出流,文本文件必須以.properties結尾,commetns為註釋,可以為null

5. load(InputStream) -- 通過一個輸入流將文件中內容傳入Properties對象中

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 首先先來描述一下我所遇到的問題,我在一個首頁的index.jsp頁面中用到了iframe框架,見下圖 在iframe中引入jsp頁面的路徑,是幾個iframe框架組合成的一個完整的頁面,但是他們的存在是相互獨立的。接著我在一個子頁面中(right.jsp)中, 想要將頁面跳轉到登錄的頁面(登錄頁面是 ...
  • AJAX PHP示例 AJAX用於創建更多互動式應用程式。 以下示例演示了當用戶在輸入欄位中鍵入字元時,網頁如何與Web伺服器通信: 體驗一下交互 在上面的示例中,當用戶在輸入欄位中鍵入字元時,showHint()執行被調用的函數。該函數由onkeyup事件觸發。 代碼說明:首先,檢查input欄位 ...
  • 搜羅到兩種相容性還不錯的方式。 1、第一種,通過clipboard.js插件實現(推薦) 此插件封裝了很多種使用方式很方便,具體demo,可以去GitHub上看,clipboard傳送門 2、第二種,純js實現: 上面兩種方式相容性都不錯,親測可用。 ...
  • 在CSS里,標簽位置居中一直是困擾Web前端的難題。在本文中,我對這類問題進行了探究和給出了幾點建議,供讀者參考。 1 行內標簽 1.1 水平居中 在父級標簽中使用 text-align: center。 效果: 1.2 垂直居中 如果是單行,則為該標簽設置行高(line-height)且與其父級標 ...
  • 介紹 客戶端不應該依賴它不需要的介面,即 一個類對另一個類的依賴應該建立在最小介面上 。 Demo引入 先來看一張圖: 如上圖所示:類A通過介面MyInterface依賴類B,類C通過介面MyInterface依賴類D;但是,類A只是想要使用B實現的介面MyInterface中的1,2,3方法,類C ...
  • 發佈 http://cxf.apache.org/download.html下載cfx項目解壓,配置系統環境 maven web項目里添加cfx 怎麼調用這些方法參考 https://www.cnblogs.com/tk55/p/11298435.html ...
  • 舉個慄子 問題描述 不同國家的人在NBA打球,但都是用英文交流。 簡單實現 Player Forwards Center Guards 測試 測試結果 存在問題 姚明剛到NBA時可能英文還不太好,也就是說聽不懂教練的戰術安排,attach 和 defense 不知道什麼意思,因此這樣實現會有問題,需 ...
  • 常見服務:http://www.webxml.com.cn/zh_cn/support.aspx 可能用到缺少的ArrayOfString.java文件 package com.test.wes.weather; import java.util.ArrayList; import java.uti ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...