算法、正則、異常
此筆記參考黑馬教程,僅學習使用,如有侵權,聯系必刪
文章目錄
- 算法、正則、異常
- 1. 常見算法
- 1.1 簡單認識算法
- 1.1.1 什么是算法?
- 1.1.2 為什么要學習算法?
- 1.2 排序算法
- 1.2.1 冒泡排序
- 1.2.1.1 實現冒泡排序的關鍵步驟分析
- 代碼實現
- 1.2.2 選擇排序
- 1.2.2.1 選擇排序的關鍵
- 代碼實現
- 1.3 查找算法
- 1.3.1 基本查找/順序查找
- 1.3.2 二分查找(折半查找)
- 代碼實現
- 2. 正則表達式
- 2.1 概述、初體驗
- 2.2 書寫規則
- 2.2.1 正則表達式的書寫規則
- 2.2.2 其他幾個常用的符號
- 2.3 應用案例
- 代碼演示
- 2.4 用于查找信息
- 代碼實現
- 2.5 用于搜索替換、分割內容
- 代碼演示
- 3. 異常
- 3.1 認識異常
- 3.1.1 什么是異常?
- 3.1.2 異常的體系
- 3.1.3 拋出異常(throws)
- 3.1.4 捕獲異常(try...catch)
- 代碼演示
- 3.2 自定義異常
- 3.2.1 自定義異常的種類
- 自定義運行時異常
- 自定義編譯時異常
- 3.2.2 異常有什么作用?
- 代碼演示
- 3.3 異常的處理
- 3.3.1 開發中對于異常的常見處理方式
- 3.3.2 拋出異常(throws)
- 3.3.3 捕獲異常(try...catch)
- 代碼演示
1. 常見算法
1.1 簡單認識算法
1.1.1 什么是算法?
- 解決某個實際問題的過程和方法
1.1.2 為什么要學習算法?
- 編程思維
- 面試
1.2 排序算法
學習算法的技巧:
- 先搞清楚算法的流程
- 直接去推敲如何寫代碼
1.2.1 冒泡排序
- 每次從數組中找出最大值放在數組的后面去
1.2.1.1 實現冒泡排序的關鍵步驟分析
- 確定總共需要做幾輪:數組的長度 - 1
- 每輪比較幾次:
- 當前位置大于后一個位置則交換數據
代碼實現
package Advanced.b_algorithm;import java.util.Arrays;/*** 目標:掌握冒泡排序的編寫*/
public class 冒泡排序 {public static void main(String[] args) {// 1. 準備一個數組int[] arr = {5, 2, 3, 1};// 2.定義一個循環控制排幾輪for (int i = 0; i < arr.length; i++) {// 3. 定義一個循環控制比較幾輪for (int j = 0; j < arr.length - i - 1; j++) {// 判斷當前位置的元素值,是否大于后一個位置處的元素值,如果大則交換if (arr[j] > arr[j + 1]) {int temp = arr[j + 1];arr[j + 1] = arr[j];arr[j] = temp;}}}System.out.println(Arrays.toString(arr)); // [1, 2, 3, 5]}
}
1.2.2 選擇排序
- 每輪選擇當前位置,開始找出后面的較小值與該位置交換

1.2.2.1 選擇排序的關鍵
- 確定總共需要選擇幾輪:數組的長度 - 1
- 控制每輪從以前位置為基準,與后面元素選擇幾次
代碼實現
package Advanced.b_algorithm;import java.util.Arrays;/*** 目標:掌握選擇排序*/
public class 選擇排序 {public static void main(String[] args) {// 1. 準備好一個數組int[] arr = {5, 1, 3, 2};// 2. 控制選擇幾輪for (int i = 0; i < arr.length - 1; i++) {// 3. 控制每輪選擇幾次for (int j = i + 1; j < arr.length; j++) {// 判斷當前位置是否大于后面位置處的元素值,若大于則交換if (arr[i] > arr[j]) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}}}System.out.println(Arrays.toString(arr)); // [1, 2, 3, 5]}
}
- 優化
package Advanced.b_algorithm;import java.util.Arrays;/*** 目標:掌握選擇排序*/
public class 選擇排序 {public static void main(String[] args) {// 1. 準備好一個數組int[] arr = {5, 1, 3, 2};// 2. 控制選擇幾輪for (int i = 0; i < arr.length - 1; i++) {int minIndex = i;// 3. 控制每輪選擇幾次for (int j = i + 1; j < arr.length; j++) {// 判斷當前位置是否大于后面位置處的元素值,若大于則交換if (arr[minIndex] > arr[j]) {minIndex = j;}}// 決定是否交換if (i != minIndex) {int temp = arr[i];arr[i] = arr[minIndex];arr[minIndex] = temp;}}System.out.println(Arrays.toString(arr)); // [1, 2, 3, 5]}
}
1.3 查找算法
1.3.1 基本查找/順序查找
就是暴力一個一個循環查找
注意:在數據量特別大的時候,基本查找這種從前往后挨個找的形式,性能是很差的!
1.3.2 二分查找(折半查找)
前提條件:數組中的數據必須是有序的
核心思想:每次排除一半的數據,查詢數據的性能明顯提高極多
二分查找正常的折半條件應該是開始位置 left <= 結束位置 right
代碼實現
package Advanced.b_algorithm;import java.util.Arrays;/*** 目標:掌握二分查找*/
public class 二分查找 {public static void main(String[] args) {// 1. 準備號一個數組int[] arr = {7, 23, 79, 81, 103, 127, 131, 147};System.out.println(binarySearch(arr, 81)); // 3System.out.println(Arrays.binarySearch(arr, 81)); // 3}public static int binarySearch(int[] arr, int data) {// 1. 定義兩個變量,一個站在左邊位置,一個站在右邊位置int left = 0;int right = arr.length - 1;// 2. 定義一個循環控制折半while (left <= right) {// 3. 每次折半,都算出中間位置處的索引int middle = (left + right) / 2;// 4. 判斷當前要找的元素值,與中間位置處的元素值的大小情況if (data < arr[middle]) {// 往左走,截止位置(右邊位置) = 中間位置 - 1right = middle - 1;} else if (data > arr[middle]) {// 往右邊找,起始位置(左邊位置) = 中間位置 + 1} else {// 中間位置處的元素值,正好等于我們要找的元素值return middle;}}return -1; // -1特殊結果,就代表沒有找到數據,數組中不存在該數據}
}
2. 正則表達式
2.1 概述、初體驗
- 就是由一些特定的字符組成,代表的是一個規則
作用一:用來校驗數據格式是否合法
作用二:在一段文本中查找滿足要求的內容
使用正則表達式校驗數據,你的代碼風格會非常的簡單、便捷
package Advanced.c_regex;/*** 目標:體驗一下使用正則表達式來校驗數據格式的合法性* 需求:校驗QQ號是否正確:要求全部是數字,長度是(6-20)之間,不能以0開頭*/
public class RegexTest1 {public static void main(String[] args) {System.out.println(checkQQ(null)); // falseSystem.out.println(checkQQ("123456789")); // trueSystem.out.println(checkQQ("21478fadf15")); // falseSystem.out.println("------------------------");System.out.println(checkQQ1(null)); // falseSystem.out.println(checkQQ1("123456789")); // trueSystem.out.println(checkQQ1("21478fadf15")); // false}public static boolean checkQQ1(String qq) {return qq != null && qq.matches("[1-9]\\d{5,19}");}public static boolean checkQQ(String qq) {// 1. 判斷qq號碼是否為nullif (qq == null || qq.startsWith("0") || qq.length() < 6 || qq.length() > 20) {return false;}// 2. qq至少不是null,不是以0開頭,滿足6-20之間的長度// 判斷qq號碼中是否都是數字for (int i = 0; i < qq.length(); i++) {// 根據索引提取當前位置處的字符char ch = qq.charAt(i);// 判斷ch記住的字符,如果不是數字,qq號就不合法if (ch < '0' || ch > '9') {return false;}}// 3. 說明qq號肯定是合法的return true;}
}
2.2 書寫規則
String 提供了一個匹配正則表達式的方法
public boolean matches(String regex)
判斷字符串是否匹配正則表達式,匹配返回 true,不匹配返回 false
2.2.1 正則表達式的書寫規則
字符類(只能匹配單個字符) | 說明 |
---|---|
[abc] | 只能是 a,b 或 c |
[^abc] | 除了 a,b,c 之外的任何字符 |
[a-zA-Z] | a 到 z,A 到 z,包括(范圍) |
[a-d[m-p]] | a 到 d,或 m 到 p |
[a-z&&[def]] | d,e 或 f(交集) |
[a-z&&[^bc]] | a 到 z,除了 b 和 c(等同于 [ad-z] ) |
[a-z&&[^m-p]] | a 到 z,除了 m到 p(等同于 [a-lq-z] ) |
預定義字符(只能匹配單個字符) | 說明 |
---|---|
. | 任何字符 |
\d | 一個數字:[0-9] |
\D | 非數字:[^0-9] |
\s | 一個空白字符 |
\S | 非空白字符:[^\s] |
\w | [a-zA-Z_0-9] |
\W | [^\w] 一個非單詞字符 |
數量詞 | 說明 |
---|---|
X? | X,一次或0次 |
X* | X,零次或多次 |
X+ | X,一次或多次 |
X{n} | X,正好 n 次 |
X{n, } | X,至少 n 次 |
X{n,m} | X,至少 n 但不超過 m 次 |
2.2.2 其他幾個常用的符號
(?i)
:忽略大小寫
|
:或
()
:分組
2.3 應用案例
需求:
校驗用戶輸入的電話、郵箱、時間是否合法
代碼演示
package Advanced.c_regex;import java.util.Scanner;/*** 目標:校驗用戶輸入的電話、郵箱、時間是否合法*/
public class RegexTest3 {public static void main(String[] args) {checkPhone();}public static void checkPhone() {while (true) {System.out.println("請您輸入您的電話號碼(手機|座機):");Scanner sc = new Scanner(System.in);String phone = sc.nextLine();if (phone.matches("(1[3-9]\\d{9})|(0\\d{2,7}-?[1-9]\\d{4,19})")) {System.out.println("您輸入的號碼格式正確~~~");break;} else {System.out.println("您輸入的號碼格式不正確");}}}public static void checkEmail() {while (true) {System.out.println("請您輸入您的郵箱:");Scanner sc = new Scanner(System.in);String phone = sc.nextLine();if (phone.matches("\\w{2,}@\\w{2,20}(\\.\\w{2,10}){1,2}")) {System.out.println("您輸入的郵箱格式正確~~~");break;} else {System.out.println("您輸入的郵箱格式不正確");}}}
}
2.4 用于查找信息
在一段文本中查找滿足要求的內容
需求:
請把下面文本中的電話、郵箱、座機號碼、熱線都爬取出來
代碼實現
package Advanced.c_regex;import java.util.regex.Matcher;
import java.util.regex.Pattern;/*** 目標:掌握使用正則表達式查找內容*/
public class RegexTest4 {public static void main(String[] args) {method1();}// 需求1:從一下內容中爬取出:手機、郵箱、座機、400電話等信息public static void method1() {String data = "來黑馬程序員學習Java,\n" +"電話:1866668888,18699997777,\n" +"或者聯系郵箱:boniu@itcast.cn,\n" +"座機電話:01036517895,010-98951256\n" +"郵箱:bozai@itcast.cn,\n" +"郵箱:dlei0009@163.com,\n" +"熱線電話:400-618-9090,400-618-4000,400618400,4006189090";// 1. 定義爬取規則String regex = "(1[3-9]\\d{9})|(0\\d{2,7}-?[1-9]\\d{4,19})|(\\w{2,}@\\w{2,20}(\\.\\w{2,10}){1,2})" + "|(400-?\\d{3,7}-?\\d{3,7})";// 2. 把正則表達式封裝成一個Pattern對象Pattern pattern = Pattern.compile(regex);// 3. 通過pattern對象去獲取查找內容的匹配器對象Matcher matcher = pattern.matcher(data);// 4. 定義一個循環開始爬取信息while (matcher.find()) {String rs = matcher.group();System.out.println(rs);}}
}
2.5 用于搜索替換、分割內容
正則表達式用于搜索替換、分割內容,需要結合 String 提供的如下方法完成:
方法名 | 說明 |
---|---|
public String replaceAll(String regex, String newStr) | 按照正則表達式匹配的內容進行替換 |
public String[] split(String regex) | 按照正則表達式匹配的內容進行分割字符串,返回一個字符串數組 |
代碼演示
package Advanced.c_regex;import java.util.Arrays;/*** 目標:掌握使用正則表達式做搜索替換、內容分割*/
public class RegexTest5 {public static void main(String[] args) {// 1. public String replaceAll(String regex, String newStr):按照正則表達式匹配的內容進行替換// 需求1:請把 古力娜扎ai888迪麗熱巴999aa5566馬爾扎哈fbbfsfs42425卡爾扎巴,中間的非中文字符替換成 ”-“String s1 = "古力娜扎ai888迪麗熱巴999aa5566馬爾扎哈fbbfsfs42425卡爾扎巴";System.out.println(s1.replaceAll("\\w+", "-")); // 古力娜扎-迪麗熱巴-馬爾扎哈-卡爾扎巴// 需求2(拓展):某語言系統,收到一個口吃的人說”我我我喜歡編編編編編編程!“,需要優化成”我喜歡編程“String s2 = "我我我喜歡編編編編編編程!";/*** (.)一組,匹配任意字符的* \\1:為這個組聲明一個組號:1號* +:聲明必須是重復的字* $1:可以去到第1組代表的那個重復的字*/System.out.println(s2.replaceAll("(.)\\1+", "$1")); // 我喜歡編程!// 2. public String[] split(String regex):按照正則表達式的內容進行分割字符串,返回一個字符串數組// 需求1:請把 古力娜扎ai888迪麗熱巴999aa5566馬爾扎哈fbbfsfs42425卡爾扎巴 中的人名獲取出來String s3 = "古力娜扎ai888迪麗熱巴999aa5566馬爾扎哈fbbfsfs42425卡爾扎巴";String[] names = s3.split("\\w+");System.out.println(Arrays.toString(names)); // [古力娜扎, 迪麗熱巴, 馬爾扎哈, 卡爾扎巴]}
}
3. 異常
3.1 認識異常
3.1.1 什么是異常?
異常就是代表程序出現的問題
3.1.2 異常的體系
Error:代表的系統級別錯誤(屬于嚴重問題),也就是說系統一旦出現問題,sun 公司會把這些問題封裝成 Error 對象給出來,說白了,Error 是給 sun 公司自己用的,不是給我們程序員用的,因此我們開發人員不用管它
Exception:叫異常,它代表的才是我們程序員可能出現的問題,所以,我們程序員通常會用 Exception 以及它的孩子來封裝程序出現的問題
- 運行時異常:RuntimeException 及其子類,編譯階段不會出現錯誤提醒,運行時出現異常(如:數組索引越界異常)
- 編譯時異常:編譯階段就會出現錯誤提醒的(如:日期解析異常)
3.1.3 拋出異常(throws)
- 在方法上使用 throws 關鍵字,可以將方法內部出現的異常拋出去給調用者處理
方法 throws 異常1, 異常2, 異常3...{...
}
3.1.4 捕獲異常(try…catch)
- 直接捕獲程序出現的異常
try{// 監視可能出現異常的代碼!
} catch (異常類型1 變量) {// 處理異常
} catch (異常類型2 變量) {// 處理異常
}...
代碼演示
package Advanced.d_exception;import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;/*** 目標:認識異常*/
public class ExceptionTest1 {public static void main(String[] args) throws ParseException {
// Integer.valueOf("abc");// int[] arr = {11,22,33};
// System.out.println(arr[5]);// try {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");Date d = sdf.parse("2023-11-11 10:24");System.out.println(d);
// } catch (ParseException e) {
// e.printStackTrace();
// }}
}
3.2 自定義異常
- Java 無法為這個世界上全部的問題都提供異常類來代表,如果企業自己的某種問題,想通過異常來表示,以便用異常來管理該問題,那就需要自己來定義異常類了
3.2.1 自定義異常的種類
自定義運行時異常
- 定義一個異常類繼承 RuntimeException
- 重寫構造器
- 通過
throw new 異常類(xxx)
來創建異常對象并拋出 - 編譯階段不報錯,提醒不強烈,運行時才可能出現!!!
自定義編譯時異常
- 定義一個異常類繼承 Exception
- 重寫構造器
- 通過
throw new 異常類(xxx)
來創建異常對象并拋出 - 編譯階段就報錯,提醒更加強烈!
3.2.2 異常有什么作用?
- 異常是用來查詢系統 Bug 的關鍵參考信息
- 異常可以作為方法內部的一種特殊返回值,以便通知上層調用者底層的執行情況
代碼演示
- AgeIllegalRuntimeException.java
package Advanced.d_exception;// 1. 必須讓這個類繼承自RuntimeException,才能成為一個運行時異常類
public class AgeIllegalRuntimeException extends RuntimeException {public AgeIllegalRuntimeException() {}public AgeIllegalRuntimeException(String message) {super(message);}
}
- AgeIllegalException.java
package Advanced.d_exception;// 1. 必須讓這個類繼承自Exception,才能成為一個編譯時異常類
public class AgeIllegalException extends Exception {public AgeIllegalException() {}public AgeIllegalException(String message) {super(message);}
}
- ExceptionTest2.java
package Advanced.d_exception;/*** 目標:掌握自定義異常,以及異常的作用*/
public class ExceptionTest2 {public static void main(String[] args) {// 需求:保存一個合法的年齡try {saveAge(160);System.out.println("底層執行成功!");} catch (Exception e) {e.printStackTrace();System.out.println("底層出現了bug!");}try {saveAge2(195);System.out.println("saveAge2底層執行是成功的!");} catch (AgeIllegalException e) {e.printStackTrace();System.out.println("saveAge2底層執行是出現bug的!");}}public static void saveAge(int age) {if (age > 0 && age < 150) {System.out.println("年齡被成功保存:" + age);} else {// 用一個異常對象封裝這個問題// throw 拋出去這個異常對象throw new AgeIllegalRuntimeException("/age is illegal, your age is " + age);}}public static void saveAge2(int age) throws AgeIllegalException {if (age > 0 && age < 150) {System.out.println("年齡被成功保存:" + age);} else {// 用一個異常對象封裝這個問題// throw 拋出去這個異常對象// throws 用在方法上,拋出方法內部的異常throw new AgeIllegalException("/age is illegal, your age is " + age);}}
}
3.3 異常的處理
3.3.1 開發中對于異常的常見處理方式
3.3.2 拋出異常(throws)
- 在方法上使用 throws 關鍵字,可以將方法內部出現的異常拋出去給調用者處理
方法 throws 異常1, 異常2, 異常3...{...
}
// 推薦方式
方法 throws Exception{
}
// Exception代表可以捕獲一切異常
3.3.3 捕獲異常(try…catch)
- 直接捕獲程序出現的異常
try{// 監視可能出現異常的代碼!
} catch (異常類型1 變量) {// 處理異常
} catch (異常類型2 變量) {// 處理異常
}...
// 推薦方式
try {// 可能出現異常的代碼!
} catch (Exception e) {e.printStackTrace(); // 直接打印異常對象的信息
}
// Exception代表可以捕獲一切異常
代碼演示
- ExceptionTest3_2.java
package Advanced.d_exception;import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;/*** 目標:異常的處理*/
public class ExceptionTest3_2 {public static void main(String[] args) {try {test1();} catch (Exception e) {System.out.println("您要找的文件不存在!");e.printStackTrace(); // 打印出這個異常對象的信息,記錄下來}}public static void test1() throws Exception {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");Date d = sdf.parse("2023-11-11 10:24:11");System.out.println(d);test2();}public static void test2() throws Exception {// 讀取文件的FileInputStream is = new FileInputStream("D:/meinv.png");}
}
- ExceptionTest4.java
package Advanced.d_exception;import java.util.Scanner;/*** 目標:掌握異常的處理方式:捕獲異常,嘗試修復*/
public class ExceptionTest4 {public static void main(String[] args) {// 需求:調用一個方法,讓用戶輸入一個合適的價格返回為止// 嘗試修復while (true) {try {System.out.println(getMoney());break;} catch (Exception e) {System.out.println("請您輸入合法的數字!!!");}}}public static double getMoney() {Scanner scanner = new Scanner(System.in);while (true) {System.out.println("請您輸出合適的價格:");double money = scanner.nextDouble();if (money >= 0) {return money;} else {System.out.println("您輸入的價格是不合適的!");}}}
}