HashMap
HashMap定义
HashMap
是一个散列表,它存储的内容是键值对(key-value)映射。HashMap
实现了Map接
口,根据键的**HashCode**
值存储数据,具有很快的访问速度HashMap
最多允许一条记录的键为**null**
HashMap
不支持线程同步。HashMap
是无序的,即不会记录插入的顺序。HashMap
的key与value类型可以相同也可以不同,
HashMap的超类与实现的接口
HashMap
继承于AbstractMap
,实现了Map
、Cloneable
、java.io.Serializable
接口。
应用实例
// 引入 HashMap 类
import java.util.HashMap;
public class MyClass {
public static void main(String[] args) {
// 创建HashMap对象 Sites
HashMap<Integer, String> Sites = new HashMap<Integer, String>();
// 添加键值对
Sites.put(1, "Google");
Sites.put(2, "Runoob");
Sites.put(3, "Taobao");
Sites.put(4, "Zhihu");
//out: {1=Google, 2=Runoob, 3=Taobao, 4=Zhihu}
System.out.println(Sites);
//访问值
System.out.println(Sites.get(3)); //out: Taobao
//删除键值对
Sites.remove(4); //删除4-Zhihu键值对
//获取HashMap键值对数量
System.out.println(Sites.size()); //out: 3
//遍历HashMap所有键值对:使用for each循环
for (Integer i : Sites.keySet()) {
System.out.println("key: " + i + " value: " + Sites.get(i));
}
//遍历HashMap所有值
for(String value: Sites.values()) {
System.out.print(value + ", ");
}
}
}
###HashMap类API(java.util包)
**
**HashMap<K, V> map = new HashMap<>();**
返回一个类型为HashMap<K, V>
的实例,其中K
和V
分别是键和值的类型,只能是引用数据类型
**HashMap**
中键和值的类型是由对象变量的类型决定的,构造函数并不需要指定- 当基本数据类型作为键或值时,需要使用基本数据类型的包装类
HashMap<String, int> map = new HashMap<>(); //编译不通过
HashMap<String, Integer> map = new HashMap<>(); //编译通过
动态方法
K
指代HashMap
中键的类别,V
指代HashMap
中值的类别**V map.put(K key, V value)**
将指定的键值对插入到map
中
- 如果插入的键值对已经存在,替换掉旧的
**value**
并将其返回,如果不存在则直接插入键值对,返回null
- 更新已经存在的值,直接
put()
新值即可,如递增值某个键的值map.put(key, map.get(key) + 1);
**void map.putAll(Map m)**
将m
的所有键值对插入到map
中
HashMap<Integer, String> sites = new HashMap<>();
sites.put(1, "Google");
sites.put(2, "Runoob");
sites.put(3, "Taobao");
HashMap<Integer, String> sites2 = new HashMap<>();
sites2.put(1, "Weibo");
sites2.put(4, "Wiki");
sites2.putAll(sites);
//out: {1=Google, 2=Runoob, 3=Taobao, 4=Wiki}
System.out.println(sites2);
**V map.putIfAbsent(K key, V value)**
先判断指定的键值对是否存在,不存在则将键值对插入到map
中
**V map.remove(K key)**
删除map
中指定键key
对应的键值对
- 返回所删除的值,如果没有删除键值对,返回
null
**boolean map.containsKey(K Key)**
如果hashMap
中是否存在指定的key
对应的映射关系返回true
,否则返回false
。
**V map.get(K key)**
获取指定key
对应对value
- 存在对应
key
的键值对时,返回value
;否则返回null
- 在获取
value
前,可以先使用map.containsKey()
方法来检查map
中是否存在指定键
**Set<K> map.keySet()**
返回由所有key
组成的Set集合
- 该方法与for each循环配合使用,用来遍历
map
中的所有键。
**Collection<V> map.values()**
返回由所有value
组成的Collection集合
- 该方法与for each循环配合使用,用来遍历
map
中的所有值。
**void map.clear()**
删除map
中所有键值对
ArrayList、LinkedList和Vector概述
List
接口一共有三个实现类,分别是ArrayList
、Vector
和LinkedList
。
List
用于存放多个元素,能够维护元素的次序,并且允许元素的重复。
- 3个具体实现类的相关区别如下:
**ArrayList**
ArrayList
是最常用的List
实现类,内部是通过数组实现的,它允许对元素进行快速随机访问。- 可以将
ArrayList
理解为数据结构中的顺序表 - 数组的缺点是每个元素之间不能有间隔,当数组大小不满足时,需要增加数组长度,此时就要将数组中已有的数据复制到新的存储空间中。
- 当从
ArrayList
的中间位置插入或者删除元素时,需要对数组进行复制、移动,代价比较高。 **ArrayList**
适合随机访问和遍历,不适合数据的插入和删除。
**Vector**
Vector
与ArrayList
一样,也是通过数组实现的,不同的是它支持线程的同步,即某一时刻只有一个线程能够写Vector
,避免多线程同时写而引起的不一致性。- 由于实现同步需要很高的花费,因此,访问
Vector
比访问ArrayList
慢。 Vector
可以当作线程安全的ArrayList
**LinkedList**
LinkedList
是用双向链表结构存储数据的
- `LinkedList`**适合数据的插入和删除,不适合随机访问和遍历**。
- 可以将`LinkedList`理解为数据结构中的链表
- `LinkedList`还提供了`List`接口中没有定义的方法,**专门用于操作表头和表尾元素**。
因此,LinkedList
可以当作堆栈、队列和双向队列使用。
**Stack**
和**Queue**
实际上如果需要使用堆栈和队列,不直接使用**LinkedList**
类,更推荐使用**Stack**
类和**Queue**
接口Stack
继承自Vector
Queue
与List
、Set
同一级别,需要由LinkedList
初始化,因此Queue
实例只包含了LinkedList
实现的少数几个方法。
Stack<String> stack = new Stack<>();
Queue<String> queue = new LinkedList<>(); //使用了LinkedList类的构造函数
ArrayList
ArrayList
类是一个可以动态修改的数组,与普通数组的区别就是**ArrayList**
没有固定大小的限制,我们可以随时添加或删除元素。普通数组与
**ArrayList**
的相互转化普通数组 →
ArrayList
String[] a = {"123", "sds", "sdww"};
List<String> la = Arrays.asList(a);
ArrayList<String> sqList = new ArrayList<>(la);
ArrayList
→ 普通数组 ```java // 创建一个动态数组 ArrayListsites = new ArrayList<>(); sites.add(“Runoob”); sites.add(“Google”);
//创建一个新的String类型的数组,数组长度和ArrayList长度一样 String[] arr = new String[sites.size()]; //将ArrayList对象转换成数组 sites.toArray(arr);
<a name="EUjeP"></a>
### 应用实例
```java
import java.util.ArrayList;
public class MyClass {
public static void main(String[] args) {
//创建ArrayList<String>对象sqList
ArrayList<String> sqList = new ArrayList<>();
//添加元素
sqList.add("Google");
sqList.add("Runoob");
sqList.add("Taobao");
sqList.add("Weibo");
//out: [Google, Runoob, Taobao, Weibo]
System.out.println(sqList);
//访问元素
System.out.println(sqList.get(1)); //out: Runoob
//修改元素
sqList.set(2, "Wiki");
//删除元素
sqList.remove(0);
//out: [Runoob, Wiki, Weibo]
System.out.println(sqList);
//遍历动态数组
for (int i = 0; i < sqList.size(); i++) {
System.out.println(sqList.get(i));
}
for (String i : sqList) {
System.out.println(i);
}
}
}
###ArrayList类API(java.util包)
ArrayList
是一个动态数组,该类提供了相关的添加、删除、修改、遍历等功能。
构造函数实例
**ArrayList<E> sqList = new ArrayList<>([Collection c]);**
返回一个类型为ArrayList<E>
的实例,其中E
是动态数组元素的类型,只能是引用数据类型
Collection c
为可选参数,可以使用实现了Collection
的集合初始化sqList
```java String[] a = {“123”, “sds”, “sdww”}; Listla = Arrays.asList(a); //必须将普通数组转为List类型
HashSet
//使用数组初始化的ArrayList
ArrayList
//使用HashSet初始化的ArrayList
ArrayList
**动态方法**
- `E`指代动态数组的元素类型
- `**boolean sqList.add([int index,] E element)**`
将元素`element`插入到动态数组的指定位置中。
- `index`为可选参数,表示元素插入处的索引值
如果没有给出`index`参数,元素将默认追加至动态数组的最末尾
- 如果成功插入元素,返回`true`。
如果`index`超出范围,则该方法抛出`IndexOutOfBoundsException`异常。
- 每次添加新元素,如果`ArrayList`的容量不足,则会根据其特定的策略进行自动扩容
自动扩容也不是无休止的,有最大容量
- `**boolean sqList.addAll([int index,] Collection c)**`
可以将实现了`Collection`接口的对象中的所有元素添加到`sqList`中,如`set`、`map`等等
- `**boolean sqList.remove(E element)**`
- `**E sqList.remove(int index)**`
用于删除动态数组里的单个元素。
- 如果传入元素,删除成功,则返回`true`,否则返回`false`。
- 如果传入索引值,则返回删除的元素。
- `**boolean sqList.removeAll(Collection c)**`
删除sqList中存在于指定集合中的元素。
- 如果从动态数组成功删除元素返回`true`。
如果sqList中存在的元素与指定集合的元素类型不兼容,则抛出`ClassCastException`异常。<br />如果sqList中包含`null`元素,并且指定集合不允许`null`元素,则抛出`NullPointerException`异常。
- `**E sqList.get(int index)**`
返回动态数组中指定索引处的元素。
- 如果`index`超出范围,则该方法抛出`IndexOutOfBoundsException`异常。
- `**E sqList.set(int index, E element)**`
替换动态数组中指定索引的元素为指定元素。
- 返回被替换的元素
- `**void sqList.sort(Comparator c)**`
根据指定的顺序对动态数组中的元素进行原地排序。
- `Comparator c`参数为排序方式,其提供升序和降序方式
```java
Comparator.naturalOrder(); //升序(自然顺序)排序
Comparator.reverseOrder(); //降序排序
**boolean sqList.contains(E element)**
判断元素element
是否在动态数组中,在的话返回true
,否则返回false
contains()
方法内部其实使用equals()
方法来遍历所有元素。
如果指定的元素与数组中的元素有匹配到,则该方法返回true
。
**int sqList.indexOf(E element)**
从动态数组中返回指定元素最先出现的索引值。
- 内部是通过遍历数组中的所有元素实现的
- 如果动态数组中不存在指定的元素,则该
indexOf()
方法返回-1
。
**int sqList.size()**
返回动态数组中元素的数量。
- 再次提醒,普通数组使用属性
.length
获取长度,字符串使用方法.length()
获取长度
**Object[] sqList.toArray([T[] arr])**
将ArrayList
对象转换为普通数组
T[] arr
为可选参数,其用于存储转换后的数组,T[]
表示数组的类型- 如果没有指定
T[] arr
参数,则返回Object[]
类型的数组 - toArray(T[] arr)方法实际上是Collection接口中的一个抽象方法,一般来说,都需要给该方法传入一个参数,否则得到Object[]进行类型转换很不方便。
```java
// 创建一个动态数组
ArrayList
sites = new ArrayList<>(); sites.add(“Runoob”); sites.add(“Google”);
//创建一个新的String类型的数组,数组长度和ArrayList长度一样 String[] arr = new String[sites.size()]; //将ArrayList对象转换成数组 sites.toArray(arr);
- `**void sqList.clear()**`
删除动态数组中的所有元素。
<a name="dkqJZ"></a>
## LinkedList
- 链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的地址。
- 与`ArrayList`相比,`LinkedList`的增加和删除的操作效率更高,而查找和修改的操作效率较低。
<a name="B9t0d"></a>
### 应用实例
```java
import java.util.LinkedList;
public class MyClass {
public static void main(String[] args) {
//创建LinkedList对象linkList
LinkedList<String> linkList = new LinkedList<String>();
//添加元素
linkList.add("Google");
linkList.add("Runoob");
linkList.add("Taobao");
linkList.addFirst("Wiki"); //在头部添加元素
linkList.addLast("BaiDu"); //在尾部添加元素
//out: [Wiki, Google, Runoob, Taobao, BaiDu]
System.out.println(linkList);
//访问元素
System.out.println(linkList.getFirst()); //获取链表头部元素
System.out.println(linkList.getLast()); //获取链表尾部元素
//删除元素
linkList.removeFirst(); //移除头部元素
linkList.removeLast(); //移除尾部元素
//遍历链表
for (int size = linkList.size(), i = 0; i < size; i++) {
System.out.println(linkList.get(i));
}
for (String i : linkList) {
System.out.println(i);
}
}
}
###LinkedList类API(java.util包)
构造函数实例
**LinkedList<E> linkList = new LinkedList<>([Collection c]);**
功能与ArrayList<>([Collection c])
相同
动态方法
E
指代动态数组的元素类型boolean LinkedList.add([int index,] E element)
boolean LinkedList.addAll([int index,] Collection c)
boolean LinkedList.remove(E element)
E LinkedList.remove(int index)
E LinkedList.get(int index)
E LinkedList.set(int index, E element)
void LinkedList.sort(Comparator c)
boolean LinkedList.contains(E element)
int LinkedList.indexOf(E element)
int LinkedList.size()
Object[] LinkedList.toArray([T[] arr])
void LinkedList.clear()
**ArrayList**
实现的方法,**LinkedList**
都实现了,且功能完全一致,但是由于两个类的元素存储方式不同,两个类方法的实际使用效率是不同的,各有侧重。
- 从上述方法可以看出,
**LinkedList**
虽然是链表,但是也提供了根据索引操作链表的方法。
然而,由于LinkedList的数据存储是基于双向链表的实现的,所以每次使用索引找到相应位置的时间复杂度是**O(linkList.size())**
,而ArrayList的时间复杂度为O(1)
下述是**LinkedList**
独有而**ArrayList**
没有的方法
void LinkedList.addFirst(E e)
void LinkedList.addLast(E e)
将元素e添加到链表头部/末尾
E LinkedList.getFirst()
E LinkedList.getLast()
返回链表的头部元素/尾部元素
E LinkedList.removeFirst()
E LinkedList.removeLast()
删除并返回链表的头部元素/尾部元素
下述是实现**Queue**
接口的方法
boolean LinkedList.offer(E e)
向链表末尾添加元素,返回是否成功,成功为true
,失败为false
。
E LinkedList.peek()
返回链表的头部元素
E LinkedList.poll()
删除并返回(弹出)链表的头部元素
ArrayList
和LinkedList
的应用场景
- 以下情况使用
**ArrayList**
:
频繁访问列表中的某一个元素。
只需要在列表末尾进行添加和删除元素操作。
- 以下情况使用
**LinkedList**
:
你需要通过循环迭代来访问列表中的某些元素。
需要频繁的在列表开头、中间、末尾等位置进行添加和删除元素操作。
时间日期API
- 旧版Java常用的时间类有
Date
、Calendar
、SimpleDateFormat
等,但存在诸多问题- 非线程安全
java.util.Date
和java.util.SimpleDateFormatter
都不是线程安全的,是可变的,这是Java日期类最大的问题之一。
- 设计很差
Java的日期/时间类的定义并不一致,在java.util
和java.sql
的包中都有Date
类,此外用于格式化和解析的类在java.text
包中定义。java.util.Date
同时包含日期和时间,而java.sql.Date
仅包含日期,将其纳入java.sql
包并不合理。另外这两个类都有相同的名字,这本身就是一个非常糟糕的设计。
- 时区处理麻烦
日期类并不提供国际化,没有时区支持,因此Java引入了java.util.Calendar
和java.util.TimeZone
类,但他们同样存在上述所有的问题。
从Java8之后,
**java.time**
包添加了一组新类1. `java.time.LocalDate` -> 只对**年月日**做出处理
1. `java.time.LocalTime` -> 只对**时分秒纳秒**做出处理
1. `java.time.LocalDateTime ` -> 同时可以处理**年月日**和**时分秒**
- 上述类的Local都可以改为Zoned,其中Local代表本地时间,没有时区的问题,Zoned则通过制定的时区处理日期问题。
- 数据库中也支持上述日期类型,在数据存储时候使时间变得简单。
- 三个包的方法都差不多,后续主要介绍
LocalDate
Date和LocalDate的区别 ```java Date date = new Date(); LocalDate ld = LocalDate.now();
System.out.println(date); //输出Tue Mar 02 11:26:57 CST 2021 System.out.println(ld); //输出2021-03-02
- `Date`是一个“万能接口”,它包含日期、时间,如果你只需日期或者时间那么有一些数据就没什么用。
在新的Java8中,日期和时间被明确划分为`LocalDate`和`LocalTime`,`LocalDate`无法包含时间,`LocalTime`无法包含日期,当然,`LocalDateTime`才能同时包含时间和日期。
- `Date`类表示完整的时间点
`LocalDate`类使用日历表示法表示日期。
- `java.util.Date`和`java.util.SimpleDateFormatter`**都不是线程安全的**
`LocalDate`、`LocalTime`和最基本的`String`一样,是**不变类型**,**不但线程安全,而且不能修改**。
- `Date`月份是从0开始,一月是0,十二月是11。
`LocalDate`月份和星期都改成了enum,即一月就是1,就不可能再用错了。
- **构造LocalDate类对象**
不能直接使用构造器来构造LocalDate类的对象,应该用**静态工厂方法(factory method)**,其会代表你调用构造器。`**LocalDate**`**有两个静态工厂方法:**<br />A. `LocalDate.now()`<br />根据当前时间来构造对象。<br />B. `LocalDate.of(1999, 12, 31)`<br />根据指定年、月和日来构造对象。
- 一旦有了`LocalDate`对象,可以用对象的`getYear()`、`getMonthValue()`和`getDayOfMonth()`方法得到年、月和日
- `Date`类也有得到日、月、年的方法,但现在这些方法已经废弃。
- `**LocalDateTime**`**转**`**LocalDate**`**和**`**LocalTime**`
由于`LocalDateTime`类既存有日期,也存有时间,因此它可以通过`toLocalDate()`方法和`toLocalTime()`方法转换为`LocalDate`类和`LocalTime`类
<a name="xSv2u"></a>
### ###LocalData类API(java.time包)###
**静态方法**
- `**LocalDate LocalDate.now()**`
构造一个表示当前日期的对象
- `**LocalDate LocalDate.of(int year, int month, int day)**`
构造一个表示给定日期的对象
**动态方法**
- `**int ld.getYear()**`
- `**int ld.getMonthValue()**`
- `**int ld.getDayOfMonth()**`
得到`LocalDate`对象的年、月和日
- `**DayOfWeek ld.getDayOfWeek()**`
得到当前日期是星期几,作为`DayOfWeek`类的一个实例返回。
- 对`DayOfWeek`对象调用`getValue()`方法类得到1~7之间的一个数,表示这是星期几,1表示星期一,7表示星期日。
- `**LocalDate ld.plusDays(int n)**`
- `**LocalDate ld.minusDays(int n)**`
生成表示当前日期之后或之前n天的`LocalDate`对象。
- `**String ld.toString()**`
包括`LocalDate`在内的几个新的时间类,都重写了toString()方法,可以直接返回时间字符串
<a name="ztUHW"></a>
## 正则表达式API
- **正则表达式定义**
正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个**“规则字符串”**,这个“规则字符串”用来表达对字符串的一种过滤逻辑。
- **正则表达式的作用**
给定一个正则表达式和另一个字符串,我们可以达到以下两个目的
1. 给定的字符串是否符合正则表达式的过滤逻辑(称作"匹配");
1. 可以通过正则表达式,从字符串中获取我们想要的特定部分。
<a name="BKCeG"></a>
### 正则表达式的编写规则
- 正则表达式实际上就是一个字符串,该字符串有具体的编写规则,下面是三个简单的正则表达式实例
| **正则表达式** | **描述** |
| --- | --- |
| this is text | 匹配字符串 "this is text" |
| this\\s+is\\s+text | 注意字符串中的 **\\s+**。<br />匹配单词 "this" 后面的 **\\s+** 可以匹配多个空格,之后匹配"is"字符串,再后 **\\s+** 匹配多个空格然后再跟上 "text" 字符串。<br />可以匹配这个实例:"this is text" |
| ^\\d+(\\.\\d+)? | ^ 定义了以什么开始<br />\\d+ 匹配一个或多个数字<br />? 设置括号内的选项是可选的<br />\\. 匹配 "."<br />可以匹配的实例:"5", "1.5" 和 "2.21"。 |
- **Java中的反斜杠**
Java的反斜杠与其他语言有所不同
- 在其他语言中,`\\`表示
我想要在正则表达式中插入一个普通的(字面上的)反斜杠,请不要给它任何特殊的意义。
- **在Java中,**`**\\**`**表示**
我要插入一个正则表达式的反斜线,所以其后的字符具有特殊的意义。<br />所以,在其他的语言中,一个反斜杠\就足以具有转义的作用,而在**Java中正则表达式中则需要有两个反斜杠才能被解析为其他语言中的转义作用**。也可以简单的理解在**Java的正则表达式中,两个**`**\\**`**代表其他语言(包括正则表达式)中的一个**`**\**`。<br />比如:**Java中表示一位数字的正则表达式是**`**\\d**`**,而表示一个普通的反斜杠是**`**\\\\**`。
**正则表达式特殊符号表**
| **字符** | **描述** |
| --- | --- |
| \\ | 转义字符。作用是**表示常见的那些不能显示的ASCII字符,**如`\\n`、`\\t`等,或者是**把有特殊意义的符号转义为字面字符**,如`\\.`使得`.`仅表示字符`"."`<br />例如,"n"匹配字符"n";"\\n"匹配换行符;"\\\\"匹配"\\";"\\("匹配"("。 |
| ^regex | 匹配必须从字符串开头位置开始。(正则表达式不管是有`^`还是`$`,`**matches()**`**方法匹配的都是整个字符串,**也可以说`matches("regex")`相当于`matches("^regex$")`) |
| regex$ | 匹配必须从字符串结尾位置开始。 |
**正则表达式匹配符号表**
- 每个匹配符号匹配字符串的一个字符
| **字符** | **描述** |
| --- | --- |
| x | 匹配字符`x` |
| . | 匹配**除换行符之外**的任何单个字符。<br />若要匹配包括换行符在内的任意字符,请使用诸如`"[\\s\\S]"`之类的表达式。 |
| [xyz] | 字符集,匹配字符串中字符集包含的**一个字符**。<br />字符集内可以使用`-`指定字符范围,如`a-d`表示`a`到`d`范围内的所有小写字母<br />例如,`"[abc]"`匹配`"plain"`中的`"a"`。 |
| [^xyz] | 反向字符集,匹配字符串中字符集未包含的任何**一个字符**<br />反向字符集内可以使用`-`指定字符范围<br />例如,`"[^abc]"`可以匹配`"plain"`中`"p"`、`"l"`、`"i"`或`"n"`。 |
| [123] | 数字集,匹配字符串中数字集包含的**一个字符**<br />数字集内可以使用`-`指定数字范围 |
| [ \\t\\n\\x0b\\r\\f] | 空格集,匹配字符串中空格集包含的**一个字符** |
| \\d | 匹配一个数字,是``[0-9]的简写 |
| \\D | 匹配一个非数字,是``[^0-9]的简写 |
| \\s | 匹配一个空格,是``[ \\t\\n\\x0b\\r\\f]的简写 |
| \\S | 匹配一个非空格 |
| \\w | 匹配一个单词字符(大小写字母、数字、下划线),是``[a-zA-Z0-9]的简写 |
| \\W | 匹配一个非单词字符(除了大小写字母、数字、下划线之外的字符),等同于``[^\\w] |
| [\\d\\D\\s\\S\\w] | “简写集” |
| [0-34bc\\n\\w] | 各类集合可以随意混合使用 |
| \\b | 匹配一个字符边界,即字符与空格间的位置。<br />例如,"er\\b"匹配"never"中的"er",但不匹配"verb"中的"er"。"\\bdog\\b"匹配"dog is good"中的"dog",但不匹配"ddoggg"中的"dog" |
| \\B | 非字符边界匹配。<br />例如,"er\\B"匹配"verb"中的"er",但不匹配"never"中的"er"。 |
**正则表达式匹配符号限定符表**
- 限定符**定义了匹配符号的匹配次数**,限定符要跟在所限定的匹配符后面
| **字符** | **描述** |
| --- | --- |
| {n} | 正好匹配n次,即匹配次数 = n。<br />例如,`"o{2}"`与`"Bob"`中的`"o"`不匹配,但与`"food"`中的`"oo"`匹配。 |
| {n,} | 至少匹配n次,即匹配次数 ≥ n |
| {n,m} | 匹配至少n次,至多m次,即n ≤ 匹配次数 ≤ m。 |
| * | 匹配次数 ≥ 0 ,是 `{0,}` 的简写 |
| + | 匹配次数 ≥ 1 ,是 `{1,}` 的简写 |
| ? | 匹配 1 次或 0 次,是 ``{0,1} 的简写 |
| *? | 如果 `?` 是限定符 `*` 或 `+` 或 `?` 或 `{}` 后面的第一个字符,那么表示**非贪婪模式**(尽可能少的匹配字符),而不是默认的**贪婪模式**<br />例如,在字符串`"oooo"`中,`"o+?"`只匹配单个`"o"`,而`"o+"`匹配所有`"o"`。 |
<a name="gT4JR"></a>
### 使用正则表达式
**支持正则表达式的String类方法**<br />String类有以下四个动态方法支持正则表达式(`str.replace()`方法不支持)
- `boolean str.matches(String regex)`
当仅且当正则匹配整个字符串`str`时返回`true`
- 实际上调用的是Matcher类的`matches()`方法
- `String[] str.split(String regex)`
将匹配正则表达式的字符串作为分隔符切片字符串
- `String str.replaceFirst(String regex, String str2)`
首次匹配的字符串片段替换为`str2`
- 实际上调用的是Matcher类的`replaceFirst()`方法
- `String str.replaceAll(String regex, String str2)`
所有匹配的字符替换为`str2`<br />实际上调用的是Matcher类的`replaceAll()`方法
**java.util.regex包**
- java.util.regex是一个用于支持正则表达式匹配的包,主要包括以下三个类:
**Pattern类**
- **Pattern对象是一个正则表达式的编译表示**。
- Pattern类没有公共构造方法,构造对象需要调用其公共静态编译方法`Pattern.compile("regex")`
**Matcher类**
- **Matcher对象是对输入字符串进行解释和匹配操作的引擎**。
- 与Pattern类一样,Matcher也没有公共构造方法。需要调用Pattern对象的`Pattern.matcher()`方法来获得一个 Matcher对象。
**PatternSyntaxException**
- PatternSyntaxException是一个非强制异常类,它表示一个正则表达式模式中的语法错误。
- **执行正则表达式相关任务的一般流程**
1. 使用`Pattern.compile("regex")`方法编译正则表达式
1. 使用`Pattern.matcher()`方法构建Matcher对象
1. 调用Matcher对象的各种方法执行正则表达式相关任务
- **实例:**
```java
String str = "abcd";
String regex = "[abc][b].{2}";
Pattern pattern = Pattern.compile(regex); //构建Pattern对象
Matcher matcher = pattern.matcher(str); //构建Matcher对象
//构建好Matcher对象后,就可以使用其方法进行各种匹配任务,
//如字符串与正则表达式是否匹配
System.out.println(matcher.matches()); //out: true
- 关于正则表达式匹配
正则表达式匹配可以有三种方法实现,分别是
boolean str.matches(String regex)
boolean Pattern.matches(String regex, CharSequence)
boolean matcher.matches()
三种方法的功能一样,实际上前两种方法的内部实现是调用第三种方法
- 匹配字符串片段
判断一个字符串中是否存在某个字符串片段匹配正则表达式,可以在正则表达式的前后加上".*"
- 实例 ```java String str = “This dog is good”; String regex = “.dog.“; Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(str);
System.out.println(“字符串中是否包含\”dog\”? “); System.out.println(matcher.matches()); //out: true
<a name="q6UKs"></a>
### ###Matcher类API(java.util.regex包)###
**动态方法**
- `boolean matcher.lookingAt()`
判断整个字符串是否与正则表达式匹配
- `boolean matcher.matches()`
判断字符串从第一个字符开始是否与正则表达式匹配,不要求整个字符串匹配正则表达式
- `int matcher.start()`
返回当前匹配的字符串片段的起始索引
- `int matcher.end()`
返回当前匹配的字符串片段的结尾索引
- `boolean matcher.find()`
尝试查找与正则表达式匹配的下一个字符串片段,如果存在返回`true`
- 实例
显示单词 "cat" 在字符串中出现的次数和位置
```java
String str = "cat cat cat cattie cat";
String regex = "\\bcat\\b";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(str);
int count = 0;
while (matcher.find()) {
System.out.println("Match number " + count++);
System.out.println("start(): " + matcher.start());
System.out.println("end(): " + matcher.end());
System.out.println();
}
上述代码输出
Match number 0
start(): 0
end(): 3
Match number 1
start(): 4
end(): 7
Match number 2
start(): 8
end(): 11
Match number 3
start(): 19
end(): 22
String matcher.replaceAll(String replacement)
首次匹配的字符串片段替换为str2
String matcher.replaceFirst(String replacement)
所有匹配的字符替换为str2
TreeSet
###TreeSet类API(java.util包)
动态方法
E treeSet.ceiling(E e)
返回集合treeSet中大于或等于给定元素e的最小元素,如果不存在这样的元素,返回null
E treeSet.floor(E e)
返回集合treeSet中小于或等于给定元素e的最大元素,如果不存在这样的元素,返回null