1.Pattern类和 Matcher类
1.Pattern类型
1.1简介:
因为正则表达式只能做一些简单的校验工作,像要做进一步复杂的工作,需要使用Pattern类和 Matcher类。
字符串在真正的校验过程中,实际上底层维护了一个pattern对象,使用对象的相关方法进行校验;
pattern类的构造器私有化了,因此我们不能通过构造器创建对象,但是可以利用工厂方法来创建对象: static compile(String regex):
通过一个案例来理解创建pattern对象校验字符串的过程:
java
public static void main(String[] args) {
String regex = "[a-zA-Z][_$a-zA-Z0-9]{7,9}";
//获取一个Pattern对象
Pattern p1 = Pattern.compile(regex);
//和普通字符串进行校验,会得到一个Mathcer对象,该对象封装的时匹配的结果,并提供各种操作
Matcher matcher = p1.matcher("micheal12_");
//想要得到是否匹配成功,需要调用Matcher里的matches(). 该方法的作用是从头到尾严格匹配
//匹配成功返回true,匹配失败返回false
boolean match = matcher.matches();
System.out.println("是否匹配成功"+match);
}
我们首先定义了一个正则表达式,要求第一位是字母,第二位是字母数字或下划线$,剩余的长度应该是7-9位。之后调用工厂方法把正则表达式传入,创建对象p1,然后创建一个matcher对象使用p1去匹配想要比较的字符串。结果封装在matcher对象中,想要获取结果,需要调用matcher对象的matches()方法,并打印出结果。
2.pattern对象的其他方法
String pattern();
作用: 返回pattern的正则表达式,即特殊的字符串
java
public static void main(String[] args) {
String regex = "\\d+";
String str = "aaa111bbb222ccc";
//获取一个Pattern对象
Pattern p1 = Pattern.compile(regex);
/**
* String pattern():
* 作用:返回Pattern的正则表达式,即特殊的字符串
*/
String str2 = p1.pattern();
System.out.println(str2);
我们先定义了一个正则表达式,要求至少传入一位的数字或字母或下划线,然后创建p1对象,之后新定义了一个字符串并通过p1调用pattern()方法,来获取传入的那个正则表达式;
String[ ] split(String str)
作用:对字符串进行切分,符合正则表达式的字符串会被切除并作为隔板,来分割字符串,返回一个数组
java
String[] split = p1.split(str);
System.out.println(Arrays.toString(split));
2.Matcher类型
该类的构造器也私有化了,不能直接通过构造器来创建对象,需要通过pattern对象的matcher()方法来创建对象,该方法的形参是需要比较的字符串,创建出的对象储存的是匹配的结果。该类提供了多种方法,并且可以对结果进行多种操作。
matches() lookingAt() find() start() end() group() groupCount() reset() 等
matchers()方法:
该方法在上述的代码中已经演示一遍了,在使用的时候需要使用matcher对象来调用,返回值是布尔类型,返回的结果就是匹配的结果,匹配成功返回true,匹配失败返回false
lookingAt() 方法:
该方法用于匹配一个普通的字符串前面是否符合正则表达式规定的形式,需要注意:内部有一个类似指针的操作,匹配成功后指针会指向子串,在匹配前指针位于字符串的前面;
java
String regex = "\\d+";
// String info = "1234abcd";
String info ="abc123";
Pattern pattern = Pattern.compile(regex);//获取模式对象
Matcher matcher = pattern.matcher(info);//获取匹配结果对象
boolean result = matcher.lookingAt();
System.out.println(result);
创建matcher对象的过程就不过多赘述了,该方法的返回值是一个bollean类型,需要使用matcher对象来调用,匹配成功就返回true,匹配失败就返回false
传入的字符串开头不是以数字开头的,所以会返回false;
find( )方法:
该方法用于匹配字符串中是否有符合正则表达式的子串,匹配操作会一直执行到字符串的最后一个位置,如果有,返回true,该方法的返回值也是boolean类型,需要注意的是:该方法中也有一个指针操作;如果匹配到子串,指针就会向后移动,寻找下一个子串,在匹配操作开始前,指针也位于字符串的前面
java
regex = "\\d+";
info ="abc123eee444ff555ggg";
pattern = Pattern.compile(regex);
matcher = pattern.matcher(info);
//循环的次数表示了find()找到的符合正则表达式要求的子串的个数
while(matcher.find()){
System.out.println("--匹配成功--");
}
该方法寻找的子串需要满足是至少一位数字,会找到133,444,555三组,所以用while循环,会返回三次匹配成功fin
group() groupCount() reset() start() end() 这几个方法必须要基于匹配操作成功之后的操作
group()方法:
该方法的返回值类型是String类型,用于返回指针指向的符合正则表达式的那部分子串
java
Pattern pattern = Pattern.compile("\\d+");
Matcher matcher = pattern.matcher("abc123def456xxx");
while(matcher.find()){
System.out.println(matcher.group());
}
在上述代码中,我们使用while循环寻找符合正则表达式的子串,并在找到之后直接调用group方法打印出来,会找到123,456
需要注意的是,在寻找子串的操作结束后,指针会处于找到的最后一个子串的尾部,此时我们如果想再次寻找符合条件的子串,指针会继续向后移动,导致查找失败,所以我们需要重置指针,再重新查找
java
matcher.reset();
while(matcher.find()){
System.out.println(matcher.group());
}
start() end() 方法
这两个方法的返回值是int类型;start用于返回符合正则表达式子串的开始索引,end用于返回符合正则表达式子串的结束索引+1(索引的初始位置是0)
java
public static void main(String[] args) {
Pattern pattern = Pattern.compile("\\d+");
Matcher matcher = pattern.matcher("abc123def456xxx");
int count = 1;
while (matcher.find()) {
int start = matcher.start();
int end = matcher.end();
System.out.println("第" +count +"部分的开始和结束位置 "+start+"," + end);
count++;
}
}
我们在这个演示中定义了一个count用于记录检索出符合正则表达式子串的次数,该方法也是使用对象来调用;
lookingAt() 和 find() 在一起使用时,可能会影响指针的操作
java
public static void main(String[] args) {
Pattern pattern = Pattern.compile("\\d+");
Matcher matcher = pattern.matcher("123aaa444bbb555");
System.out.println("字符串是否以数字开头"+matcher.lookingAt());
/**
* 因为在使用lookingAt时指针向后移动了一次
* 所以在使用find()方法时,指针就不是从字符串前就开始移动的,而是紧随着lookingAt()方法的位置移动
* 注意指针重置的问题
*/
// matcher.reset();
while(matcher.find()){
System.out.println(matcher.group());
}
}
在上述代码中,我们先使用lookingAt方法判断字符串是否以数字开头,在判断的过程中,指针已经移动到第一个以数字开头的子串后,所以这时候我们调用find()方法去检索每一个符合正则表达式的子串时,会导致找不到第一个子串,返回的结果只有第二个和第三个子串,
为了解决这个问题,我们必须让指针复位,使用reset方法
groupCount()方法
该方法的返回值是int类型,用于返回正则表达式中小括号的个数
java
public static void main(String[] args) {
Pattern pattern = Pattern.compile("(ca)(t)");
Matcher matcher = pattern.matcher("one cat, two cats in a yard");
/**
* int groupCount()
* 作用:用于获取正则表达式中小括号的个数。()用于分组
*/
System.out.println(matcher.groupCount());
while(matcher.find()){
//打印符合正则表达式的子串,因此循环次数是两次
System.out.println(matcher.group());
}
System.out.println("=======================");
matcher.reset();
matcher.find();
//使用小括号的个数来循环,可以使用group()重载方法,String group(int group)
//注意,想要使用小括号的个数进行遍历,需要将指针移动到字符串之前,然后还需要find()方法,使指针归位
//group(0): 表示的是对组进行拆分括号整体的样子
//group(1):表示第一个括号
//group(2):表示第二个括号
for (int i = 0; i <= matcher.groupCount(); i++) {
System.out.println(matcher.group(i));
}
}
在上述代码中,我们传入的正则表达式是(ca)(t),在我们直接使用find方法通过循环可以得到两个cat,我们也可以通过小括号的个数来进行循环,需要注意,我们需要把指针复位,我们可以分别通过遍历分别得到满足两个括号的子串,满足第一个括号的子串,满足第二个括号的子串
所以满足两个括号的子串样式就是cat,满足第一个括号的样式就是ca,满足第二个括号的样式是t打印结果如下:
2.包装类
1.包装类的学习
因为Java是面向对象编程的语言,而基本数据类型没有面向对象的特征,所以Java专门为这些基本数据类型设计了具有面向对象特征的类,实际上就是对这些数据类型做了类的封装,即里面有一个基本数据类型的成员变量和成员方法,常量等
除了int 和 char以外的其余六个基本数据类型的包装类名都是基本数据类型的首字母大写的形式
int---Integer char---Character
装箱和拆箱操作:
装箱:调用包装类的valueOf方法获取一个包装类对象的过程称之为装箱
拆箱:调用包装类里的XXXValue方法,返回一个基本数据类型的过程称之为拆箱
我们通过一个案例来更好的理解装箱和拆箱:
java
public static void main(String[] args) {
//装箱操作,对1进行封装,获取一个包装类对象,思考:num存储的是什么?
//存储的是对象的地址 int a = 1; a存储的是值
Integer num = new Integer(1);
//num和num2是不是同一个对象? 两个对象
Integer num2 = Integer.valueOf(1);//利用valueOf()的方式进行装箱,类名调用
System.out.println(num==num2); //是两个不同的对象,只不过对象的成员变量的值一样
System.out.println(num.equals(num2)); //true,值是相等的
//拆箱 包装类对象调用方法xxxValue();
int i = num.intValue();//调用对象的intValue()方法来进行拆箱操作
//形参是包装类,因此可以赋值为null,编译器不会报错
// Integer result = calculate(null,num2);
Integer result = calculate(num,num2);
System.out.println(result);
//
}
//定义一个方法,形参是包装类型
public static Integer calculate(Integer num, Integer num2) {
return num+num2;
}
首先我们调用构造器创建了一个Integer类型的对象num,然后使用Integer.valueOf的方式来创建一个Integer对象num2;并判断它们两个是不是一个对象,由于都是相当于new出来的,所以说肯定返回false,之后判断他们的值是否相同,值都是1,返回true。当使用拆箱时,需要使用包装类对象来调用intValue()方法,我们在后面定义了一个返回值类型是Integer方法calculate,返回值是两个形参的和,在main方法中直接调用该方法,传入两个参数num,num2并设置返回值,打印结果,可以得到两个包装类对象的和,说明包装类也可以作为返回值类型。
2.包装类的自动拆箱和装箱
从jdk1.5开始,引入了包装类的自动拆箱和装箱;
自动装箱:将基本数据类型的字面量(直接表达式的数)或变量直接赋值给包装类的变量;本质上编译器在编译期间自动调用了valueOf方法;进行包装
自动拆箱:将包装类的变量的地址直接赋值给基本数据类型的变量,本质上编译器在编译期间调用了XXXValue方法,进行拆箱
java
public static void main(String[] args) {
Integer num = 1; //发生了自动装箱的操作,底层调用了Integer.valueOf()进行包装
int a = 10;
Integer num2 = a;//也是自动装箱
//自动拆箱
int x = num; //底层隐含了num.intValue();
int y = new Integer(100);
}
我们直接声明一个包装类的对象并初始化为int类型的1,编译器自动调用了valueOf方法装箱;也可以直接声明一个int类型的变量a,将其直接赋值给包装类的对象
对于自动拆箱操作,我们直接声明一个变量 x,并将包装类对象num的地址赋值给该变量,实现了自动拆箱,还可以直接调用包装类的构造器并传入参数100来赋值
3.包装类的常量池
自动装箱或者手动装箱的对象都会有常量池;Byte,Short,Integer,Long四种类型的常量池的范围[-128,127] ; Character的常量池范围是[0,127] ; Boolean的常量池就只有两个值 true和false ; 浮点数类型没有常量池
java
public static void main(String[] args) {
//检验常量池
Integer n1 = 10;
Integer n2 = 10;
int a = 10;
System.out.println(n1 == n2);//true
Integer n3 = Integer.valueOf(a);
System.out.println(n3 == n2);//true
Integer n4 = new Integer(10);
System.out.println(n4 == n2);//false,new出来的对象都是在堆里的
//范围
Integer n5 = 128;
Integer n6 = 128;
System.out.println(n5 == n6);//false 128超过范围了,应该是在堆中创建的
Boolean b1 = true;
Boolean b2 = true;
//调用常量也是常量池
// Boolean b2 = Boolean.TRUE;
System.out.println(b1 == b2);//true 在常量池中,不创建新的对象
Character c1 = 'a';
Character c2 = 'a';
System.out.println(c1 == c2);//true
}
在上述的代码中,我们检验了包装类的常量池;首先定义了n1和n2,并都赋值为10;在包装类常量池中检验他们是不是一个对象;之后又通过装箱的操作定义了n3,检验他们是不是同样的对象,检验结果是true,然后我们通过new关键字创建了一个和n2值一样的对象n4,经过检验发现他们不是同一个对象;
然后检验常量池的范围,Integer的范围是[-128,127],我们定义的值是128,超出了字符串常量池,对象就变为在堆中创建;之后我们测验了Boolean类型的对象,如果值相同则也是一个对象;
对于Character类型也是一样的,只要不超过范围,就不会产生新的对象,这样有利于保护内存,节约空间;
4.包装类的其他方法或者常量
java
System.out.println(Short.MAX_VALUE);//32767
System.out.println(Short.MIN_VALUE);//-32728
//找出两个数中的较大值
System.out.println(Integer.max(10,20));//20
System.out.println(Integer.min(10,20));//10
我们可以通过类名调用他们内部的常量,比如最大值最小值;也可以通过类名调用内部已经定义好的成员方法,比如找出最大值,最小值;
static int parseInt( String str )
该方法是一个静态方法,将字符串类型的值转为int类型的值,需要使用Integer类名来调用,方法声明了一个运行时异常;数字格式异常,当传入的数字字符串中含有不属于数字的形式,就会报异常
java
String str = "10";
// String str = "10a"; 这样使用就会出现运行时异常NumberFormatException
int n1= Integer.parseInt(str);
System.out.println(n1);//10
java
int n2 = 10;
System.out.println(Integer.toHexString(n2));//16进制
System.out.println(Integer.toBinaryString(n2));//2进制
System.out.println(Integer.toOctalString(n2));//8进制
还可以通过包装类名调用一些方法,使int类型的数据转换为16进制,2进制,8进制等;
3. BigDecimal类型
当我们在进行计算时,尤其是要精确到浮点数15,16位的时候,建议使用BigDecimal类型;
常用的构造器:
new BigDecimal(int i);
new BigDecimal(double i); //不建议使用,因为double类型在传入的时候就可能已经发生精度缺失
new BigDecimal(long i);
new BigDecimal(String i); //如果想使用浮点数,建议使用String类型
加减乘除运算:需要注意:在除法的过程中,除不尽会报异常的,除数不能为0,对象也不能为null
-add -substract -multiply -divide
我们通过一个案例来演示;
java
BigDecimal bd1 = new BigDecimal("3");
BigDecimal bd2 = new BigDecimal("1.5");
BigDecimal r1 = bd1.add(bd2);
BigDecimal r2 = bd1.subtract(bd2);
BigDecimal r3 = bd1.multiply(bd2);
BigDecimal r4 = bd1.divide(bd2);
System.out.println("r1 = " + r1+"r2 = " + r2+"r3 = " + r3+"r4 = "+r4 );
在做除法运算时,除不尽就会发生异常,所以一般使用try-catch 来处理,以免影响其他程序的运行
java
public static void main(String[] args) {
BigDecimal bg1 = new BigDecimal("3");
BigDecimal bg2 = new BigDecimal("2.9");
//减法
System.out.println(bg1.subtract(bg2));
//除法
try{
System.out.println(bg1.divide(bg2));
}catch (ArithmeticException e){
e.printStackTrace();
}
System.out.println(bg1.subtract(bg2));
}
我们在使用减法是可以正常运行的,在做除法时,使用try-catch,以免影响打印下一次减法的结果