文章目录
Demo11-包装类、正则表达式、Lambda、算法
1.包装类
1.1包装类基础知识
1.包装类其实就是8种基本数据类型对应的引用类型
基本数据类型 | 引用数据类型 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
char | Character |
float | Float |
double | Double |
boolean | Boolean |
2.为什么提供包装类:
- java为了实现一切皆对象,为8种基本类型提供了对应的引用类型
- 后期的集合和泛型只支持引用类型,不支持基本数据类型,那么就需要将基本数据类型包装为对应的引用类型*(以前集合和泛型是支持基本数据类型的,但就是因为支持,所以没人用包装类,后来就规定集合和泛型不支持基本数据类型)*
3.自动装箱和自动拆箱:
- 自动装箱:基本类型的数据和变量可以直接赋值给包装类型的变量
- 自动拆箱:包装类型的变量可以直接赋值给基本数据类型的变量
1.2包装类相比基本数据类型特有功能:
-
包装类的变量可以是null,而基本数据类型就不可以
- Integer a = null;(正确)
- int a = null;(错误)
-
可以把基本类型的数据转换成字符串类型(没啥用):
- 法一:调用toString()方法得到字符串结果:
Integer i = 23; String rs = i.toString();
- 法二:调用Integer.toString(基本类型的数据):
Integer i = 23; String rs = Integer.toString(i);//参数类型是基本数据类型,这里自动拆箱了
- 但其实这个特性没啥用和,我们可以直接将基本数据类型数据或包装类型数据与空字符串连接构成字符串(我不知道为啥包装类型数据也可以和空字符串进行连接)
System.out.println(5+""); Integer i = 6; System.out.println(i + "");
-
可以把字符串类型的数值转换成真实的数据类型(要转换的字符串内容必须和对应的数据类型一致,否则会有NumberFormatException异常):
- 法一:Integer.parseInt(“字符串类型的整数”)注意:parseInt返回值是对应的基本数据类型
int age = Integer.parseInt("23");
- 法二:Integer.valueOf(“字符串类型的整数”)注意,valueOf返回值是对应的包装类类型
Integer age1 = Integer.valueOf("23"); int age2 = Integer.valueOf("23");//方法返回的是包装类型,自动拆箱赋值给基本数据类型的变量
2.正则表达式
2.1正则表达式基础知识
1.正则表达式可以用一些规定的字符来指定规则,并校验数据格式的合法性
2.字符串对象提供了匹配正则表达式规则的API:
public boolean matches(String regex):判断是否匹配正则表达式,匹配返回true,不匹配返回false
2.2正则表达式匹配规则
1.字符类(默认匹配一个字符)
举例 | 说明 |
---|---|
[abc] | 只能是a或b或c |
[^abc] | 除了a,b,c之外的任何字符 |
[a-zA-Z] | a到z,或A到Z |
[a-d[m-p]] | a到d,或m到p(我认为和[a-dm-p]一样) |
[a-z&&[def]] | d或e或f(交集) |
[a-z&&[^bc]] | a到z,除了b和c(相当于[ad-z]) |
[a-z&&[^m-p]] | a到z,除了m到p(相当于[a-lq-z]) |
\. | 小数点 |
2.预定义的字符类(默认匹配一个字符)
举例 | 说明 |
---|---|
. | 任何字符 |
\d | 一个数字,相当于[0-9] |
\D | 非数字,相当于[^0-9] |
\s | 一个空白字符,相当于[\t\n\xOB\f\r] |
\S | 非空白字符,相当于[^\s] |
\w | 英文或数字或下划线,相当于[a-zA-Z_0-9] |
\W | 一个非单词字符,**多在匹配中文时使用,**相当于[^\w] |
3.贪婪的量词(配合匹配多个字符)
举例 | 说明 |
---|---|
X? | X,一次或根本不 |
X* | X,零次或多次 |
X+ | X,一次或多次 |
X{n} | X,正好n次 |
X{n,} | X,至少n次 |
X{n,m} | X,至少n次但不超过m次 |
注意事项:
- 看上面的举例可以发现,匹配规则的[]或{}里面都没有空格,所以我们使用的时候也不要加空格,以防给自己挖坑
- 如果匹配规则中有单斜杠,一定要在单斜杠前面再加一个单斜杠使其成为一个普通的单斜杠而不是转义字符
// 验证码 必须是数字和字符 必须是4位
System.out.println("23dF".matches("[a-zA-Z0-9]{4}"));//true
System.out.println("23_F".matches("[a-zA-Z0-9]{4}"));//false
System.out.println("23dF".matches("[\\w&&[^_]]{4}"));//true
System.out.println("23_F".matches("[\\w&&[^_]]{4}"));//false
//判断手机号格式是否正确
System.out.println("13333".matches("1[3-9]\\d{9}"));//false
// 判断邮箱格式是否正确
//3268847878@qq.com(两级域名)
//3268847dsda878@163.com
//3268847dsda878@pci.com.cn(两级域名)
System.out.println("5888@qq.com".matches("\\w{1,30}@[a-z0-9]{2,20}(\\.[a-z]{2,20}){1,2}"));
// (\\.[a-z]{2,20}){1,2}")代表域名是一级域名或两级域名,其中\.用于匹配小数点,需要在单斜杠前面再加一个单斜杠使其成为一个普通的单斜杠而不是转义字符
//判断座机号是否正确
//027-496464
//027496464
System.out.println("020-121121".matches("0\\d{2,6}-?\\d{5,20}"));//?表示有1个或0个-
2.3正则表达式在字符串中的使用
方法名 | 说明 |
---|---|
public String replaceAll(String regex,String newStr) | 按照正则表达式匹配的内容进行替换 |
public String[] split(String regex) | 按照正则表达式匹配的内容进行分割字符串,返回一个字符串数组 |
public class RegexDemo04 {
public static void main(String[] args) {
String names = "小红dhdfhdf342小明43fdffdfbjdfaf小白";
String[] arrs = names.split("\\w+");//arrs数组内容:["小红","小明","小白"]
for (int i = 0; i < arrs.length; i++) {
System.out.println(arrs[i]);
}
System.out.println(names.replaceAll("\\w+", " "));//输出"小红 小明 小白"
}
}
2.4正则表达式爬取信息
//这个案例的流程是人家规定的,没有为什么这样那样,记着流程就可以了
public class RegexDemo04 {
public static void main(String[] args) {
String s = "好好学习133331757333天天向上, daydayup020-121121goodgoodstudy";
//1.定义爬取规则(|表示或)
String regex = "1[3-9]\\d{9}|0\\d{2,5}-?\\d{5,8}";
//2.编译正则表达式成为一个匹配规则对象
Pattern pattern = Pattern.compile(regex);
//3.通过匹配规则对象得到一个匹配数据内容的匹配器对象
Matcher matcher = pattern.matcher(s);
//4.通过匹配器去内容中爬取信息
while (matcher.find()) {
System.out.println(matcher.group());
}
}
}
//输出13333175733和020-121121
3.Arrays类
3.1Arrays基础知识
是数组操作工具类专门用于操作数组元素的(我们已经说过很多次了,工具类构造器私有化不能创建对象,工具类的方法都是静态方法,Arrays类也不例外)
Arrays类的常用API
方法名 | 说明 |
---|---|
public static String toString(类型[] a) | 将数组转为String类型 |
public static void sort(类型[] a) | 对数组进行默认升序排序(java这里使用的快速排序) |
public static void sort(类型[] a, Comparator<? super T>c) | 使用比较器对象自定义排序 |
public static int binarySearch(int[] a, int key) | 二分搜索数组中的数据,存在返回索引,不存在返回一个负数 |
关于binarySearch方法:
-
传入的数组参数必须排好序了,否则出bug(也不报错,但可能找不到这个元素)
int[] arr2 = {12, 36, 34, 25 , 13, 24, 234, 100}; //第一次36和25比较,比其大,往25右边找,然后就永远找不到25左边的36了~~ System.out.println(Arrays.binarySearch(arr2 , 36));
-
如果找不到,返回什么负数呢:- (应该将此数插入在哪个索引) - 1
public static void main(String[] args) { int[] arr = {2, 10, 23, 24, 55, 100}; //输出-7(由来,应该将此数插在索引6,那么-6-1=-7) System.out.println(Arrays.binarySearch(arr, 555)); }
3.2Arrays类对于Comparator比较器的支持
- Arrays的sort方法对于有值特性的数组是默认升序排序
- 使用比较器对象自定义排序规则时,数组类型必须是引用类型
- 可以这样理解:如果数组中的数据是基本类型,那默认升序排一下不就完了嘛,但是如果是引用类型,我想按身高或体重进行排序怎么办呢,这时就要自定义比较规则了.也就是说引用类型想排序只能用比较器对象,而基本类型也可以用但没必要,所以直接不让基本类型使用比较器对象
- 自己定义排序规则:
- 如果认为左边数据大于右边数据,返回正整数
- 如果认为左边数据小于右边数据,返回负整数
- 如果认为左边数据等于右边数据,返回0
public class ArraysDemo2 {
public static void main(String[] args) {
Integer[] ages1 = {34, 12, 42, 23};
//参数一:被排序的数组 必须是引用类型的元素
//参数二:匿名内部类对象,代表了一个比较器对象。
Arrays.sort(ages1, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
// if(o1 > o2){
// return -1;
// }else if(o1 < o2){
// return 1;
// }
// return 0;
//和上面注释掉的一样,但这种是不是更优雅了呢~~~
return o2 - o1; //降序
}
});
System.out.println(Arrays.toString(ages1));
System.out.println("------优雅的分割线-----------");
Student[] students = new Student[3];
students[0] = new Student(185.5);
students[1] = new Student(175.5);
students[2] = new Student(195.5);
// Arrays.sort(students); // 直接运行会报错
Arrays.sort(students, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return Double.compare(o2.getHeight(), o1.getHeight()); //降序,以后浮点数比较就这样来
}
});
System.out.println(Arrays.toString(students));
}
}
class Student {
private double height;
public Student(double height) {
this.height = height;
}
public double getHeight() {
return height;
}
@Override
public String toString() {
return "Student{" +
"height=" + height +
'}';
}
}
关于上述案例的第31行的return Double.compare(o2.getHeight(), o1.getHeight());:
-
因为height是浮点数,如果直接
- return o2.getHeight() - o1.getHeight();会报错,因为返回的是浮点型了,而人家要返回的是int型
- return (int)(o2.getHeight() - o1.getHeight());会达不到预期
- 比如173.3-173.2=0.1,强转后只保留整数变为0,那就是return 0,达不到预期了
-
正确做法是31行这样,看一下Double的compare方法源码:
public static int compare(double d1, double d2) { if (d1 < d2) return -1; if (d1 > d2) return 1; long thisBits = Double.doubleToLongBits(d1); long anotherBits = Double.doubleToLongBits(d2); return (thisBits == anotherBits ? 0 : (thisBits < anotherBits ? -1 : 1)); }
- 可以发现人家做了这样一件事
- d1 < d2返回-1
- d1 > d2返回1
- d1 == d2返回0
- 发现这个这个方法整好解决了我们的难题,所以使用这个方法实现程序
- 可以发现人家做了这样一件事
4.Lambda表达式
1.Lambda表达式是JDK8开始后的一种新语法形式,是为了简化匿名内部类的代码写法
2.Lambda表达式只能简化函数式接口的匿名内部类的写法形式
函数式接口:
- 首先必须是接口,其次接口中有且仅有一个抽象方法的形式
- 通常我们会在接口上加一个@FunctionalInterface注解,标记该接口必须满足是函数式接口
3.Lambda表达式的简化格式:
(匿名内部类被重写方法的形参列表) -> {
被重写方法的方法体代码
}
注:->是语法形式,无实际含义
4.Lambda表达式的省略写法(进一步在Lambda表达式的基础上进行简化)
- 参数类型可以不写
- 如果只有一个参数,参数类型可以不写,同时()也可以省略(就记着,省略小括号只有一种情况:有且仅有一个参数)
- 如果Lambda表达式的方法体只有一行代码,可以省略大括号不写
- 此时必须同时要省略分号
- 如果这一行代码是return语句,此时也必须省略return不写
.Lambda表达式省略写法速记:参数类型可以省略,如果还要进行下一步省略就看有没有满足:一个参数or一行代码
public class LambdaDemo2 {
public static void main(String[] args) {
//完整形式
Swimming s1 = new Swimming() {
@Override
public void swim() {
System.out.println("s1老师游泳贼溜~~~~~");
}
};
go(s1);
//初次简化:不要new Swimming和重写的方法名,只保留参数列表和方法体
Swimming s2 = () -> {
System.out.println("s2老师游泳贼溜~~~~~");
};
go(s2);
//再次简化:不要{}和分号
Swimming s3 = () -> System.out.println("s3老师游泳贼溜~~~~~");
go(s3);
//我们已经在匿名内部类说过,匿名内部类可以作为实参直接传给方法
go(new Swimming() {
@Override
public void swim() {
System.out.println("第一个学生游泳很开心~~~");
}
});
//依据上面的"初次简化":只保留参数列表和方法体
go(() ->{
System.out.println("第二个学生游泳很开心~~~");
});
//依据上面的"再次简化":不要{}和分号
go(() -> System.out.println("第三个学生游泳很开心~~~"));
}
public static void go(Swimming s){
System.out.println("开始。。。");
s.swim();
System.out.println("结束。。。");
}
}
@FunctionalInterface
interface Swimming{
void swim();
}