一、正则表达式
用来描述或者匹配一系列符合某个语句规则的字符串
正则表达式定义了字符串的模式,可以用来搜索、编辑或处理文本。
正则表达式是由普通字符(例如字符 a 到 z)以及特殊字符(称为"元字符")组成的文字模式。模式描述在搜索文本时要匹配的一个或多个字符串。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。
1. 常用正则表达式
字符 | 描述 |
---|---|
\ | 将下一个字符标记为一个特殊字符、或一个原义字符、或一个 向后引用、或一个八进制转义符。例如,‘n’ 匹配字符 “n”。’\n’ 匹配一个换行符。序列 ‘\\’ 匹配 “\” 而 “\(” 则匹配 “(” |
^ | 匹配输入字符串的开始位置 |
$ | 匹配输入字符串的结束位置 |
* | 匹配前面的子表达式零次或多次。例如,zo* 能匹配 “z” 以及 “zoo”。* 等价于{0,} |
+ | 匹配前面的子表达式一次或多次。例如,‘zo+’ 能匹配 “zo” 以及 “zoo”,但不能匹配 “z”。+ 等价于 {1,} |
? | 匹配前面的子表达式零次或一次。例如,“Mi(ku)?” 可以匹配 “Mi” 或 “Miku” 。? 等价于 {0,1} |
{n} | n 是一个非负整数。匹配确定的 n 次。例如,‘o{2}’ 不能匹配 “Bob” 中的 ‘o’,但是能匹配 “food” 中的两个 o |
{n,} | n 是一个非负整数。至少匹配n 次。例如,‘o{2,}’ 不能匹配 “Bob” 中的 ‘o’,但能匹配 “foooood” 中的所有 o。‘o{1,}’ 等价于 ‘o+’。‘o{0,}’ 则等价于 ‘o*’ |
{n,m} | m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,“o{1,3}” 将匹配 “fooooood” 中的前三个 o。‘o{0,1}’ 等价于 ‘o?’。请注意在逗号和两个数之间不能有空格 |
? | 当该字符紧跟在任何一个其他限制符 * + ? {n} {n,} {n,m} 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串 “oooo”,‘o+?’ 将匹配单个 “o”,而 ‘o+’ 将匹配所有 ‘o’ |
. | 匹配除换行符(\n、\r)之外的任何单个字符。要匹配包括 ‘\n’ 在内的任何字符,请使用像"(.|\n)"的模式 |
\d | 匹配一个数字字符。等价于 [0-9] |
\D | 匹配一个非数字字符。等价于 [^0-9] |
\f | 匹配一个换页符。等价于 \x0c 和 \cL |
\n | 匹配一个换行符。等价于 \x0a 和 \cJ |
\r | 匹配一个回车符。等价于 \x0d 和 \cM |
\s | 匹配任何空白字符,包括空格、制表符、换页符等等。等价于[ \f\n\r\t\v] |
\S | 匹配任何非空白字符。等价于 [^ \f\n\r\t\v] |
\t | 匹配一个制表符。等价于 \x09 和 \cI |
\v | 匹配一个垂直制表符。等价于 \x0b 和 \cK |
\w | 匹配字母、数字、下划线。等价于 [A-Za-z0-9_] |
\W | 匹配非字母、数字、下划线。等价于 [^A-Za-z0-9_]。 |
\b | 匹配一个字边界,即字与空格间的位置。例如,“er\b"匹配"never"中的"er”,但不匹配"verb"中的"er" |
\B | 非字边界匹配。“er\B"匹配"verb"中的"er”,但不匹配"never"中的"er" |
() | 表示捕获分组,() 会把每个分组里的匹配的值保存起来,多个匹配值可以通过数字n来查看 (n是一个数字,表示第 n 个捕获组的内容) |
2. 运算符优先级
正则表达式从左到右进行计算,并遵循优先级顺序,这与算术表达式非常类似。
运算符 | 描述(从最高到最低) |
---|---|
\ | 转义符 |
() (?:) (?=) [] | 圆括号和方括号 |
* + ? {n} {n,} {n,m} | 限定符 |
^ $ \任何元字符、任何字符 | 定位点和序列(即:位置和顺序) |
| | 替换,“或"操作 字符具有高于替换运算符的优先级,使得"m|food"匹配"m"或"food”。若要匹配"mood"或"food",请使用括号创建子表达式,从而产生"(m|f)ood" |
案例:把一个字符串中的电话号码中间4位替换成* 如:130****1111
String str = "樱泽墨15112341111 英梨梨13012342222 加藤惠22233344455";
String regex = "(1\\d{2})(\\d{4})(\\d{4})";
//替换
String replaceAll = str.replaceAll(regex, "$1****$3");
System.out.println(replaceAll);
//底层源码:
//创建正则表达式的对象
//Pattern pattern = Pattern.compile(regex);
//获取匹配结果的对象
//Matcher matcher = pattern.matcher(str);
//替换
//String result = matcher.replaceAll("$1****$3");
//System.out.println(result);
3. Pattern类 & Matcher类
Pattern: 代表正则表达式的匹配模式
pattern 对象是一个正则表达式的编译表示。Pattern 类没有公共构造方法。要创建一个 Pattern 对象,你必须首先调用其公共静态编译方法,它返回一个 Pattern 对象。该方法接受一个正则表达式作为它的第一个参数。
Matcher: 提供了对正则表达式的分组支持,以及对正则表达式的多次匹配支持
Matcher 对象是对输入字符串进行解释和匹配操作的引擎。与Pattern 类一样,Matcher 也没有公共构造方法。你需要调用 Pattern 对象的 matcher 方法来获得一个 Matcher 对象。
案例1:校验QQ邮箱
String str = "5201314@qq.com";
String regex = "\\d{5,11}@qq\\.com";
//判断字符串str是否匹配正则表达式regex
boolean matches = str.matches(regex);
//底层源码:
//boolean matches = Pattern.matches(regex , str);
System.out.println(matches);//true
案例2:分隔路径
String str = "F:\\动漫\\穿越\\刀剑神域.mp4";
//匹配 :\\ 或 \\
String regex = ":?\\\\";
//依据正则表达式分隔字符串
String[] split = str.split(regex);
//底层源码
//创建匹配模式对象
//Pattern pattern = Pattern.compile(regex);
//String[] split = pattern.split(str);
for (String s : split) {
System.out.println(s);
}
/*输出结果:
F
动漫
穿越
刀剑神域.mp4
案例3:用Pattern和Matcher 找到前端代码中的图片路径
String str = "<img src='wife/艾米莉娅.png'/><input type='image' src='submit.gif' /><img src='樱泽墨.jpg'/>";
String regex = "<img\\b[^>]*\\bsrc\\b\\s*=\\s*('|\")?([^'\"\n\r\f>]+(\\.jpg|\\.bmp|\\.eps|\\.gif|\\.mif|\\.miff|\\.png|\\.tif|\\.tiff|\\.svg|\\.wmf|\\.jpe|\\.jpeg|\\.dib|\\.ico|\\.tga|\\.cut|\\.pic)\\b)[^>]*>";
//获取正则表达式对象
Pattern pattern = Pattern.compile(regex);
//匹配结果
Matcher matcher = pattern.matcher(str);
//遍历匹配结果
while (matcher.find()) {
String result = matcher.group(2);//获取正则表达式里第二个括号(组)里的内容
System.out.println(result);
}
/*运行结果:
wife/艾米莉娅.png
樱泽墨.jpg
*/
System.out.println("在字符串中是否整个匹配:" + matcher.matches());//false
System.out.println("在字符串中是否开头就匹配:" + matcher.lookingAt());//true
System.out.println("在字符串中是否有包含匹配:" + matcher.find());//true
总结: Pattern与Matcher一起合作。Matcher类提供了对正则表达式的分组支持,以及对正则表达式的多次匹配支持. 单独用Pattern只能使用Pattern.matches(String regex,CharSequence input)一种最基础最简单的匹配。
二、日期时间类
1. Date - 日期类
java.util.Date类表示特定的瞬间,精确到毫秒。
java.util 包提供了 Date 类来封装当前的日期和时间。Date 类提供两个构造函数来实例化 Date 对象。
1.构造函数使用当前日期和时间来初始化对象。
Date( )
Date date = new Date();
System.out.println(date);
// 星期 月份 日期 时:分:秒 时区 年份
// Thu Jul 08 23: 09: 28 CST 2021
2.构造函数接收一个参数,该参数是从1970年1月1日起的毫秒数。
Date(long millisec)
//从1970.1.1 0:0:0往后推1000毫秒
Date date = new Date(1000);
System.out.println(date);
//Thu Jan 01 08:00:01 CST 1970
//中国统一采用东八区时间,所以时间加了8小时
2. SimpleDateFormat - 格式化日期类
SimpleDateFormat 是一个以语言环境敏感的方式来格式化和分析日期的类。允许选择任何自定义日期时间格式来运行。
SimpleDateFormat simpleDateFormatf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
//格式化日期:date 转 字符串
String format = simpleDateFormatf.format(new Date());
System.out.println(format); //2021年07月08日 23:23:22
//解析:字符串 转 date
Date date = simpleDateFormatf.parse("Thu Jul 08 23:22:57 CST 2021");
System.out.println(date);// Thu Jul 08 11:37:48 CST 2021
日期和时间的格式化编码
字母 | 描述 | 示例 |
---|---|---|
G | 纪元标记 | AD |
y | 四位年份 | 2001 |
M | 月份 | July or 07 |
d | 一个月的日期 | 10 |
h | A.M./P.M. (1~12)格式小时 | 12 |
H | 一天中的小时 (0~23) | 22 |
m | 分钟数 | 30 |
s | 秒数 | 55 |
S | 毫秒数 | 234 |
E | 星期几 | Tuesday |
D | 一年中的日子 | 360 |
F | 一个月中第几周的周几 | 2 (second Wed. in July) |
w | 一年中第几周 | 40 |
W | 一个月中第几周 | 1 |
a | A.M./P.M. 标记 | PM |
k | 一天中的小时(1~24) | 24 |
K | A.M./P.M. (0~11)格式小时 | 10 |
z | 时区 | Eastern Standard Time |
3. Calendar - 日历类
Calendar类(日历)是一个抽象基类,主要用于完成日期字段之间相互操作的功能。即可以设置和获取日期数据的特定部分。
创建一个代表系统当前日期的Calendar对象
Calendar c = Calendar.getInstance();//默认是当前日期
创建一个指定日期的Calendar对象
使用Calendar类代表特定的时间,需要先创建一个Calendar的对象,然后再设定该对象中的年月日参数来完成。
//创建一个代表2021年7月8日的Calendar对象
Calendar c = Calendar.getInstance();
c.set(2021, 7 , 8);
Calendar类对象字段类型
常量 | 描述 |
---|---|
Calendar.YEAR | 年份 |
Calendar.MONTH | 月份 |
Calendar.DATE | 日期 |
Calendar.DAY_OF_MONTH | 日期,和上面的字段意义完全相同 |
Calendar.HOUR | 12小时制的小时 |
Calendar.HOUR_OF_DAY | 24小时制的小时 |
Calendar.MINUTE | 分钟 |
Calendar.SECOND | 秒 |
Calendar.DAY_OF_WEEK | 星期几 |
//获取当前日期的Calendar类的对象
Calendar c = Calendar.getInstance();
// 获得年份
int year = c.get(Calendar.YEAR);
// 获得月份(从0开始计算)
int month = c.get(Calendar.MONTH) + 1;
// 获得日期
int date = c.get(Calendar.DATE);
// 获得小时
int hour = c.get(Calendar.HOUR_OF_DAY);
// 获得分钟
int minute = c.get(Calendar.MINUTE);
// 获得秒
int second = c.get(Calendar.SECOND);
// 获得星期几(注意:1代表星期日、2代表星期一、3代表星期二,以此类推)
int day = c.get(Calendar.DAY_OF_WEEK);
System.out.println(date);//8
//把c对象的日期加上10,其它所有的数值会被重新计算
c.add(Calendar.DATE, 10);
System.out.println(c.get(Calendar.DATE));//18
//其他字段属性add的意义以此类推
//把c对象代表的年份设置为2008年,其他的所有数值会被重新计算
c.set(Calendar.YEAR,2008);
System.out.println(c.get(Calendar.YEAR));//2008
//其他字段属性set的意义以此类推
三、Math类
Math 包含了用于执行基本数学运算的属性和方法,如初等指数、对数、平方根和三角函数。
Math类是final类,Math 的方法都被定义为 static 形式,通过 Math 类可以在主函数中直接调用。
1. Math类的常用方法
System.out.println("求次方:" + Math.pow(3, 2));//9.0
System.out.println("求平方根:" + Math.sqrt(9));//3.0
System.out.println("求绝对值:" + Math.abs(-100));//100
System.out.println("向上取整(天花板):" + Math.ceil(1.1));//2.0
System.out.println("向下取整(地板):" + Math.floor(1.9));//1.0
System.out.println("四舍五入:" + Math.round(1.4));//1
System.out.println("获取随机数0~1(不包含1):" + Math.random());//0.4523198926846782
System.out.println("最大值:" + Math.max(10, 20));//20
System.out.println("最小值:" + Math.min(10, 20));//10
注意: Math.round()是在参数的基础上加0.5然后向下取整,方法内部调用了floor方法
Math.round(-1.5)的结果是 -1
-1.5加0.5 等于 -1.0 向下取整就是 -1
需求:随机出1~100
System.out.println((int)(Math.random()*100)+1);
Math.abs();有可能返回负数吗?
System.out.println(Math.abs(Integer.MIN_VALUE));
首先我们看Math.abs()
的源码:
public static int abs(int a) {
return (a < 0) ? -a : a;
}
按照Java 语言规范的第15.15.4中,-x等于(~x)+1,其中~是位运算符。
也就是说int类型的最小值是-2147483648,首先进行了符号位的运算,把-2147483648(也就是符号1,后面31个1)转变成2147483647(符号位0,后面31个1),这里并不是之前数学上直接负负得正得到2147483648,显然这已经超过了int类型最大值。然后把得到的2147483647(这里已经是int类型的最大值),然后进行+1操作,得到了-2147483648(符号位1,后面31个1)。
2. 静态导入(了解)
当使用一个类里面的静态方法或者静态变量时,每次都需要写类名。如果不想写类名,想直接写方法名或者变量名,则可以考虑使用静态导入
语法:
import static 包名.类名.*; //导入该类下的所有静态方法和常量
例如:
import static java.lang.Math.*; //导入Math下的所有方法和变量(包括常量)
//代码中可以直接使用方面和变量名,而不需要前缀Math。
max(3,4);
缺点: 可读性差
如果自己写了同名方法,会优先调用(就近原则)
public static void main(String[] args) {
System.out.println("求次方:" + pow(3, 2));//88888
System.out.println("最大值:" + max(10, 20));//20
System.out.println("最小值:" + min(10, 20));//10
}
public static int pow(int a,int b){
return 88888;
}
四、Random类
此类用于生成随机数
1. Random随机类的使用
//创建一个随机数对象
Random random = new Random();
System.out.println("随机int值:" + random.nextInt());//1323220369
System.out.println("随机int值(0~9):" + random.nextInt(10));//5
System.out.println("随机boolean值:" + random.nextBoolean());//false
System.out.println("随机double值:" + random.nextDouble());//0.9319247552571699
需求:点名器
String[] names = {"樱岛麻衣","椎名真白","艾米莉娅","雷姆","加藤惠","一之濑千鹤","英梨梨","更科瑠夏","樱泽墨","本间芽衣子","小鸟游六花","莱卡"};
Random random = new Random();
int index = random.nextInt(names.length);
System.out.println(names[index]);
2. 深入理解Random的随机功能
生产随机数需要种子(Seed),且如果种子固定,random()每次运行生成的随机数(其实是伪随机数)也是固定的;因为返回的随机数是根据稳定的算法得出的稳定结果序列,并且Seed就是这个算法开始计算的第一个值
Random类中不含参构造方法每次都使用当前时间(纳秒)作为种子,而含参构造方法是以一个固定值作为种子。种子数固定,随机值也是固定的。
1毫秒=1k微妙=1m纳秒=1b皮秒
//设置种子数为1000
Random random = new Random(1000);
//因为种子数固定,结果并不随机,一直固定
System.out.println("随机int值:" + random.nextInt());//-1244746321
System.out.println("随机int值:" + random.nextInt(10));//5
五、System类
-
System类提供了一些静态属性和方法,允许通过类名直接调用。
-
System类提供了代表标准输入、标准输出、错误输出的类属性。
-
System类提供了一些静态方法用于访问环境变量、系统属性的方法。
1. System-系统类的属性
//系统标准的输入流(方向:控制台->程序)
InputStream inputStream = System.in;
Scanner scan = new Scanner(inputStream);
String next = scan.next();//输入字符串
scan.close();//关闭资源
//系统标准的输出流(方向:程序->控制台)
PrintStream out = System.out;
out.println(next);
//系统标准的错误输出流(方向:程序->控制台)
PrintStream err = System.err;
err.println(next);
研究System中的out和err
System.out.println("小明");
System.err.println("小红");
System.out.println("小强");
/*输出结果随机,例如
小明 小明 小红 小明小红
小强 小红 小明 ......
小红 小强 小强 小强
*/
out是一个线程中的代码
err也是一个线程中的代码
多线程随机性很强
2. System的方法
方法 | 描述 |
---|---|
exit(int status) | 退出当前虚拟机 |
currentTimeMillis() | 获得当前系统的毫秒值(与1970 年 1 月 1 日午夜之间的时间差)测试程序的消耗时间 - long |
getProperties() | 获得当前的所有系统属性 - Properties |
getProperty(String key) | 获得指定键的系统属性 - String |
setIn(InputStream in) | 输入重定向 |
setOut(PrintStream out) | 输出重定向 |
setErr(PrintStream err) | 错误重定向 |
//获得当前系统的毫秒值(与1970 年 1 月 1 日00:00:00之间的时间差)
long currentTimeMillis = System.currentTimeMillis();
System.out.println(currentTimeMillis);//1625766335382
//获取到系统所有的参数
Properties properties = System.getProperties();
System.out.println(properties);
//通过key获取value
String value = System.getProperty("os.name");
System.out.println(value);//Windows 10
//关闭虚拟机
System.exit(0);
六、Runtime类
Runtime代表Java程序的运行时环境,可以通过 getRuntime 方法获取当前运行时。
应用程序不能自己创建Runtime对象,可以通过Runtime的静态方法getRuntime()获得Runtime对象。Runtime类可以访问jvm的相关信息,如处理器数量,内存信息等
//获取运算环境的对象
Runtime run = Runtime.getRuntime();
System.out.println("获取最大内存数:(字节)" + run.maxMemory());//3782737920
System.out.println("获取闲置内存数:(字节)" + run.freeMemory());//250001408
System.out.println("获取处理数:" + run.availableProcessors());//8
一段好的代码必须是运行时间快并且消耗内存少
七、大数值运算类
Java中提供了大数字的操作类在java.math包下的BigInteger和BigDecimal。这两个类用于高精度计算,大数以字符串的形式传入
BigInteger
针对大整数的处理类
BigInteger 类型的数字范围较 Integer 类型的数字范围要大得多。 Integer 是 int 的包装类, int 的最大值是 2³¹-1 ,如果要计算更大的数字,使用 Integer 数据类型就无法实现了,所以 Java 中提供了 BigInteger 类来处理更大的数字。 BigInteger 支持任意精度的整数,也就是说在运算中 BigInteger 类型可以准确地表示任何大小的整数值而不会丢失任何信息。
将 2147483648 转换为 BigInteger 类型 :
BigInteger intMax = new BigInteger("2147483648");
//参数是以字符串的形式存在
方法 | 描述 |
---|---|
BigInteger(String value) | 构造方法,将value字符串变成BigInteger类型数据 |
add(BigInteger value) | 加法,求两个BigInteger类型数据的和。 |
subtract(BigInteger value) | 减法,求两个BigInteger类型数据的差 |
multiply(BigInteger value) | 乘法,求两个BigInteger类型数据的积 |
divide(BigInteger divisor) | 除法,求两个BigInteger类型数据的商 |
modInverse(BigInteger m) | 取模,求BigInteger类型数据对m求模 |
remainder(BigInteger divisor) | 求余数,求BigInteger类型数据除以divisor的余数 |
abs() | 绝对值,求BigInteger类型数据的绝对值 |
negate() | 相反数,求BigInteger类型数据的相反数 |
max(BigInteger value) | 最大数,求两个BigInteger类型数据的最大值 |
min(BigInteger value) | 最小数,求两个BigInteger类型数据的最小值 |
BigInteger fifteen = new BigInteger("15");
BigInteger ten = new BigInteger("10");
BigInteger negateTen = new BigInteger("-10");
System.out.println("15+10= " + fifteen.add(ten));//25
System.out.println("15-10= " + fifteen.subtract(ten));//5
System.out.println("15*10= " + fifteen.multiply(ten));//150
System.out.println("15/10= " + fifteen.divide(ten));//1
//此方法的模数不能为负
System.out.println("15对10求模= " + fifteen.mod(ten));//5
//求余数时,结果的正负和被除数相同
System.out.println("15/10余数= " + fifteen.remainder(ten));//5
System.out.println("-10的绝对值= " + negateTen.abs());//10
System.out.println("15的相反数= " + fifteen.negate());//-15
System.out.println("15和10最大数= " + fifteen.max(ten));//15
System.out.println("15和-10最小数= " + fifteen.min(negateTen));//-10
利用BigInteger构造方法转换进制
String string1 = new BigInteger("15", 10).toString(2);
System.out.println("十进制的20转换成二进制是:" + string1);//1111
String string2 = new BigInteger("15", 10).toString(8);
System.out.println("十进制的20转换成八进制是:" + string2);//17
String string3 = new BigInteger("15", 10).toString(16);
System.out.println("十进制的20转换成十六进制是:" + string3);//f
String string4 = new BigInteger("110", 2).toString(10);
System.out.println("二进制的110转换成十进制是:" + string4);//6
String string5 = new BigInteger("110", 8).toString(10);
System.out.println("八进制的110转换成十进制是:" + string5);//72
String string6 = new BigInteger("110", 16).toString(10);
System.out.println("十六进制的110转换成十进制是:" + string6);//272
BigDecimal
针对大小数的处理类
BigDecimal 和 BigInteger 都能用来实现大数字的运算,不同的是 BigDecimal 加入了小数的概念。
BigDecimal 类型的数字可以用来做超大的浮点数的运算。 BigDecimal 类支持任何精度的定点数,可以用它来精确计算货币值。
BigDecimal 类中常用的两个构造方法
//实例化时将双精度型转换为 BigDecimal 类型
public BigDecimal(double val)
//实例化时将字符串形式转换为 BigDecimal 类型
public BigDecimal(String val)
方法 | 描述 |
---|---|
add(BigDecimal value) | 加法 |
subtract(BigDecimal value) | 减法 |
multiply(BigDecimal value) | 乘法 |
divide(BigDecimal value, int sacle ,int roundingMode) | 除法,方法中 3 个参数分别代表除数、小数点后的位数、近似处理模式 |
BigDecimal bigD1 = new BigDecimal("0.1");
BigDecimal bigD03 = new BigDecimal("0.03");
//加法运算
System.out.println("0.1+0.03= " + bigD1.add(bigD03));
//减法运算
System.out.println("0.1-0.03= " + bigD1.subtract(bigD03));
//乘法运算
System.out.println("0.1*0.03= " + bigD1.multiply(bigD03));
//除法运算 ROUND_HALF_UP 四舍五入
BigDecimal divide = bigD1.divide(bigD03, 5, BigDecimal.ROUND_HALF_UP);
System.out.println("0.1/0.03= " + divide);