😎接上篇让我们一起接着了解Java SE语言
目录
StringBuilder / StringBuffer 类
Comparator 接口和 Comparable 接口都用于比较两个元素的大小:
四、数据类型
基本类型
Java 语言提供了八种基本类型,用户无需定义也可以直接使用。其数据保存在相应的方法栈中。
基本数据类型 | 字节数 | 默认值 | 包装数据类型 | 备注 |
---|---|---|---|---|
字节 | 1 | 0 | 字节 | |
短 | 2 | 0 | 短 | |
整型 | 4 | 0 | 整数 | |
长 | 8 | 0 | 长 | |
浮 | 4 | 0.0f | 浮 | 数字后加f |
双 | 8 | 0.0 | 双 | |
煳 | 2 | 零 | 字符 | 必须用单引号 |
布尔 | 1 | 假 | 布尔 |
- 布尔型
布尔 类型只含有两个值:true 和 false。字节存储为 11111111 和 00000000 。
boolean b = true;
boolean b = false;
- 字符型
char 类型使用单引号来表示字符。因为 Java 统一采用 unicode 编码,2 字节可以表示一字符。char 类型同样可以用十六进制码保存汉字等特殊字符:'\u0000' - '\uffff'。
char ch = 'a';
char ch = '中';
char ch = '/u3089';
- 整型和浮点型
Java 没有无符号类型,所有数据都有符号。
-
整型(byte/short/int/long) 用来表示整型数据。
-
浮点型(float/double) 用来表示浮点数据,实际以指数形式存储,所以和实际值之间有偏差。
-
为 float 类型赋值必须在数字后加 f,否则数字默认被识别为 double 类型,会导致赋值出错。
-
数字基本类型都包含最大最小值常量,如 和 .
Integer.MAX_VALUE
Integer.MIN_VALUE
-
在浮点型有三个特殊数值表示溢出和出错:
POSITIVE_INFINITY
:正无穷大,正数除以 0 可以得到。NEGATIVE_INFINITY
:负无穷大,负数除以 0 可以得到。NaN
:非数,零除以 0 可以得到。(两个 NAN 值也不相等)
-
int n = 0;
float f = 0.0f;
long l = Long.MAX_VALUE;
double d = POSITIVE_INFINITY;
包装类型
均继承自 Number 抽象类,把基本类型数据封装成对象。基本类型和包装类型之间会自动进行转化。
-
基本类型(如int),是一个值。允许不赋初值,系统自动添加默认值。
-
包装类型(如Integer),是一个对象。实例化必须赋初值,且赋值后不能改变(final)。
包装类型主要用于集合框架中的元素。但阿里巴巴要求所有实体类(POJO) 属性、远程过程调用方法(RPC) 的返回值和参数都必须使用包装数据类型。以此来提醒使用者在需要使用时,必须显式地进行赋值。
类型转换
对于基础类型:
-
按上图顺序可以自动进行类型转换。但整型转化为浮点型时,如果数据过大可能会导致数据丢失精度。
-
反之则必须进行强制类型转换。但务必小心,超出范围可能会产生意想不到的错误。
int i = 'x'; // 自动转换
char c = (char)60; // 强制转换
但是包装类型之间的转换,需要使用特殊的方法。
Integer i = l.intValue();
Long l = i.longValue();
数组
数组 类
数据的集合。本质是一个对象,数据存储在堆区,由引用指向数组首个元素的地址。
创建数组
创建数组时,必须确定数组长度和类型。但如果储存的是基本类型,允许不赋初值(使用默认值)。
int[] arr = new int[4]; // 方法一
int[] arr = {1,2,3,4}; // 方法二
int[] arr = new int[]{1,2,3,4}; // 方法三
数组长度:在数组对象中,定义了 长度 属性记录了数组长度。
int len = arr.length; // 返回数组长度
数组类
对数组进行操作的辅助类,实现了对数组的常用操作。
数组排序
sort 方法:可以对数组排序,默认数组数值从小到大排列,用户可以自定义排列顺序,
Arrays.sort(arr); // 数组排序
数组复制
copyOf/copyOfRange 方法:复制数组。底层调用 System.arrayCopy 的本地方法实现,常用于数组扩容。
int[] arr1 = Arrays.copyOf(arr, 10); // 复制数组:前 10 个单位
int[] arr2 = Arrays.copyOf(arr, 0, arr.length); // 复制数组:从 0 到 arr.length - 1
数组转化
asList 方法:将数组转化为列表(List 类),但数组数据必须是包装类型。
调用该方法将数组转换为列表后,在内存中实际还是以数组形式存储。这可能会导致以下两个问题:
- 调用 List 类的 add 方法向列表中插入数据,会导致异常;
- 对原数组进行更改,也会导致列表中的数据发生变化。
arr[] = new Integer[]{1, 2, 3, 4}; // 数组必须是包装数据类型
List list = Arrays.asList(arr); // 将数组转换为集合(有问题)
List list = new ArrayList<>(Arrays.asList(arr)); // 将数组转换为集合(推荐)
字符串
字符串 类
保存字符串。String 类本质是一个 final 对象,由引用指向存储字符串对象的地址。引用虽然可变,但内存数据不能被更改。
创建字符串
String 对象创建后一经赋值不再改变,有以下两种创建方式:
-
直接赋值:如果常量池没有,则在常量池新建对象。否则直接使用常量池中已有对象,引用指向常量池。
-
构造方法:如果常量池没有,则在常量池新建对象。无论如何一定会在堆区创建对象,引用指向堆区。
String str1 = "string"; // 引用指向常量池
String str2 = "str" + "ing"; // 引用指向常量池(指向 str1 的字符串对象)
String str3 = new String("string"); // 引用指向堆区(在堆区新建字符串对象)
String str4 = str1 + str2; // 引用指向堆区
String newStr = new String(str.getBytes("ISO-8859-1"), "GBK"); // 获取指定类型编码对象,按指定类型编码
String 对象创建后一经赋值不再改变。对字符串数据进行改变,实际是创建新的 String 对象,并改变引用指向新的对象。
str1 = "goodbye"; // str1 指向新的字符串对象
常用方法
int len = str.length(); // 返回字符串长度
String[] strs = str.split(","); // 按分隔符分解字符串
boolean c = str.contains(str2); // 判断是否存在子字符串
int index = str.indexOf(str2); // 查找子字符串出现的第一个位置,没有返回-1
int index = str.lastIndexOf(str2); // 查找子字符串出现的最后一个位置,没有返回-1
String str2 = str.trim(); // 去除字符串左右空格
String str2 = str.substring(0,3); // 截取指定位置(0-2)的子字符串
String str2 = str.replace("a", "b"); // 新字符 a 替换旧字符 b
类型转换
// Number > String
String s1 = data.toString(); // data 必须为包装数据类型
String s2 = Integer.toString(data); // data 可以为基础数据类型,包括字符数组 char[]
String s3 = String.valueOf(data); // data 可以为基础数据类型,包括字符数组 char[]
// String > char
char c = str.charAt(0);
char[] ch = str.toCharArray();
// String > int
int n1 = Integer.parseInt(str);
int n2 = Integer.valueOf(str);
StringBuilder / StringBuffer 类
由于 String 类不可变性,对其频繁更改往往会产生较多临时变量类,占用大量内存。对此我们通常使用 StringBuilder/StringBuffer 来避免,这两个类允许在原有内存地址对字符串进行操作。其中 StringBuilder 类性能更好,StringBuffer 类线程安全。
创建字符串
必须通过构造方法创建,不可以直接赋值的形式创建:StringBuffer str = “hello”;
。
字符串默认长度为16,超出后会进行自动扩容。
StringBuffer str = new StringBuffer("hello");
将 StringBuilder / StringBuffer 类转化为 String 类。
String str2 = str.toString();
专用方法
StringBuilder / StringBuffer 类可以使用 String 类的全部方法,还新增了以下方法直接对字符串进行修改。
str.append("add"); // 末尾添加字符串,也可以是其他基础类型
str.insert(0,"insert"); // 指定位置插入字符串,也可以是其他基础类型
str.deleteCharAt(6); // 删除指定位置(6)的字符
str.delete(6,8); // 删除指定位置(6和7)的字符串
str.reverse(str2); // 翻转字符串
大数
在 Java 程序中,我们可能会用到一些数值特别巨大、或者小数特别精确的数值,这些数值无法用基础类型表示。因此我们定义了 BigInteger/BigDecimal 类来保存这类数据,实际是以字符串形式在堆区存储。
BigInteger类
主要用来操作比 long 类型更大的整型数字。
大十进制类
基于 BigInteger 类实现。由于基本浮点数类型(float/double) 会产生精度丢失问题,因此常使用 BigDecimal 类代替。涉及金额必须使用该类。
float x = 1.0f; // 约等于 0.1
float a = 1.0f - 0.9f;
float b = 0.9f - 0.8f;
System.out.println(a == b); // false
BigDecimal a = new BigDecimal("1.0"); // 等于 0.1
BigDecimal b = new BigDecimal("0.9");
BigDecimal c = new BigDecimal("0.8");
BigDecimal x = a.subtract(b);
BigDecimal y = b.subtract(c);
System.out.println(x.equals(y)); // true
BigInteger 和BigDecimal类常用方法
BigDecimal x = a.add(b); // 加
BigDecimal x = a.subtract(b); // 减
BigDecimal x = a.multiply(b); // 乘
BigDecimal x = a.divide(b); // 除
BigDecimal x = a.abs(); // 绝对值
a.compareTo(b); // 比较大小
// BigDecimal 类专用
BigDecimal x = y.setScale(3, rules); // 设置精度和保留规则
枚举
Enum类
(JDK 1.5 新增)比 Class 类 多了部分特殊约束的特殊类型,能更加简洁地定义常量。
使代码更具可读性,允许进行编译时检查,预先记录可接受值的列表,并避免由于传入无效值而引起的意外行为。
自定义枚举类实际是继承 Enum 类的 final 类,在类中将自定义该类型的 public static final 属性,并引入了相关方法。
// 定义枚举类
public enum Day {
MONDAY, TUESDAY, WEDNESDAY,
THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
// 使用枚举类
public class Demo {
public boolean test(Day today){
if(today == Day.MONDAY) return true;
else teturn false;
}
}
我们可以通过在枚举类型中定义属性,方法和构造函数让它变得更加强大。
实际开发中,枚举类通常的形式是有两个参数(int code,Sring msg)的构造器,可以作为状态码进行返回。
public enum StatusCodeEnum{
SUCCESS(200,"成功"), NOTFOUND(404,"未找到"), ERROR(500,"错误");
private int code;
private String message;
// 根据常量自动构造
private StatusCodeEnum(int code, String message) {
this.code = code;
this.message = message;
}
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
@Override
public String toString() {
return "PinType{" +
"code=" + code +
", message='" + message + '\'' +
'}';
}
}
根据常量自动构造对象并调用方法
System.out.println(StatusCodeEnum.SUCCESS.getCode());
时间
数字类型
在日常 Java 开发中,我们最常使用 Long 类型,而不是 Date/Timestamp 类型表示时间。
我们可以通过 System.currentTimeMillis 方法获取当前系统时间,默认为 13 位的数字(精确到 ms)。
Long timestamp1 = System.currentTimeMillis(); // 13 位 精确到 ms
Long timestamp2 = (System.currentTimeMillis()) / 1000; // 10 位 精确到 s
泛型
泛型定义
定义类时并不固定数据类型,等到创建对象或调用方法时再明确数据类型。
编译过程中,由编译器检查类型安全,自动隐性地对类的数据类型进行强制转换(Object -> 指定数据类型)。编译后生成的 字节码文件(.class) 将不再含有泛型。
泛型使用
可使用 A-Z 之间的任何一个字母,常用:
- T (type): 表示具体的一个 java 类型
- K V (key value): 分别代表 java 键值中的 Key Value
- E (element): 代表 java 集合框架元素
- ?:表示不确定的 java 类
// 定义时使用泛型
public class Box<T> {
private T t;
public void set(T t) {
this.t = t;
}
public T get() {
return t;
}
}
// 调用时明确类型
class Test{
static void main(String[] args){
Box<Integer> myBox = new Box<>();
myBox.set(3);
System.out.print(myBox.get());
}
}
五、数值比较和排序的常用方法
等值判断
Object 类实现了 equals 方法 ,用于比较两个数据元素是否相等。
浮点类型由于精度丢失问题,进行等值判断常出现错误。如果有需求推荐使用 BigDecimal 类。
int a = 20 - 10;
int b = 10;
System.out.println(a.equals(b)); // true
double a = 20.0 - 10.0;
double b = 10.0;
System.out.println(a.equals(b)); // false
和 == 的区别
-
对于基本类型,两者等价:判断数据是否相等。
-
对于对象(如 String 类):
- ==:比较两个元素内存地址是否相等,即是否是同一个元素。
- equals 方法:比较两个元素内容是否一致。
System.out.println(s1 == s2); // 判断两个引用指向的内存地址是否相等
System.out.println(s1.equals(s2)); // 判断两个引用指向的内存地址是否相等(s1 为空抛出空指针异常)
System.out.println(Objects.equals(s1,s2)); // 判断两个引用指向的元素是否一致(推荐)
重写 等于 方法
对于用户自定义类,正常使用等于 方法需要进行重写。重写 equals 方法必须重写哈希码 方法:以保证相同对象拥有相同的哈希地址。这样才能正常地把该类对象放入 HashSet/HashMap 等集合框架中查找。
Object 类的 hashcode 方法是本地方法(底层用 c/c++ 实现),直接返回对象的内存地址。
public class User{
int ID;
String name;
......
@Override
public boolean equals(Object obj) {
if(this == obj) return true;
if(obj == null) return false;
if(obj instanceof User){
User other = (User) obj;
if(equals(this.ID, other.ID) && equals(this.name, other.name)){
return true;
}
}
return false;
}
@Override
public int hashCode() {
int result = 17;
result = 31 * result + (ID == null ? 0 : ID.hashCode());
result = 31 * result + (name == null ? 0 : name.hashCode());
return result;
}
}
数值比较
Comparator 接口和 Comparable 接口都用于比较两个元素的大小:
-
Comparable 接口位于 java.lang 包内,定义在要比较的实体类内部:包含 compareTo 方法。
-
Comparator 接口位于 java.util 包内,实现在类的外部:包含 compare 方法和 equals 方法。
Comparator 接口的 equals 方法和 Object 类的 equals 方法不同, Object 类的 equals 方法实现在实体类的内部。
compareTo方法
Java 自带数据类型均已实现 Comparable 接口并重写 compareTo 方法,默认情况下
- 如果 s1 等于 s2,则返回 0;
- 如果 s1 小于 s2,则返回小于 0 的值;
- 如果 s1 大于 s2,则返回大于 0 的值。
Integer s1 = 100;
Integer s2 = 90;
System.out.println(s1.compareTo(s2));
比较 方法
Arrays/Collections 类定义了 sort 方法对数组或者集合元素进行排列,数值的比较通过调用 Comparator 接口的 compare 方法实现。
执行 sort 方法时如果没有重写 compare 方法,默认调用的 compare 方法将会直接调用数据类型的 compareTo 方法,使数据从小到大排列。如果是自定义数据类型且未实现 compareTo 方法,则必须重写 compare 方法。
Arrays.sort(students); // 对数组排序
Collections.sort(students); // 对集合元素排序
开发者可以通过重写 compare 方法,实现自定义排列顺序。但要注意,如果数组中保存的是基础类型数据则无法自定义排序。
Arrays.sort(students, new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
return s1.getID() - s2.getID();
}
});
Collections.sort(students, (s1, s2) -> s1.getID() - s2.getID()); // 使用 Lamdba 表达式简写
数据排序
Arrays/Collections 类定义了 sort 方法对数组或者集合元素进行排列,数值的比较通过调用 Comparator 接口的 compare 方法实现。
六、异常
异常类型
可投掷类
Java 程序中的异常是一个在程序执行期间发生的事件,它中断正在执行程序的正常指令流。为了能够及时有效地处理程序中的运行错误,必须使用异常类。
java 程序中所有的异常都继承自 Throwable 类,Throwable 类有两个子类 Error 类和 Exception 类:
-
Error 类:【错误】表示 java 程序在运行时产生的无法处理的故障(如堆栈溢出),错误出现时会导致程序无法正常执行并强制退出。
-
Exception 类:【异常】表示 java 程序中产生的可以被处理的故障,异常出现时可以由程序进行处理。
运行时异常类
【运行时异常】 Exception 类的子类。
表示 java 程序运行状态中发生的异常,在编译时无法被检测。在 java 程序运行时会由系统自动抛出,允许应用程序不进行处理。
异常类型 | 介绍 |
---|---|
算术异常 | 算术异常,以零做除数 |
ArrayIndexOutOfBoundException | 数组越界异常 |
NullPointerException | 空指针异常,对象不存在 |
已检查异常类
【可检查异常】Exception 类除 RuntimeException 以外其他子类的统称。
表示 java 程序编译时检测到的异常。出现时必须在程序中进行捕获或抛出,否则编译不会通过。
异常类型 | 介绍 |
---|---|
IOException | IO 异常 |
FileNotFoundException | 找不到文件异常,继承自 IO 异常 |
ClassNotFoundException | 找不到类异常 |
异常类
源码解析
状态信息
Throwable / Exception 类是有状态的(因此 Throwable 是接口而不能是类),记录了四个信息:
private transient Object backtrace; // 栈的回溯点
private String detailMessage; // 异常的信息:在创建异常时备注
private Throwable cause = this; // 异常的原因:导致该异常的异常,默认为自身
private StackTraceElement[] stackTrace = UNASSIGNED_STACK; // 异常的发生顺序:以栈的形式存储
构造方法
Throwable / Exception 类含有四个构造方法,在创建时可以记录异常信息:
throw new Exception(); // 默认
throw new Exception("message"); // 记录异常信息
throw new Exception(e); // 记录异常原因
throw new Exception("message", e); // 记录详细信息和异常原因
常用方法
Throwable / Exception 类定义了多种常用方法用于获取异常数据,常用的有:
- getMessage 方法:获取异常的信息。
- getStackTrace 方法:获取的异常发生顺序。
- printStackTrace 方法:获取异常的发生顺序并打印(开发和调试阶段用来显示异常信息,帮助开发者找出错误)。
catch(Exception e){
System.out.println(e.getMessage());
e.printStacTrace();
}
自定义异常
我们也可以通过继承并重写 Exception / RuntimeException 类的方式,自定义异常类并使用。
// 自定义异常,重写方法可任选
class MyException extends Exception {
@Override
public MyException() {
super();
}
@Override
public MyException(String message) {
super(message);
}
@Override
public MyException(String message, Throwable cause){
super(message,cause);
}
@Override
public MyException(Throwable cause) {
super(cause);
}
}
异常转译
在项目开发过程中,当 Sevice/DAO 层出现如 SQLException 异常时,程序一般不会把底层的异常传到 controller 层。程序可以捕获原始异常,然后再抛出一个新的业务异常。
catch(SQLException e){
throw new MyException("SQL Error", e);
}
异常处理
抛出异常throw
当方法执行出现问题时,方法就会创建异常对象并抛出。开发者可以在程序中自行抛出异常;JVM 在执行程序时发现问题也会自动抛出异常。
-
throw 语句:开发者自行创建异常对象并抛出,等待程序进行异常处理。
-
throws 语句:声明方法可能抛出某种异常且未经处理,调用该方法的上级需要进行异常处理。
class TestException{
// 把方法中的抛出异常交给上层处理
public void writeList(int size) throws IndexOutOfBoundsException, IOException{
PrintWriter out = null;
// 用户自定义异常并抛出
if(size < 1) throw new IndexOutOfBoundsException("至少要输出1个字符");
try{
// 虚拟机自动发现异常也会抛出,必须出现在 try 代码块中
out = new PrintWriter(new FileWriter(txt));
for (int i = 0; i < size; i++)
System.out.println("Value at: " + i + " = " + list.get(i));
}finally{
if (out != null) out.close();
}
}
}
捕获异常
当方法执行抛出异常时,必须由专门的代码块对异常进行处理。
-
try 语句:可能出现异常的代码块。
-
catch 语句:捕获相应异常后停止执行 try 代码,转而执行对应 catch 代码。如果没有异常 catch 代码不会执行。
-
final 语句:无论是否发生异常,最后 代码总会被执行。一般用于释放资源。
注意事项
-
如果 try 语句中出现的异常未被 catch,默认将异常 throw 给上层调用者处理。但必须在方法中声明 throws。
-
try/catch 代码中的 return 语句会在执行完 最后 后再返回,但 final 中对返回变量的改变不会影响最终的返回结果。
-
最后 代码中应避免含有 return 语句或抛出异常,否则只会执行 最后 中的 返回 语句,且不会向上级抛出异常。
Java 7 后在 try 语句中打开 IO 流,会在跳出后自动关闭流。不必再用 最后 语句关闭。
class TestException{
public void writeList(int size) {
PrintWriter out = null;
try {
if(size < 1) throw new IndexOutOfBoundsException("至少要输出1个字符");
out = new PrintWriter(new FileWriter("OutFile.txt"));
for (int i = 0; i < size; i++)
System.out.println("Value at: " + i + " = " + list.get(i));
} catch (IndexOutOfBoundsException e) {
System.err.println("Caught IndexOutOfBoundsException: " + e.getMessage());
} catch (IOException e) {
System.err.println("Caught IOException: " + e.getMessage());
} finally {
if (out != null) out.close();
}
}
}
七、正则匹配
基本使用
java.util.regex 包主要包括以下三个类:
- 模式类
正则表达式的编译表示。没有公共构造方法,必须首先调用其公共静态编译方法获得 Pattern 对象。
- 匹配器类
对输入字符串进行解释和匹配操作的引擎。没有公共构造方法,需要调用 Pattern 对象的 matcher 方法获得 Matcher 对象。
- PatternSyntaxException 类
非强制异常类,表示正则表达式模式中的语法错误。
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexMatches {
public static void main( String args[] ) {
Pattern p = Pattern.compile("abc"); // 编译正则表达式
Matcher matcher = p.matcher("abcdefg"); // 放入字符串中匹配
System.out.println(matcher.lookingAt()); // 是否存在子串匹配 true
System.out.println(matcher.matches()); // 是否完全匹配 false
}
}
正则表达式
我们可以通过使用特殊符号,让一个正则表达式能够匹配多种符合要求的字符串。
表意符号
-
.
表示任意字符
在 Java 中,正则表达式编译需要再经过一次转义。因此 才表示插入一个正则表达式的反斜线!\\
\\d
表示一位数字\\\\
表示一个反斜杠
字符集
x|y
匹配 x 或 y[abc]
匹配括号中任意单个字符[^abc]
匹配除括号中的任意单个字符[a-zA-Z]
匹配任意单个字母[a-z&&[^def]]
除 def 外的任意单个字母
字符串匹配
通过 、、 符号,我们可以对指定类型的字符串进行匹配。?
*
+
贪婪模式 | 饥饿模式 | 独占模式 | 结果 |
---|---|---|---|
X? | X?? | X?+ | 匹配0或1次 |
X* | X*? | X*+ | 匹配0次或多次 |
X+ | X+? | X++ | 匹配1次或多次 |
X{n} | X{n}? | X{n}+ | 匹配n次 |
X{m,n} | X{m,n}? | X{m,n}+ | 匹配m-n次 |
在匹配字符串时,同一个正则表达式可能会在在字符串中匹配到多种结果。Java 提供了以下三种方式供开发者选择:
- 贪婪模式 (默认)尽可能匹配长字符串。
- 饥饿模式 (?)尽可能匹配短字符串。
- 独占模式 (+)尽可能匹配长字符串,不成功会结束匹配而不回溯。
捕获组
普通捕获组
我们可以在正则表达式中同时捕获多个结果,最终以 group 的形式呈现。
- matcher.group(0) 完全匹配整个正则表达式。
- matcher.group(1-n) 从左到右分别记录正则表达式中 n 个括号内的结果。
public class RegexMatches {
public static void main( String args[] ) {
String regex = "(\\d{4})-((\\d{2})-(\\d{2}))"
Pattern p = Pattern.compile(regex); // 编译正则表达式
Matcher matcher = p.matcher("2020-10-25"); // 放入字符串
matcher.find(); // 执行匹配
System.out.printf(matcher.group(0)); // 2020-10-25
System.out.printf(matcher.group(1)); // 2020
System.out.printf(matcher.group(2)); // 10-25
System.out.printf(matcher.group(3)); // 10
System.out.printf(matcher.group(4)); // 25
}
}
命名捕获组
我们可以通过 对括号内容就行命名,并通过名称获取括号内的匹配结果。(?<Name>Expression)
public class RegexMatches {
public static void main( String args[] ) {
String regex = "(?<year>\\d{4})-(?<md>(?<month>\\d{2})-(?<date>\\d{2}))";
Pattern p = Pattern.compile(regex); // 编译正则表达式
Matcher matcher = p.matcher("2020-10-25"); // 放入字符串中匹配
matcher.find(); // 执行匹配
System.out.printf(matcher.group("year")); // 2020
System.out.printf(matcher.group("md")); // 10-25
System.out.printf(matcher.group("month")); // 10
System.out.printf(matcher.group("date")); // 25
}
}
非捕获组
我们可以通过 对组不进行捕获。(?:Expression)
(?=pattern)
例如,'Windows (?=95|98|NT|2000)' 匹配“Windows 2000”中的“Windows”,但不匹配“Windows 3.1”中的“Windows”。
预测先行不占用字符,即发生匹配后,下一匹配的搜索紧随上一匹配之后,而不是在组成预测先行的字符后。
(?!pattern)
如 'Windows (?!95|98|NT|2000)' 匹配“Windows 3.1”中的 “Windows”,但不匹配“Windows 2000”中的“Windows”。
预测先行不占用字符,即发生匹配后,下一匹配的搜索紧随上一匹配之后,而不是在组成预测先行的字符后。
Java SE的基础知识就到这里了,小伙伴们掌握多少呢,让我们一起加油!