- 最近学习到第 23 天了,还有 4 天时间我的 JavaSE 课程就要结束了,之后会有一个考试,需要复习一下,正好利用这个时间把之前的学习内容给大家总结分享出来。
- 今天分享的内容主要是关于 正则表达式 的几种功能的使用,还会有一些常用的 API 的使用为大家简单介绍下,下面就开始我们的学习啦。🐳
1.正则表达式
1.1 - 正则表达式的概述及简单使用
- 概述:是指一个用来描述或者匹配一系列符合某个语法规则的字符串的单个字符串。其实就是一个用来表示匹配规则的一个字符串,java 会将这些字符串编译成执行代码去做各种运算。
- 举例:邮箱注册用户名和密码的校验。
- 校验 QQ 案例
- 要求:必须是 5 - 15 位字符,0 不能开头,全部是数字。
- 使用正则表达式判断:
[1-9]\\d{4,14}
。
这里举这个小栗子🐿是为了让大家可以看到,使用了正则表达式的判断是非常的方便的,稍后会为大家介绍这个正则表达式的意义。
1.2 - 字符类
首先我们先来学习以下正则表达式中的字符类,我们想要对一个字符串中的各个字符进行判断,就要知道每个字符在正则表达式中的表示规则,知道了这个之后我们就能继续向下学习了。
Character classes
[abc]
a, b, or c (simple class)
[^abc]
Any character except a, b, or c (negation)
[a-zA-Z]
a through z or A through Z, inclusive (range)
[a-d[m-p]]
a through d, or m through p: [a-dm-p] (union)
[a-z&&[def]]
d, e, or f (intersection)
[a-z&&[^bc]]
a through z, except for b and c: [ad-z] (subtraction)
[a-z&&[^m-p]]
a through z, and not m through p: [a-lq-z] (subtraction)
-
[ ]
: 代表单个字符。 -
[^]
: 除了该字符外的所有单个字符。 -
[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 && [^bc],a-z 除去 bc。 -
[a-z&&[^m-p]]
:a-z 中除了 m-p。
Reminder 💁♂️
[ ] 中括号中的内容我们可以理解为,对于一个单个的字符中,可以包含的字符的一个集合。
1.3 - 预定义字符类
预定义字符相当于正则表达式中,为我们提供了一些特殊的字符集合的快捷表达方式。学习了这个字符类之后,就可以用一个简单字符表达一个特殊的字符集合了。
redefined character classes
.
Any character (may or may not match line terminators)
\d
A digit: [0-9]
\D
A non-digit: [^0-9]
\h
A horizontal whitespace character:[ \t\xA0\u1680\u180e\u2000-\u200a\u202f\u205f\u3000]
\H
A non-horizontal whitespace character: [^\h]
\s
A whitespace character: [ \t\n\x0B\f\r]
\S
A non-whitespace character: [^\s]
\v
A vertical whitespace character: [\n\x0B\f\r\x85\u2028\u2029]
\V
A non-vertical whitespace character: [^\v]
\w
A word character: [a-zA-Z_0-9]
\W
A non-word character: [^\w]
-
.
:任意字符。 -
\d
:[0-9] 单个数字字符。
\d 代表转义字符,如果想表示 \d 的话,需要 \d。 -
\D
:[^0-9] 除了数字外的单个字符。 -
\s
:[\t\n\x0B\f\r] 空白字符。 -
\S
:[^\s] 非空白字符。 -
\w
:[a-zA-Z_0-9] 单词字符。
下划线也属于单词字符。 -
\W
:[^\w] 非单词字符。
1.4 - 数量词
上面我们学习了各种字符及字符集在正则表达式中的表达方式,但是如果我们想要表达一个字符出现多次时,我们就需要借助与正则表达式的另外一个规则了,这个规则就是数量词。
quantifiers
X?
X, once or not at all
X*
X, zero or more times
X+
X, one or more times
X{n}
X, exactly n times
X{n,}
X, at least n times
X{n, m}
X, at least n but not more than m times
-
X?
:出现 1 次 或 1 次也没有(不能出现其他)。 -
X*
:出现 0 次 或 更多次。 -
X+
:出现 1 次 或 多次,不包括 0 次。 -
X{n}
:出现恰好 n 次。 -
X{n,}
:出现至少 n 次。 -
X{n,m}
:出现 [n, m] 次,包含 n 也包含 m。
1.5 - 分割功能
下面介绍一个 String 类中的方法,它的参数是
regex
也就是我们今天学习的正则表达式,那么我们来简单使用一下吧。
- public String[] split(String regex)
- 概述:字符串分割方法,将给定字符串中,两端都符合正则表达式的字符串拆分出来。特别的,这个匹配的字符串不会出现在返回的字符数组中。
- 案例:我们有一个已知的字符串,其中包含了多个名字,并且每个名字中间都用
,
分隔,我们想要获取每个名字,此时可以借助正则表达式来完成。
String str = "Sawyer,Jerry,Tom";
String[] arr_str = str.split("\\,”);
System.out.println(Arrays.toString(arr_str));
Reminder 💁♂️
这里的正则表达式需要写成\\\,
,表示是正则表达式的\\,
如果写成\\,
则代表的是字符中的转义字符。
1.6 - 替换功能
- public String replaceAll(String regex, String replacement)
- 正则表达式替换功能。
String str1 = “I123 Love432 Sa324wyer!”; // 去掉数字
// 任意数字,使用 + 可以匹配多位数字,减少 replace 次数,提高性能。
String reget = “\\d+”;
String str2 = str1.replaceAll(reget, “”);
System.out.println(str2);
- 这里我们借助 String 中的另一个方法
replaceAll()
方法将字符串中的所有数字替换为空字符串。特别的,这里的正则表达式中使用了+
来匹配出现 1 次或多次的数字,也就是将一组连续的数字一次替换掉,而不需要每次只替换掉一个数字,提高性能。
1.7 - 分组功能
- 概述:捕获组可以通过从左到右计算其开括号来进行编组。类似数学中的 () 将多次出现的字符串归为一组。
读读 API 📖
Capturing groups are numbered by counting their opening parentheses from left to right. In the expression ((A)(B(C))), for example, there are four such groups:
1 ((A)(B(C)))
2 (A)
3 (B(C))
4 (C)
- 需求:判断一个字符串是否是叠词或复词。
/*
(.)代表任意一组字符
\\1 代表一组再次出现一次
\\2 代表第二组又出现了一次
*/
String regex1 = "(.)\\1(.)\\2";
System.out.println("快快乐乐".matches(regex1)); // true
System.out.println("快乐乐乐".matches(regex1)); // false
System.out.println("高高兴兴".matches(regex1)); // true
System.out.println("死啦死啦".matches(regex1)); // false
String regex2 = "(..)\\1";
System.out.println("死啦死啦".matches(regex2)); // true
System.out.println("高兴高兴".matches(regex2)); // true
System.out.println("快快乐乐".matches(regex2)); // false
- 需求:请按照叠词切割:"sdqqfgkkkhjppppk1";
String str_sou = "sdqqfgkkkhjppppk1";
// 将出现 1 次或多次的字符组切掉,+ 代表1组出现一次或多次。
String regex = "(.)\\1+";
String[] arr_str = str_sou.split(regex);
System.out.println(Arrays.toString(arr_str));
- 需求:”我我....我...我.要...要要要...要学....学学..学.编..编编.编.程.程.程..程”,将字符串还原成:"我要学编程"。
String str_sou = "我我....我...我.要...要要要...要学....学学..学.编..编编.编.程.程.程..程";
// 1.去掉.
String regex_replace1 = "\\.+";
String str_replace1 = str_sou.replaceAll(regex_replace1, "");
System.out.println(str_replace1);
// 2.替换组
String regex_replace2 = "(.)\\1+";
// $1 代表第一组中内容,()内的内容。
String str_replace2 = str_replace1.replaceAll(regex_replace2, "$1");
System.out.println(str_replace2);
2.Pattern 和 Matcher
2.1 - Pattern 概述
- 一个正则表达式字符串,必须首先成一个 Pattern 实例对象,用于对正则表达式字符串进行编译。生成的对象可以用于创建 Matcher 对象,可以匹配任意字符序列。
所有执行状态的匹配都保存在匹配器中,这些匹配器可以被共享。
读读 API 📖
A regular expression, specified as a string, must first be compiled into an instance of this class. The resulting pattern can then be used to create a Matcher object that can match arbitrary character sequences against the regular expression. All of the state involved in performing a match resides in the matcher, so many matchers can share the same pattern.
- 一个典型的调用顺序如下👇
// 编译正则表达式
Pattern p = Pattern.compile("a*b");
// 获取匹配器
Matcher m = p.matcher("aaaaab");
// 执行匹配
boolean b = m.matches();
- 不建议将它用在单次调用中,该语句虽然等效与上面三个语句,但是重复匹配的效率低,因为每次都要通过 Pattern 编译正则表达式语句。
boolean b = Pattern.matches("a*b", "aaaaab");
读读 API 📖
A matches method is defined by this class as a convenience for when a regular expression is used just once. This method compiles an expression and matches an input sequence against it in a single invocation. The statement
is equivalent to the three statements above, though for repeated matches it is less efficient since it does not allow the compiled pattern to be reused.
- Pattern 的实例是不可变的,在多线程是安全的。但这样使用 Matcher 类的实例是不安全的。
Instances of this class are immutable and are safe for use by multiple concurrent threads. Instances of the Matcher class are not safe for such use.
- API 总结
- Pattern 用于编译正则表达式。
- Matcher 用于创建匹器,匹配器可以匹配任意字符序列,并且可以执行多个匹配任务。
- 典型的执行顺序:编译正则表达式 -> 创建匹配器 -> 执行匹配
- 如果需要用同一个正则表达式来匹配多个字符序列时,建议重复使用同一个 Pattern 编译器对象。
- Pattern 的实例是不可变并且线程安全的,但是 Matcher 实例是线程不安全的。
2.2 - Pattern 应用
- 需求:将一个字符串中的手机号码获取出来。
- 数据:"我的手机号是18676403416,曾经用过13364286497,还用过18988888888";
String str_sou = "我的手机号是18676403416,曾经用过13364286497,还用过18988888888";
// 手机号的正则表达式
String REGEX_NUM = "1[3578]\\d{9}";
Pattern p = Pattern.compile(REGEX_NUM);
Matcher m = p.matcher(str_sou);
boolean b = m.find(); // 尝试查找与该匹配模式所匹配的下一个子序列
System.out.println(b);
// No match found 需要先执行 find() 后再获取
String str_group = m.group(); // 获取曾经查找到的子序列
System.out.println(str_group);
/*
* 正则匹配器的典型应用
* 遍历 find() 方法 获取所有 group() 子串
* */
while (m.find())
System.out.println(m.group());
3.Math
- 概述
Math 是一个 final 修饰的类,所有成员都是静态的,并且私有构造方法不能被实例化。
public final class Math
- 成员变量
public static final double PI
The double value that is closer than any other to pi, the ratio of the circumference of a circle to its diameter.
- 成员方法
public static int abs(int a)
取绝对值。public static double ceil(double a)
ceil(天花板),向上(数值大)取整,结果是 double 类型。
13.0 -12
12.3 -12.99
12.0 -13
-
public static double floor(double a)
ceil(地板),向下(数值小)取整,结果是 double 类型。
13.0 -12
12.3 -12.99
12.0 -13
public static int max(int a, int b)
获取两个值中的最大值。public static double pow(double a, double b)
乘方运算:a 是底数,b 是指数。public static double random()
生成 [0.0, 1.0) 随机数。public static int round(float a)
四舍五入:参数是 float 类型时返回 int 类型,参数是 double 类型时返回 long 类型。public static double sqrt(double a)
开平方根:返回 double 类型。
4.Random
- 构造方法一
使用 System.nanoTime() 纳秒值作为种子。
Random random1 = new Random();
for (int i = 0; i < 10; i++) {
System.out.println(random1.nextInt());
}
- 构造方法二
相同的种子时,同一次调用 nextInt 的结果是一样的,换句话说,每运行得到的 a b 结果是固定的。
Random random2 = new Random(1000);
int a = random2.nextInt();
int b = random2.nextInt();
System.out.println(a);
System.out.println(b);
public int nextInt(int n)
取值范围 [0, bound) 等价于 [0, bound - 1]
👇 取值范围[0, 100) => [0, 99]
System.out.println(random1.nextInt(100));
5.System
5.1 - 概述
System 类包含几个有用的类字段和方法。它不能被实例化。
读读 API 📖
The System class contains several useful class fields and methods. It cannot be instantiated.
5.2 - 标准输入输出流。
1. In:标准输入流,默认指向键盘。
2. Out:标准输出流,默认指向控制台。
5.3 - 静态方法:
-
public static void gc()
执行垃圾回收器。
class FinalizeTest {
// 当 FinalizeTest 类的对象变成垃圾对象后,回收器在不确定时间回收这个对象。
// 在回收之前,会调用这个方法。
@Override
protected void finalize() throws Throwable {
System.out.println("Garbage is cleared!");
}
}
public static void exit(int status)
立刻退出 JVM 运行,按照惯例,非 0 状态表示异常终止。public static long currentTimeMillis()
1970 UTC 至今毫秒 milliseconds,可以用于计算方法执行时间。public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
src - the source array.
srcPos - starting position in the source array.
dest - the destination array.
destPos - starting position in the destination data.
length - the number of array elements to be copied.
- src - 源数组。
- srcPos - 源数组起始位置。
- dest - 目标数组。
- destPos - 目标数组的起始数据。
- length - 要复制的数组元素的数目。
6.BigInteger
- 概述:可以让超过
Integer
范围的数进行运算,可以存放任意精度的整数。
例如我们想将这样一个数赋值给变量。
long l = 12345678987654321123456789
这个数的大小已经超过了 long 的 取值范围,所以编译报错。
我们可以通过 String 字符串来创建 BigInteger 对象来保存这个数值,并进行数学运算。
BigInteger bi1 = new BigInteger("12345678987654321123456789");
igInteger bi1 = new BigInteger("100");
BigInteger bi2 = new BigInteger("2");
System.out.println(bi1.add(bi2)); // +
System.out.println(bi1.subtract(bi2)); // -
System.out.println(bi1.multiply(bi2)); // *
System.out.println(bi1.divide(bi2)); // /
// 取商 取模
BigInteger[] arr_bi = bi1.divideAndRemainder(bi2);
System.out.println(Arrays.toString(arr_bi));
7.BigDecimal
概述:可以更精确的存储小数,也可以存任意小数。
因为计算机中的数据都是以二进制形式存储的,在表示小数的时候不能精确的表示出来,只能无限接近(例如用十进制表示 1/3)。
System.out.println(2.0 - 1.1); // 0.8999999999999999
方式一:不推荐方式💩因为不够精确。
BigDecimal bd1 = new BigDecimal(2.0);
BigDecimal bd2 = new BigDecimal(1.1);
System.out.println(bd1.subtract(bd2)); // 0.899999999999999911182158029987476766109466552734375
- 方式二:推荐方式🐹通过构造方法中传入字符串的方式。
BigDecimal bd3 = new BigDecimal("2.0");
BigDecimal bd4 = new BigDecimal("1.1");
System.out.println(bd3.subtract(bd4)); // 0.9
- 方式三:推荐方式🐹静态方法创建对象。
BigDecimal bd5 = BigDecimal.valueOf(2.0);
BigDecimal bd6 = BigDecimal.valueOf(1.1);
System.out.println(bd5.subtract(bd6)); // 0.9
8.Date (java.util.Date)
8.1 - 概述
分配 Date 对象并初始化它自从标准基准时间,称为"新纪元",即 1970 年 1 月 1 日,格林尼治标准时间 00:00:00 代表指定的毫秒数。
读读 API 📖
Allocates a Date object and initializes it to represent the specified number of milliseconds since the standard base time known as "the epoch", namely January 1, 1970, 00:00:00 GMT.
8.2 - 构造方法
public Date()
默认输出格式:EEE MMM dd HH:mm:ss zzz yyyy
打印输出:Fri Dec 23 16:48:30 CST 2016。public Date(long date)
代表 1970 年 1 月 1 日,加上我们的东八区时区转变为 08:00:00。
打印输出:Thu Jan 01 08:00:00 CST 1970
8.3 - 成员方法
-
public long getTime()
将时间转换为毫秒值。
两个取值方式是相同的。
new Date().getTime() // 通过事件对象获取毫秒值。
System.currentTimeMillis() // 通过系统方法获取毫秒值。
-
public void setTime(long time)
设置毫秒值,改变时间对象,1000毫秒 = 1秒。
9.SimpleDataFormat
概述:DateFormat 是 abstract 不允许实例化。可以使用子类 SimpleDateFormat。
Date -> String
// 方式一:默认格式
Date date = new Date();
SimpleDateFormat sdf1 = new SimpleDateFormat();
System.out.println(sdf1.format(date));
// 方式二:自定义格式
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(sdf.format(date));
- String -> Date
String str = "2016年12月22日 08:00:00";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
Date d = sdf.parse(str); // 解析出 Date
System.out.println(sdf.format(d));
-
Date and Time Patterns
10.Test👨💻你来到这个世界多少天?
- 需求:计算你来到这个世界多少天?
- 分析
- 将生日字符串和今天字符串对象存储在 String 类型的变量中
- 定义日期格式化对象
- 将日期字符串转换成日期对象
- 通过日期对象计算出时间差值
- 将时间毫秒值转换为天数
public class Test {
public static void test() throws ParseException {
// 1.将日期存储在 String 变量中
String str_birthday = "1991 年 10 月 21 日";
String str_today = "2016 年 11 月 22 日";
// 2.定义日期格式化对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy 年 MM 月 dd 日");
// 3.将日期字符串转换为日期对象
Date date_birthday = sdf.parse(str_birthday);
Date date_today = sdf.parse(str_today);
// 4.通过日期对象计算毫秒值
long time = date_today.getTime() - date_birthday.getTime();
// 5.转换为天数
System.out.println(time / 1000 / 60 / 60 / 24);
}
}
11.Calendar
概述:是一个抽象类,子类有 GregorianCalendar。
public static Calendar getInstance()
父类引用指向子类对象:可以使用子类中的重写方法。public int get(int field)
Field Detail。
Reminder 💁♂️
月份:[0, 11]
星期:从周日开始。
abstract public void add(int field, int amount)
对日历中元素进行加减操作。public final void set(int year, int month, int date)
设置年月日。
Reminder 💁♂️
12 -> 0 年 进位 -> 2017
悄悄话 🌈
- 已经有一段时间没有和小伙伴们分享我的学习笔记了,接下来的几天我会把我之前的笔记都整理并陆续的分享出来。
- 和小伙伴们汇报下我最近的学习情况吧,今天完成了又一个阶段的学习,刚刚结束了 IO 流的考试,考试成绩很不错😋(开心),今天是休息日,因为马上 JavaSE 的课程就要结束了,感觉班级的学习氛围有些不如以前,本该是抓紧复习的时候,但是明显感觉一部分的人已经开始浮躁起来了。我个人还好,已经做好了复习的计划正在有条不紊的进行着。
- 因为马上就要放假了,大概有20天的时间,今天过年打算留在魔都不回家过年了,所以我要计划一下趁着放假的时间啃一本书才好,列了一下要看的书单,其中有《深入理解JVM虚拟机》 《Java并发编程实战》 《Effective Java》 《软件建模与设计》。本着我自己的想法,我是想按照这3本的顺序依次往下啃的,可开学之后就要进入 JavaEE 的学习了,老师的建议是先自学一下 JS 以及一些前端的技术,之前接触过一些前端的技术,但都是懵懂状态,想着学习了 Java 并且今后是要伴随终生的一门语言,应该要深挖一下这门语言的一些底层实现,不然的话遇到一些深入的问题根本无从下手去解决,很不喜欢这样的状态。所以如果有在做 JavaEE 开发的小伙伴也可以给我提一些建议,我就感激不尽了。
- 好了,写了这么多,只是想与大家交流一下,而不只是把技术性的东西贴在这里作为展示,能一起交流探讨一下才是最重要的。我要继续整理接下来的笔记了,想要交流的小伙伴们可以评论或发私信给我。
彩蛋 🐣
-
最近开通了简书专题 JavaSE 成长之路,主要为一样正在 JavaSE 修行中的简友们提供了技术交流的平台,希望大家多多投稿交流互动。
如果你觉得我的分享对你有帮助的话,请在下面👇随手点个喜欢 💖,你的肯定才是我最大的动力,感谢。