[TOC]
> # 本文關鍵字
> 1. Java中的線程、鎖
> - 生產者消費者模式
> - ThreadLocal
> 2. Java集合
> 3. Java異常處理機制
> 4. 正則表達式
# 1、Java多線程
### 1、什么是多線程?使用多線程有什么好處?
> **進程**:是系統進行資源分配和調度的基本單位,在Android中表現為一個APP;
> **線程**:是程序執行的最小單元,是進程的一個實體,一個進程中可以有多個線程;
> **多線程**:是進程中同時又多個線程在同時運行。
> **優點** :使用多線程最直接的好處就是提高了程序的執行效率
> **生命周期**:新建狀態 就緒狀態 運行狀態 阻塞狀態 死亡狀態
### 2、多線程鎖:synchronized()、 Lock(接口) lock()/unlock()
> 1.不加鎖執行有什么現象
> 2.加鎖后執行有什么不同
> 3.若需兩個線程執行中產生交叉,并輸出交叉結果,退出應如何實現?
>實例:定義三個變量i=0;a=3;b=5;和兩個方法
### 3、wait(),notify(),join(),yield()
**1.基礎概念**
> wait():**必須獲得對象鎖**,一般與synchronized關鍵字一起使用,使當前線程進入到阻塞狀態,并釋放當前鎖
> notify()/notifyAll():喚醒單個/所有被阻塞的線程(**必須獲得對象鎖**),使這些線程進入到就緒狀態,即可運行狀態,等待cpu執行
> join():使當前線程等待調用該方法的線程結束,再執行后續的操作
> yield():告訴處理器當前線程可以暫停,暫停后直接進入到就緒態,不會釋放當前鎖,使同優先級或高優先級的線程可以運行,通常在debug或者測試環境下使用
**2.主線程需等子線程結束應如何實現(分別使用wait()、notify()和join()實現)**
**3.yeild()的理解,什么情況下使用?**
```java
/**
* A hint to the scheduler that the current thread is willing to yield
* its current use of a processor. The scheduler is free to ignore this
* hint.
*
* <p> Yield is a heuristic attempt to improve relative progression
* between threads that would otherwise over-utilise a CPU. Its use
* should be combined with detailed profiling and benchmarking to
* ensure that it actually has the desired effect.
*
* <p> It is rarely appropriate to use this method. It may be useful
* for debugging or testing purposes, where it may help to reproduce
* bugs due to race conditions. It may also be useful when designing
* concurrency control constructs such as the ones in the
* {@link java.util.concurrent.locks} package.
*/
public static native void yield();
```
> 根據官方的API介紹,我們可以知道:yeild ( ) 方法是**給調度程序發送了一個當前線程可以讓出正在使用的處理器的暗示,當然調度程序可以根據當時的情況,選擇是否忽略這個暗示;通常在開發中,yield()函數用在測試或者debug過程中**
### 4、可重入鎖、ReentrantReadWriteLock
> * **read鎖和write鎖互斥**
> * **read/write鎖可以多次進入**
> * **synchronized也是可重入鎖**
### 5、線程池
**使用線程池的優點:**
> * **重用**線程池中的線程,避免線程的創建和銷毀帶來的性能消耗;
> * 有效控制線程池的**最大并發數**,避免大量的線程之間因互相搶占系統資源而導致阻塞現象;
> * 進行**線程管理**,提供定時/循環間隔執行等功能。
a.Executors的**類型:**
```
//創建一個單一線程池:線程以隊列順序來執行。
ExecutorService threadPool = Executors.newSingleThreadExecutor();
//創建一個定長線程池,超出的線程會在隊列中等待。
ExecutorService threadPool = Executors.newFixedThreadPool(2);
//創建一個定長線程池,支持定時及周期性任務執行。
ExecutorService threadPool = Executors.newScheduledThreadPool(3);
//創建一個無界線程池:可進行線程自動回收,可存放線程數量最大值為Integer.MAX_VALUE
ExecutorService threadPool = Executors.newCachedThreadPool();
```
b.在阿里開發手冊中說明了Executors各個方法的**弊端**:
> * newFixedThreadPool和newSingleThreadExecutor:主要問題是堆積的請求處理隊列可能會耗費非常大的內存,甚至OOM。
>
>
> * newCachedThreadPool和newScheduledThreadPool:主要問題是線程數最大數是Integer.MAX_VALUE,可能會創建數量非常多的線程,甚至OOM。
c.**解決方式**:改用ThreadPoolExecutor創建線程池,便于明確線程池的運行規則,規避資源耗盡的風險。
其中,Executor、ThreadPoolExecutor、ScheduledExecutorService和ScheduledThreadPoolExecutor關系如下:
```
java.util.concurrent.Executor : 負責線程的使用與調度的根接口
|–ExecutorService:Executor的子接口,線程池的主要接口
|–ThreadPoolExecutor:ExecutorService的實現類
|–ScheduledExecutorService:ExecutorService的子接口,負責線程的調度
|–ScheduledThreadPoolExecutor:繼承了ThreadPoolExecutor實現了ScheduledExecutorService
```
d.ThreadPoolExecutor的**構造函數:**
```
public ThreadPoolExecutor(int corePoolSize, //核心線程數量
int maximumPoolSize, //最大線程數量
long keepAliveTime, //線程的存活時間(默認只對非核心線程有效,可設置是否對核心線程生效)
TimeUnit unit, //存活時間單位 有TimeUnit.MILLSECONDS,TimeUnit.SECOND等
BlockingQueue<Runnable> workQueue, //線程池的任務隊列
ThreadFactory threadFactory, //線程工廠,用來創建新的線程
RejectedExecutionHandler handler) //線程池無法執行新任務時,用來拋出異常
```
**推薦閱讀**:
[JDK 源碼解析--Executors、ExecutorService、ThreadPoolExecutor 線程池](https://blog.csdn.net/wenniuwuren/article/details/51429120 "JDK 源碼解析--Executors、ExecutorService、ThreadPoolExecutor 線程池")
[要點提煉|開發藝術之線程](https://www.jianshu.com/p/ab77a2e83c52 "要點提煉|開發藝術之線程")[](https://blog.csdn.net/wenniuwuren/article/details/51429120)
### 6、ThreadLocal
每個線程中都有一份的線程變量,作用域在本線程中。
核心方法有:
```
protected T initialValue() {return null;} //一個protected方法,一般是用來在使用時進行重寫的,它是一個延遲加載方法
public T get() {} //獲取ThreadLocal在當前線程中保存的變量副本
public void set(T value) {} //設置當前線程中變量的副本
public void remove() {} //移除當前線程中變量的副本
```
在使用get()前必須先進行set() 或者重寫 *initialValue() 方法*
推薦閱讀:[http://www.cnblogs.com/dolphin0520/p/3920407.html](http://www.cnblogs.com/dolphin0520/p/3920407.html "http://www.cnblogs.com/dolphin0520/p/3920407.html")
# 2、生產者和消費者模式
**生產者和消費者在同一時間段內共用同一存儲空間,生產者向該空間里生產數據,而消費者從該空間中取走數據。**
**實現方式:**
* 使用wait()和notify()實現
* ```
/**
* 通過wait()和notify() 實現的生產者和消費者模型
* Created by duoshilin on 2018/12/18.
*/
public class ProducerConsumer {
public static void main(String[] args) {
Queue<Integer> queue = new LinkedList<>();
new Producer("P-1",queue,5).start();
new Producer("P-2",queue,5).start();
new Consumer("C-1",queue,5).start();
new Consumer("C-2",queue,5).start();
new Consumer("C-3",queue,5).start();
}
public static class Producer extends Thread{
private Queue<Integer> queue;//緩存隊列
String name; //生產出的產品名
int maxSize; //最大生產量
volatile static int i=1; //表示產品編號
public Producer(String name, Queue<Integer> queue, int maxSize) {
super(name);
this.queue = queue;
this.name = name;
this.maxSize = maxSize;
}
@Override
public void run() {
while (true){
synchronized (queue){
while (queue.size() == maxSize){
try {
System.out.println("緩存隊列已滿,生產者["+name+"]正在歇息,等待消費者消費...");
queue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//System.out.println("生產者["+name+"] 正在生產第 "+i+" 件商品...");
//模擬生產的耗時操作
try {
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
queue.offer(i);
System.out.println("生產者["+name+"] 生產了第 "+(i++)+" 件商品...");
queue.notifyAll();
//使當前線程釋放鎖,讓其他線程有機會執行,模擬出生產和消費可同時進行的效果
try {
queue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public static class Consumer extends Thread{
private Queue<Integer> queue;//緩存隊列
String name; //當前消費的產品名
int maxSize;
public Consumer(String name, Queue<Integer> queue, int maxSize) {
super(name);
this.queue = queue;
this.name = name;
this.maxSize = maxSize;
}
@Override
public void run() {
while (true){
synchronized (queue){
while (queue.isEmpty()){
try {
System.out.println("緩存隊列已空,消費者["+name+"]正在等待新的商品...");
queue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//模擬消費的耗時操作
try {
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
int x = queue.poll();
System.out.println("消費者["+name+"] 使用了第 "+x+" 件商品...");
queue.notifyAll();
//使當前線程釋放鎖,讓其他線程有機會執行,模擬出生產和消費可同時進行的效果
try {
queue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
```
* 運行效果
```
生產者[P-1] 生產了第 1 件商品...
消費者[C-3] 使用了第 1 件商品...
緩存隊列已空,消費者[C-2]正在等待新的商品...
緩存隊列已空,消費者[C-1]正在等待新的商品...
生產者[P-2] 生產了第 2 件商品...
消費者[C-1] 使用了第 2 件商品...
緩存隊列已空,消費者[C-2]正在等待新的商品...
緩存隊列已空,消費者[C-3]正在等待新的商品...
生產者[P-1] 生產了第 3 件商品...
生產者[P-2] 生產了第 4 件商品...
消費者[C-3] 使用了第 3 件商品...
消費者[C-2] 使用了第 4 件商品...
緩存隊列已空,消費者[C-1]正在等待新的商品...
緩存隊列已空,消費者[C-3]正在等待新的商品...
生產者[P-2] 生產了第 5 件商品...
生產者[P-1] 生產了第 6 件商品...
消費者[C-3] 使用了第 5 件商品...
消費者[C-1] 使用了第 6 件商品...
緩存隊列已空,消費者[C-2]正在等待新的商品...
緩存隊列已空,消費者[C-3]正在等待新的商品...
生產者[P-1] 生產了第 7 件商品...
生產者[P-2] 生產了第 8 件商品...
消費者[C-3] 使用了第 7 件商品...
消費者[C-2] 使用了第 8 件商品...
緩存隊列已空,消費者[C-1]正在等待新的商品...
緩存隊列已空,消費者[C-3]正在等待新的商品...
生產者[P-2] 生產了第 9 件商品...
生產者[P-1] 生產了第 10 件商品...
消費者[C-3] 使用了第 9 件商品...
消費者[C-1] 使用了第 10 件商品...
緩存隊列已空,消費者[C-2]正在等待新的商品...
緩存隊列已空,消費者[C-3]正在等待新的商品...
生產者[P-1] 生產了第 11 件商品...
生產者[P-2] 生產了第 12 件商品...
消費者[C-3] 使用了第 11 件商品...
消費者[C-2] 使用了第 12 件商品...
緩存隊列已空,消費者[C-1]正在等待新的商品...
緩存隊列已空,消費者[C-3]正在等待新的商品...
生產者[P-2] 生產了第 13 件商品...
生產者[P-1] 生產了第 14 件商品...
消費者[C-3] 使用了第 13 件商品...
消費者[C-1] 使用了第 14 件商品...
緩存隊列已空,消費者[C-2]正在等待新的商品...
緩存隊列已空,消費者[C-3]正在等待新的商品...
生產者[P-1] 生產了第 15 件商品...
```
* 使用Lock(ReentrantLock) 和 Condition 實現的生產者消費者模式
* > 使用lock.lock() 和 lock.unlock() 為代碼加鎖和釋放鎖,將需要加鎖的代碼放在這兩行代碼之間
* ```
/**
* 使用Lock 和 Condition 實現的生產者消費者模式
* Created by duoshilin on 2018/12/18.
*/
public class ProducerConsumerByLock {
private static int i = 1;
private static Lock lock = new ReentrantLock();
private static Condition pCondition = lock.newCondition();
private static Condition cCondition = lock.newCondition();
private static Queue<Integer> queue = new LinkedList<>();
public static void main(String[] args) {
new Producer("P-1",queue,5).start();
new Producer("P-2",queue,5).start();
new Consumer("C-1",queue,5).start();
new Consumer("C-2",queue,5).start();
new Consumer("C-3",queue,5).start();
}
/**
* 生產者
*/
public static class Producer extends Thread{
Queue<Integer> queue;
int maxSize;
String name;
public Producer(String name, Queue<Integer> queue, int maxSize) {
super(name);
this.queue = queue;
this.maxSize = maxSize;
this.name = name;
}
@Override
public void run() {
while (true){
lock.lock();//加鎖
while (queue.size() == maxSize){
try {
System.out.println("緩存隊列已滿,生產者["+name+"]正在歇息,等待消費者消費...");
pCondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//模擬生產的耗時操作
try {
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
queue.offer(i);
System.out.println("生產者["+name+"] 生產了第 "+(i++)+" 件商品...");
//喚醒所有的生產者、消費者
pCondition.signalAll();
cCondition.signalAll();
//休息
try {
pCondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.unlock();//釋放鎖
}
}
}
public static class Consumer extends Thread{
Queue<Integer> queue;
int maxSize;
String name;
public Consumer(String name, Queue<Integer> queue, int maxSize) {
super(name);
this.queue = queue;
this.maxSize = maxSize;
this.name = name;
}
@Override
public void run() {
while (true){
lock.lock();
while (queue.isEmpty()){
try {
System.out.println("緩存隊列已空,消費者["+name+"]正在等待新的商品...");
cCondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//模擬消費的耗時操作
try {
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
int x = queue.poll();
System.out.println("消費者["+name+"] 使用了第 "+x+" 件商品...");
pCondition.signalAll();
cCondition.signalAll();
//休息
try {
cCondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.unlock();
}
}
}
}
```
運行效果如下:
```
生產者[P-1] 生產了第 1 件商品...
生產者[P-2] 生產了第 2 件商品...
消費者[C-1] 使用了第 1 件商品...
消費者[C-2] 使用了第 2 件商品...
緩存隊列已空,消費者[C-3]正在等待新的商品...
生產者[P-1] 生產了第 3 件商品...
生產者[P-2] 生產了第 4 件商品...
消費者[C-1] 使用了第 3 件商品...
消費者[C-2] 使用了第 4 件商品...
緩存隊列已空,消費者[C-3]正在等待新的商品...
生產者[P-1] 生產了第 5 件商品...
生產者[P-2] 生產了第 6 件商品...
消費者[C-1] 使用了第 5 件商品...
消費者[C-2] 使用了第 6 件商品...
緩存隊列已空,消費者[C-3]正在等待新的商品...
生產者[P-1] 生產了第 7 件商品...
生產者[P-2] 生產了第 8 件商品...
消費者[C-1] 使用了第 7 件商品...
消費者[C-2] 使用了第 8 件商品...
緩存隊列已空,消費者[C-3]正在等待新的商品...
生產者[P-1] 生產了第 9 件商品...
生產者[P-2] 生產了第 10 件商品...
消費者[C-1] 使用了第 9 件商品...
消費者[C-2] 使用了第 10 件商品...
緩存隊列已空,消費者[C-3]正在等待新的商品...
生產者[P-1] 生產了第 11 件商品...
生產者[P-2] 生產了第 12 件商品...
消費者[C-1] 使用了第 11 件商品...
消費者[C-2] 使用了第 12 件商品...
緩存隊列已空,消費者[C-3]正在等待新的商品...
生產者[P-1] 生產了第 13 件商品...
生產者[P-2] 生產了第 14 件商品...
消費者[C-1] 使用了第 13 件商品...
消費者[C-2] 使用了第 14 件商品...
緩存隊列已空,消費者[C-3]正在等待新的商品...
生產者[P-1] 生產了第 15 件商品...
生產者[P-2] 生產了第 16 件商品...
消費者[C-1] 使用了第 15 件商品...
消費者[C-2] 使用了第 16 件商品...
緩存隊列已空,消費者[C-3]正在等待新的商品...
生產者[P-1] 生產了第 17 件商品...
生產者[P-2] 生產了第 18 件商品...
消費者[C-1] 使用了第 17 件商品...
```
* 使用阻塞隊列(LinkedBlockingQueue)實現
> LinkedBlockingQueue是一個阻塞的線程安全的隊列,底層采用鏈表實現。
>
> ? LinkedBlockingQueue構造的時候若沒有指定大小,則默認大小為Integer.MAX_VALUE,當然也可以在構造函數的參數中指定大小。LinkedBlockingQueue不接受null。
>
> 添加元素的方法有三個:add,put,offer,且這三個元素都是向隊列尾部添加元素的意思。? ?
>
> add方法在添加元素的時候,若超出了隊列的長度會直接拋出異常:?? ???
>
> put方法,若向隊尾添加元素的時候發現隊列已經滿了會發生阻塞一直等待空間,以加入元素。?
>
> offer方法在添加元素時,如果發現隊列已滿無法添加的話,會直接返回false。??
>
> 從隊列中取出并移除頭元素的方法有:poll,remove,take。?? ??
>
> ? ??? ??poll: 若隊列為空,返回null。
>
> ? ??? ??remove:若隊列為空,拋出NoSuchElementException異常。
>
> ? ??? ??take:若隊列為空,發生阻塞,等待有元素。
```
/**
* 生產者消費者模式:使用{@link java.util.concurrent.BlockingQueue}實現
* Created by duoshilin on 2018/12/18.
*/
public class ProducerConsumerByBQ {
private static volatile int i = 1;
private static LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue<>(5);
public static void main(String[] args) {
Thread p1 = new Producer("P-1", queue, 5);
Thread p2 = new Producer("P-2", queue, 5);
p1.start();
p2.start();
new Consumer("C-1", queue, 5).start();
new Consumer("C-2", queue, 5).start();
new Consumer("C-3", queue, 5).start();
try {
p1.join();
p2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
Iterator iterator = queue.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
/**
* 生產者
*/
public static class Producer extends Thread {
LinkedBlockingQueue<Integer> queue;
int maxSize;
String name;
public Producer(String name, LinkedBlockingQueue<Integer> queue, int maxSize) {
super(name);
this.queue = queue;
this.maxSize = maxSize;
this.name = name;
}
@Override
public void run() {
while (true) {
try {
synchronized (Producer.class){
queue.put(i);
System.out.println("生產者[" + name + "] 生產了第 " + (i++) + " 件商品...");
}
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static class Consumer extends Thread {
LinkedBlockingQueue<Integer> queue;
int maxSize;
String name;
public Consumer(String name, LinkedBlockingQueue<Integer> queue, int maxSize) {
super(name);
this.queue = queue;
this.maxSize = maxSize;
this.name = name;
}
@Override
public void run() {
while (true) {
try {
synchronized (Consumer.class){
int x = queue.take();
System.out.println("消費者[" + name + "] 使用了第 " + x + " 件商品...");
}
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
```
運行效果:
* ```
生產者[P-1] 生產了第 1 件商品...
生產者[P-2] 生產了第 2 件商品...
消費者[C-1] 使用了第 1 件商品...
消費者[C-2] 使用了第 2 件商品...
生產者[P-1] 生產了第 3 件商品...
消費者[C-3] 使用了第 3 件商品...
生產者[P-2] 生產了第 4 件商品...
消費者[C-1] 使用了第 4 件商品...
生產者[P-2] 生產了第 5 件商品...
消費者[C-2] 使用了第 5 件商品...
生產者[P-1] 生產了第 6 件商品...
消費者[C-2] 使用了第 6 件商品...
生產者[P-2] 生產了第 7 件商品...
消費者[C-3] 使用了第 7 件商品...
生產者[P-2] 生產了第 8 件商品...
消費者[C-2] 使用了第 8 件商品...
生產者[P-1] 生產了第 9 件商品...
消費者[C-1] 使用了第 9 件商品...
生產者[P-1] 生產了第 10 件商品...
消費者[C-3] 使用了第 10 件商品...
生產者[P-2] 生產了第 11 件商品...
消費者[C-2] 使用了第 11 件商品...
生產者[P-2] 生產了第 12 件商品...
消費者[C-3] 使用了第 12 件商品...
生產者[P-1] 生產了第 13 件商品...
消費者[C-1] 使用了第 13 件商品...
生產者[P-2] 生產了第 14 件商品...
消費者[C-2] 使用了第 14 件商品...
```
# 3、Java集合

圖片來源:[https://blog.csdn.net/Hacker_ZhiDian/article/details/80590428](https://blog.csdn.net/Hacker_ZhiDian/article/details/80590428 "https://blog.csdn.net/Hacker_ZhiDian/article/details/80590428")
* Java中的集合分為三大類:**List、Set和Map**。由上圖可以看出,**List和Set繼承自Collection,而Map不是Collection的子類。**
* **List接口的實現類有:ArrayList、LinkList、Vector =>Stack**
點擊展開內容




**ArrayList:內部采用數組**保存元素,初始默認容量為 10,之后添加元素時,如果數組容量不足,則以 1.5 倍的倍數擴容數組,溢出時拋出 OutOfMemeryError 異常。擴容操作即為新建一個更大的數組并將原數組中的元素拷貝到新數組中。在元素較多時擴容操作開銷較大,如果一開始可以確定最大需要的容量,那么建議使用另一個構造方法*public ArrayList(int initialCapacity){}*來創建指定初始容量的 ArrayList 以提高效率。因為采用的數組儲存元素,所以插入和刪除元素操作較慢(時間復雜度為 O(N))。 **ArrayList 為非線程安全的類**。
**LinkedList :內部采用雙向鏈表**來儲存元素,每添加一個元素就新建一個 Node 并添加到對應的位置,就沒有所謂的擴容機制,同時實現了 Deque (雙端隊列)接口,可以作為隊列 / 雙端隊列使用。插入元素、移除元素效率較高(時間復雜度為 O(1)),但是隨機訪問元素效率較低(時間復雜度為 O(N))。**LinkedList 非線程安全。**
**Vector :**和 ArrayList 相似,**內部采用數組保存元素**,默認容量為 10。創建時如果指定了 capacityIncrement 參數,那么每次擴容時數組容量增加 capacityIncrement ,否則擴容時數組容量變為原來的 2 倍。**Vector 線程安全**。
**Stack :**繼承于 Vector 類,提供了數據結構中 棧 的相關操作方法,**線程安全**。
* **Map接口的實現類有:HashMap => LinkHashMap、TreeMap(有序的)、WeakHashMap、IdentifyHashMap、ConcurrentHashMap和Hashtable**
* **HashMap 中元素的遍歷順序和元素的插入順序是沒有任何關系的**,因為插入元素時主要依據的是元素的鍵的 hashCode 值,而每個元素的鍵的 hashCode 沒有什么規則(根據鍵所屬的類的實現而定),所以我們并不能試圖按照插入元素的順序來取出元素。如果需要使得取出的元素順序是按照插入元素的先后順序排序的話,請使用 LinkedHashMap 。
**容量**(默認為 16,如果自定義初始容量,那么會處理成最小的不小于指定的容量的 2 的次冪數,注意 HashMap 的容量一定會是 2 的次冪數);
**擴容機制**(每次擴容變成上一次容量的 2 倍,如果當前元素數目達到擴容閥值(負載因子 * 當前 HashMap 總容量),進行擴容);
**負載因子**(默認 0.75 );
**最大容量**(Integer.MAX_VALUE - 8);
* **TreeMap 最大的特點是能根據插入的鍵值對的鍵來對鍵值對元素節點進行排序**,而當我們遍歷 TreeMap 對象的時候取得的元素順序是按照某個規則來進行排序的,具體規則我們可以在創建 TreeMap 對象的實現傳入一個 Comparator 對象的參數來進行指定。需要注意的是:如果沒有指定 TreeMap 的 Comparator 對象,那么需要保證 TreeMap 儲存的鍵值對元素的 “鍵” 是實現了 Comparable 接口的,否則會報類型轉換異常(ClassCastException),這一點在源碼的分析中已經提到了。
而相對于 HashMap 來說,TreeMap 沒有什么初始容量和負載因子的概念,因為它是用的是紅黑樹這種數據結構,即為動態申請內存空間(插入一個元素就申請一個元素的內存空間),也因為如此,其插入元素和查詢元素的時間復雜度均為 O(logn),即為樹的高度,n 為 TreeMap 中節點數。
**紅黑樹**是一種很有用的數據結構,只是維護的時候比一般的二叉搜索樹復雜一點,主要是**為了維護高度平衡以保證較高的查找效率**。
* **LinkedHashMap?**內部通過**雙向鏈表**來維持元素的順序,同時其繼承于?HashMap。
* **Hashtable**(1.5后被棄用)和HashMap很類似,最重要的區別是**Hashtable是線程安全的,而HashMap則不是線程安全的**,在1.5之后推薦使用ConcurrentHashMap([HashMap和Hashtable的區別](http://www.importnew.com/7010.html "HashMap和Hashtable的區別"))
* **ConcurrentHashMap?**類,這個類是 JDK1.5 新增的一個類,可以用來代替Hashtable,可以非常高效的進行相關的元素操作,同時還保證多線程安全。內部實現非常巧妙,簡單來說就是內部有多個互斥鎖,每個互斥鎖負責一段區域
> 假設現在內部有 100 個元素,即有一個長度為 100 的元素數組,那么 ConcurrentHashMap 提供了 10 個鎖,每個鎖負責 10 個元素(0~9, 10~19, …, 90~99),每當有線程操作某個元素時,通過這個元素的鍵的 hash 值可以得到其操作的是哪個區域,之后就鎖住對應區域的鎖對象即可,而其他區域的元素依然可以被其他線程訪問。這就好比一個廁所,里面有多個位置,每個位置每次只能有一個人上廁所,但是不能因為這一個人上廁所就把整個廁所給鎖掉,所以就是每個位置設置一把鎖,對應只負責這個位置即可。
* **WeakHashMap** 默認的初始容量是 16,最大容量為 1 << 30 ;默認擴容因子為 0.75;可以指定初始容量,但是處理過后的初始容量一定是 2 的次冪,好處是可以通過 & 運算來代替 % 運算提高效率;每次擴容時容量翻倍。節點(Entry)之間利用單項鏈表之間來處理 hash 值沖突
* **Set接口的實現類有:HashSet、TreeSet、LinkHashSet**
* Set的實現是基于Map的,將使用要保存的值都保存在Map的key上面,然后對Map的key進行相關操作
> 推薦閱讀:[https://blog.csdn.net/Hacker_ZhiDian](https://blog.csdn.net/Hacker_ZhiDian "https://blog.csdn.net/Hacker_ZhiDian")
# 4、Java異常處理機制

* **檢查性異常:**所謂檢查(**Checked**)是指編譯器要檢查這類異常,檢查的目的一方面是因為該類異常的發生難以避免,另一方面就是讓開發者去解決掉這類異常,所以稱為必須處理(try ...catch)的異常。如果不處理這類異常,集成開發環境中的編譯器一般會給出錯誤提示。**例如:**一個讀取文件的方法代碼邏輯沒有錯誤,但程序運行時可能會因為文件找不到而拋出FileNotFoundException,如果不處理這些異常,程序將來肯定會出錯。所以編譯器會提示你要去捕獲并處理這種可能發生的異常,不處理就不能通過編譯。
* **運行時異常(非檢查性異常):**?所謂非檢查(**Unchecked**)是指編譯器不會檢查這類異常,不檢查的則開發者在代碼的編輯編譯階段就不是必須處理,這類異常一般可以避免,因此無需處理(try ...catch)。如果不處理這類異常,集成開發環境中的編譯器也不會給出錯誤提示。**例如:**你的程序邏輯本身有問題,比如數組越界、訪問null對象,這種錯誤你自己是可以避免的。編譯器不會強制你檢查這種異常。
* **錯誤:**?錯誤不是異常,而是脫離程序員控制的問題。錯誤在代碼中通常被忽略。例如,當棧溢出時,一個錯誤就發生了,它們在編譯也檢查不到的
所有的異常類是從 java.lang.Exception 類繼承的子類。Exception 類是 Throwable 類的子類。除了Exception類外,Throwable還有一個子類Error 。Java 程序通常不捕獲錯誤Error。錯誤一般發生在嚴重故障時,它們在Java程序處理的范疇之外。Error 用來指示運行時環境發生的錯誤。例如,JVM 內存溢出。一般地,程序不會從錯誤中恢復。異常類有兩個主要的子類:IOException 類和 RuntimeException 類。
| | **異常**| **描述**|
|--|--|--|
| **Java中一些常見的非檢查性異常** |
|| ArithmeticException | 當出現異常的運算條件時,拋出此異常。例如,一個整數"除以零"時,拋出此類的一個實例。|
|| ArrayIndexOutOfBoundsException | 用非法索引訪問數組時拋出的異常。如果索引為負或大于等于數組大小,則該索引為非法索引。 |
| |ArrayStoreException | 試圖將錯誤類型的對象存儲到一個對象數組時拋出的異常。 |
| |ClassCastException | 當試圖將對象強制轉換為不是實例的子類時,拋出該異常。 |
| |IllegalArgumentException | 拋出的異常表明向方法傳遞了一個不合法或不正確的參數。 |
| |IllegalMonitorStateException | 拋出的異常表明某一線程已經試圖等待對象的監視器,或者試圖通知其他正在等待對象的監視器而本身沒有指定監視器的線程。|
| |IllegalStateException | 在非法或不適當的時間調用方法時產生的信號。換句話說,即 Java 環境或 Java 應用程序沒有處于請求操作所要求的適當狀態下。|
| |IllegalThreadStateException | 線程沒有處于請求操作所要求的適當狀態時拋出的異常。|
| |IndexOutOfBoundsException | 指示某排序索引(例如對數組、字符串或向量的排序)超出范圍時拋出。|
| |NegativeArraySizeException | 如果應用程序試圖創建大小為負的數組,則拋出該異常。 |
| |NullPointerException | 當應用程序試圖在需要對象的地方使用?null?時,拋出該異常 |
|| NumberFormatException | 當應用程序試圖將字符串轉換成一種數值類型,但該字符串不能轉換為適當格式時,拋出該異常。|
|| SecurityException| 由安全管理器拋出的異常,指示存在安全侵犯。|
| |StringIndexOutOfBoundsException | 此異常由?String?方法拋出,指示索引或者為負,或者超出字符串的大小。|
| |UnsupportedOperationException | 當不支持請求的操作時,拋出該異常。|
| **Java中的一些受檢異常** |
| |ClassNotFoundException | 應用程序試圖加載類時,找不到相應的類,拋出該異常。|
| |CloneNotSupportedException | 當調用?Object?類中的?clone?方法克隆對象,但該對象的類無法實現?Cloneable?接口時,拋出該異常。 |
| |IllegalAccessException | 拒絕訪問一個類的時候,拋出該異常。|
| |InstantiationException | 當試圖使用?Class?類中的?newInstance?方法創建一個類的實例,而指定的類對象因為是一個接口或是一個抽象類而無法實例化時,拋出該異常。 |
| |InterruptedException | 一個線程被另一個線程中斷,拋出該異常。|
| |NoSuchFieldException | 請求的變量不存在 |
| |NoSuchMethodException | 請求的方法不存在 |
### Exception的一些常用方法及說明
| Exception | 方法及說明|
|----|:-----|
| **public String getMessage()**| 返回關于發生的異常的詳細信息。這個消息在Throwable 類的構造函數中初始化了。 |
| **public Throwable getCause()**| 返回一個Throwable 對象代表異常原因。 |
| **public String toString()**|使用getMessage()的結果返回類的串級名字。 |
| **public void printStackTrace()** | 打印toString()結果和棧層次到System.err,即錯誤輸出流。 |
| **public StackTraceElement [] getStackTrace()** | 返回一個包含堆棧層次的數組。下標為0的元素代表棧頂,最后一個元素代表方法調用堆棧的棧底。 |
| **public Throwable fillInStackTrace()** |用當前的調用棧層次填充Throwable 對象棧層次,添加到棧層次任何先前信息中。 |
### 異常處理
```
try
{
// 程序代碼
}catch(ExceptionName e)
{
//Catch 塊1
}catch(ExceptionName e)
{
//Catch 塊2
} finally {
//不論是否發生異常,總會執行,所以通常
//做一些善后操作,如釋放資源等
}
```
### throws/throw 關鍵字:
如果一個方法沒有捕獲到一個檢查性異常,那么該方法必須使用 **throws 關鍵字來聲明異常**。throws 關鍵字放在方法簽名的尾部。
也可以使用 **throw 關鍵字拋出一個異常**,無論它是新實例化的還是剛捕獲到的。
# 5、正則表達式
參考資料:
> [http://www.runoob.com/java/java-regular-expressions.html](http://www.runoob.com/java/java-regular-expressions.html "http://www.runoob.com/java/java-regular-expressions.html")
>
> [http://www.cnblogs.com/interdrp/p/5586587.html](http://www.cnblogs.com/interdrp/p/5586587.html "http://www.cnblogs.com/interdrp/p/5586587.html")