算法、正则、异常
此笔记参考黑马教程,仅学习使用,如有侵权,联系必删
文章目录
- 算法、正则、异常
- 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("您输入的价格是不合适的!");}}}
}