Java常用API

API

API(Application Programming interface) :应用程序编程接口。

Object

Object类是Java中所有类的祖宗类。Java中所有类的对象都可以直接使用Object类中提供的一些方法。

toString

返回对象的字符串形式。让子类重写,返回子类对象的内容。

1
2
3
4
5
6
7
8
9
10
11
12
public class Student {
private int age;
private String name;

@Override
public String toString() {//重写toString方法
return "Student{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
equals

默认比较两个对象的地址是否相等。让子类重写,用于比较对象的内容是否相同。

1
2
3
4
5
6
7
8
9
10
@Override
public boolean equals(Object o) {//上述Student类重写equals方法
//1.判断两个对象地址是否一样
if (this == o) return true;
//2.判断o是否为null,或者两个对象类型是否一样
if (o == null || getClass() != o.getClass()) return false;
//3.o不是null,且为学生类型,比较两个对象内容是否一样
Student student = (Student) o;
return age == student.age && Objects.equals(name, student.name);
}
clone

当某个对象调用这个方法时,clone方法会复制一个一模一样的新对象返回。

clone方法是protected,只能在Object所在的lang包下或者Object的子类中访问。需要在子类中重写clone方法才能在其他包下使用clone方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//User类
public class User implements Cloneable{//2.重写clone方法需要实现Cloneable接口,该接口啥也没有,但必须implements Cloneable
private String name;
private int age;
private double[] scores;

public User() {}

public User(String name, int age, double[] scores) {
this.name = name;
this.age = age;
this.scores = scores;
}

//1.重写clone()方法时要throws CloneNotSupportedException
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();//浅拷贝
//返回的是Object类型,clone后赋值时要强转为User类型
}

@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", scores=" + Arrays.toString(scores) +
'}' + ", scores addr=" + scores;
}
}
1
2
3
4
5
6
7
public static void main(String[] args) throws CloneNotSupportedException {//运行时需要throws CloneNotSupportedException 
User u1 = new User("surourou", 18, new double[]{100,99.8});
User u2 = (User) u1.clone();//clone返回的是Object类型,clone后赋值时要强转为User类型

System.out.println(u1);
System.out.println(u2);
}
浅克隆

深克隆

1
2
3
4
5
6
7
8
9
//实现浅克隆和深克隆
@Override
protected Object clone() throws CloneNotSupportedException {
//return super.clone();//浅拷贝
//深拷贝
User u2 = (User) super.clone();
u2.scores = u2.scores.clone();
return u2;
}

Objects

操作对象

1
2
3
4
String s1 = null;
String s2 = "girl";
//System.out.println(s1.equals(s2));//报错NullPointerException
System.out.println(Objects.equals(s1, s2));//更安全
1
2
3
4
//Objects.equals源码
public static boolean equals(Object a, Object b) {
return (a == b) || (a != null && a.equals(b));
}

包装类

包装类把基本类型的数据包装成对象

自动装箱:基本数据类型可以自动转换为包装类型。

自动拆箱:包装类型可以自动转换为基本数据类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
Integer i1 = new Integer(12);//已过时
Integer i2 = Integer.valueOf(12);
System.out.println(i1 + i2);

//自动装箱:自动把基本类型数据转换成对象
Integer i3 = 18;
//自动拆箱:自动把包装类型的对象转换成对应的基本数字类型
int i4 = i3;

ArrayList<Integer> list = new ArrayList<>();
list.add(18);//自动装箱
list.add(19);//自动装箱
int rs = list.get(0);//自动拆箱

1
2
3
4
5
6
7
8
9
10
11
12
//1.基本类型数据转换成字符串
Integer in1 = Integer.valueOf(23);
String st1 = Integer.toString(in1);//"23"
String st2 = in1.toString();//"23"
String st3 = in1 + "";//"23"

//2.字符串类型数值转换成对应的基本类型
String str1 = "18";
int age = Integer.valueOf(str1);

String str2 = "99.88";
double score = Double.valueOf(str2);

StringBuilder

StringBuilder可变字符串对象,相当于一个容器,它里面装的字符串可以改变,用来操作字符串。

StringBuilderString更适合做字符串的修改操作,效率更高。对于字符串相关的操作,如频繁的拼接、修改等,建议用StringBuidler效率更高。

1
2
3
StringBuffer sb = new StringBuffer();
sb.append("srr").append("666").append(18).append(true);//支持链式编程,且append可以是任意类型
System.out.println(sb);//srr66618true

StringBuffer

StringBuffer的用法与StringBuilder一模一样。

StringBuilder线程不安全StringBuffer线程安全的。

StringJoiner(JDK8)

JDK8开始才有,跟StringBuilder一样用来操作字符串的,也可以看成是一个容器,创建之后里面的内容可变

1
2
3
4
5
StringJoiner sj = new StringJoiner(",");
sj.add("srr").add("666");//srr,666

StringJoiner sj1 = new StringJoiner(",","[","]");
sj1.add("srr").add("666");//[srr,666]

Math

System

System代表程序所在的系统。

注意:exit方法参数为0代表人为操作,非零代表异常值。

Runtime

Runtime代表程序所在的运行环境。Runtime是一个单例类。

注意:

1.Systemexit方法就是调用Runtimeexit方法,两者是一样的。

2.totalMemoryfreeMemory返回的单位Byte/1024得到单位KB/1024/1024得到单位MB

3.使用exec方法启动程序需要throws IOException

1
2
3
Process p = rt.exec("D:\\software\\ToDesk\\ToDesk.exe");//需要throws IOException
Thread.sleep(5000);//需要throws InterruptedException
p.destroy();//销毁该程序

BigDecimal

BigDecimal用于解决浮点型运算时,出现结果失真的问题。

注意:

1.使用BigDecimal(double val)会出现精度问题,使用BigDecimal(String val)来进行构造

1
2
3
4
5
6
7
8
9
10
11
//两种方法构造BigDecimal类,效果一样
BigDecimal b1 = BigDecimal.valueOf(0.1);
BigDecimal b2 = new BigDecimal(Double.toString(0.2));
//不要使用new BigDecimal(0.2)来构造,会出现精度错误

System.out.println(b1.add(b2));

BigDecimal b3 = BigDecimal.valueOf(0.3);
//System.out.println(b1.divide(b3));//报错,java.lang.ArithmeticException: Non-terminating decimal expansion,无法确定精度
System.out.println(b1.divide(b3, 3, BigDecimal.ROUND_HALF_UP));
//保留3位小数,BigDecimal.ROUND_HALF_UP表示四舍五入

Date

Date代表日期和时间。

1
2
3
4
5
6
7
8
9
10
//Date对象代表系统当前时间信息
Date d1 = new Date();

long time = d1.getTime();
Date d2 = new Date(time);//时间毫秒值

Date d3 = new Date();
d3.setTime(time);

System.out.println(d1.toString() + "\n" + d2 + "\n" + d3);//三者一样:Sun Sep 22 14:57:55 CST 2024

SimpleDateFormat

SimpleDateFormat代表简单日期格式化,可以用来把日期对象时间毫秒值格式化成想要的形式。

1
2
3
4
5
6
Date d = new Date();
long t = d.getTime();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss EEE a");//指定格式
String s1 = sdf.format(d);
String s2 = sdf.format(t);
System.out.println(s1 + "\n" + s2);//两者一样:2024年09月22日 15:01:38 周日 下午

SimpleDateFormat可以解析字符串时间成为日期对象。

1
2
3
4
5
//指定的时间格式必须与被解析的时间格式一模一样,否则报错java.text.ParseException:
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String s3 = "2024-09-15 12:18:08";
Date date = sdf1.parse(s3);//必须throws ParseException
System.out.println(date);

Calendar

Calendar代表的是系统此刻时间对应的日历,通过它可以单独获取、修改时间中的年、月、日、时、分、秒等。

注意:calendar可变对象,一旦修改后其对象本身表示的时间将产生变化

Calendar是抽象类,类方法getInstance获取该类的通用对象,返回一个Calendar对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Calendar calendar = Calendar.getInstance();//系统此刻时间的日历对象
System.out.println(calendar);//该日历对象的全部信息
/*
java.util.GregorianCalendar[time=1726989854082,areFieldsSet=true,areAllFieldsSet=true,
lenient=true,zone=sun.util.calendar.ZoneInfo[id="Asia/Shanghai",offset=28800000,
dstSavings=0,useDaylight=false,transitions=31,lastRule=null],firstDayOfWeek=2,
minimalDaysInFirstWeek=1,ERA=1,YEAR=2024,MONTH=8,WEEK_OF_YEAR=38,WEEK_OF_MONTH=4,
DAY_OF_MONTH=22,DAY_OF_YEAR=266,DAY_OF_WEEK=1,DAY_OF_WEEK_IN_MONTH=4,AM_PM=1,HOUR=3,
HOUR_OF_DAY=15,MINUTE=24,SECOND=14,MILLISECOND=82,ZONE_OFFSET=28800000,DST_OFFSET=0]
上面的关键字都是可以使用Calendar.关键字获取
*/

int month = calendar.get(Calendar.MONTH);//月份从0开始算,九月为8
Date date1 = calendar.getTime();//获取日期对象
long time1 = calendar.getTimeInMillis();//获取时间毫秒值
calendar.set(Calendar.YEAR, 2016);//修改日历信息

JDK8新增的时间API

LocalDate、LocalTime、LocalDateTime

LocalDate:代表本地日期(年、月、日、星期)

LocalTime:代表本地时间(时、分、秒、纳秒)

LocalDateTime:代表本地日期、时间(年、月、日、星期、时、分、秒、纳秒)

1
2
3
4
5
//LocalDate、LocalTime和LocalDateTime互相转换
LocalDateTime ldt = LocalDateTime.now();
LocalDate ld = ldt.toLocalDate();
LocalTime lt = ldt.toLocalTime();
LocalDateTime ldt1 = LocalDateTime.of(ld, lt);

ZoneID、ZonedDateTime

1
2
3
4
5
ZoneId zone = ZoneId.systemDefault();//系统默认时区
ZonedDateTime zdt = ZonedDateTime.now(zone);//获取某个时区的ZonedDateTime对象
ZonedDateTime zdt1 = ZonedDateTime.now(Clock.systemUTC());//世界标准时间
ZonedDateTime zdt2 = ZonedDateTime.now();//系统默认时区的ZonedDateTime对象
Calendar calendar1 = Calendar.getInstance(TimeZone.getTimeZone(zone));//某个时区对应Calendar对象

Instant

通过获取Instant的对象可以拿到此刻的时间,该时间由两部分组成:从1970-01-01 00:00:00 开始走到此刻的总秒数 + 不够1秒的纳秒数

作用:可以用来记录代码的执行时间,或用于记录用户操作某个事件的时间点。

传统的Date类,只能精确到毫秒,并且是可变对象;新增的Instant类,可以精确到纳秒,并且是不可变对象,推荐用Instant代替Date

DateTimeFormatter

DateTimeFormatter是格式化器,用于时间的格式化、解析。和SimpleDateFormat相比,DateTimeFormatter是线程安全的。

1
2
3
4
5
6
7
8
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime ldt2 = LocalDateTime.now();
String rs = dtf.format(ldt2);//正向格式化
String rs1 = ldt2.format(dtf);//方向格式化

//解析时间:LocalDateTime.parse
String string = "2024-09-08 12:08:22";
LocalDateTime ldt3 = LocalDateTime.parse(string, dtf);

Period

用于计算两个LocalDate对象相差的年数、月数、天。

1
2
3
4
5
6
7
LocalDate d1 = LocalDate.of(2020, 10, 1);
LocalDate d2 = LocalDate.of(2024, 9, 26);
Period p = Period.between(d1, d2);
System.out.println(p.getYears());//3
System.out.println(p.getMonths());//11
System.out.println(p.getDays());//25
//总共差了3年11月25天

Duration

用于计算两个时间对象相差的天数、小时数、分数、秒数、纳秒数;支持LocalTimeLocalDateTimeInstant等时间。

1
2
3
4
5
6
7
8
9
10
11
12
LocalDateTime t1 = LocalDateTime.of(2024, 9, 25, 10, 10, 22);
LocalDateTime t2 = LocalDateTime.of(2024, 9, 26, 12, 8, 21);
Duration d = Duration.between(t1, t2);
System.out.println(d.toDays());

System.out.println("天:" + d.toDays());//seconds / SECONDS_PER_DAY
System.out.println("时:" + d.toHours());//seconds / SECONDS_PER_HOUR
System.out.println("分:" + d.toMinutes());//seconds / SECONDS_PER_MINUTE
System.out.println("秒:" + d.toSeconds());//seconds
//注意:天、小时、分、秒都是通过seconds(秒)进行换算的
System.out.println("毫秒:" + d.toMillis());
System.out.println("纳秒:" + d.toNanos());

Arrays

用来操作数组的一个工具类。

1
2
3
4
5
6
7
8
9
10
11
12
13
double[] arr = {10, 20, 30, 40, 50};
System.out.println(Arrays.toString(arr));//[10.0, 20.0, 30.0, 40.0, 50.0]

double[] arr1 = Arrays.copyOf(arr, 3);
double[] arr2 = Arrays.copyOfRange(arr, 1, 3);

Arrays.setAll(arr, new IntToDoubleFunction() {
@Override
public double applyAsDouble(int value) {
return arr[value] * 0.8;
}
});
System.out.println(Arrays.toString(arr));//[8.0, 16.0, 24.0, 32.0, 40.0]
1
2
3
4
5
6
//setAll方法的源码
public static void setAll(double[] array, IntToDoubleFunction generator) {
Objects.requireNonNull(generator);
for (int i = 0; i < array.length; i++)
array[i] = generator.applyAsDouble(i);
}

Arrays使用sort方法进行排序。使用Arrays对对象进行排序时,有两种方法:

1.让该对象的类实现Comparable(比较规则)接口,然后重写compareTo方法,自己来制定比较规则。

2.使用下面这个sort方法,创建Comparator比较器接口的匿名内部类对象,然后自己制定比较规则。

1
public static <T> void sort(T[] arr, Comparator<? super T> c) 	//对数组进行排序(支持自定义排序规则)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
//Student类
public class Student implements Comparable<Student>{
private String name;
private double height;
private int age;

@Override
public int compareTo(Student o) {//方法一:实现Comparable接口,重写compareTo方法
if(this.age > o.age) {return 1;}
else if(this.age < o.age) {return -1;}
return 0;//升序
//return this.age - o.age;//升序
//return o.age - this.age;//降序
}

public Student(){}
public Student(String name, double height, int age) {
this.name = name;
this.height = height;
this.age = age;
}

@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", height=" + height +
", age=" + age +
'}';
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public double getHeight() {
return height;
}

public void setHeight(double height) {
this.height = height;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Student[] student = new Student[3];
student[0] = new Student("srr1", 168.2, 18);
student[1] = new Student("srr2", 163.2, 16);
student[2] = new Student("srr3", 160.2, 19);

Arrays.sort(student);//方法一:Student类内部实现Comparable接口,重写compareTo方法
System.out.println(Arrays.toString(student));

Arrays.sort(student, new Comparator<Student>() {////方法二:创造Comparator比较器接口的匿名内部类对象
@Override
public int compare(Student o1, Student o2) {
//if(o1.getHeight() > o2.getHeight()) {return 1;}
//else if(o1.getHeight() < o2.getHeight()) {return -1;}
//return 0;//升序
return Double.compare(o1.getHeight(), o2.getHeight());//升序
//return Double.compare(o2.getHeight(), o1.getHeight());//降序
}
});
System.out.println(Arrays.toString(student));

Lambda表达式

Lambda表达式是JDK8开始新增的一种语法形式,用于简化匿名内部类的代码写法。

Lambda表达式只能简化函数式接口匿名内部类

函数式接口:有且仅有一个抽象方法的接口。

注意:大部分函数式接口,上面都可能会有一个@FunctionalInterface的注解,有该注解的接口就必定是函数式接口。

Lambda表达式的省略写法(进一步简化Lambda表达式的写法):

1.参数类型可以省略不写。

2.如果只有一个参数,参数类型可以省略,同时()也可以省略。

3.如果Lambda表达式中的方法体代码只有一行代码,可以省略大括号不写,同时要省略分号;。此时,如果这行代码是return语句,也必须去掉return不写。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Arrays.sort(student, new Comparator<Student>() {//原始写法
@Override
public int compare(Student o1, Student o2) {
//if(o1.getHeight() > o2.getHeight()) {return 1;}
//else if(o1.getHeight() < o2.getHeight()) {return -1;}
//return 0;//升序
return Double.compare(o1.getHeight(), o2.getHeight());//升序
//return Double.compare(o2.getHeight(), o1.getHeight());//降序
}
});

Arrays.sort(student, (Student o1, Student o2) -> {//Lambda表达式
return Double.compare(o2.getHeight(), o1.getHeight());
});

Arrays.sort(student, (o1, o2) -> Double.compare(o2.getHeight(), o1.getHeight()));//简化的Lambda表达式

方法引用

方法引用:进一步简化Lambda表达式,方法引用的标志性符号::

静态方法的引用

格式:类名::静态方法

如果某个Lambda表达式里只是调用一个静态方法,并且前后参数的形式一致,就可以使用静态方法引用。

1
2
3
4
5
6
7
8
9
public class CompareByData {
public static int compareByAge(Student o1, Student o2) {
return o1.getAge() - o2.getAge();
}

public int compareByAgeDesc(Student o1, Student o2) {//降序
return o2.getAge() - o1.getAge();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
Arrays.sort(student, new Comparator<Student>() {//原始写法
@Override
public int compare(Student o1, Student o2) {
return o1.getAge() - o2.getAge();//按照年龄升序排序
}
});

Arrays.sort(student, (o1, o2) -> o1.getAge() - o2.getAge() );//Lambda简化

Arrays.sort(student, (o1, o2) -> CompareByData.compareByAge(o1, o2));//调用CompareByData的静态方法

Arrays.sort(student, CompareByData::compareByAge );//静态方法引用
System.out.println(Arrays.toString(student));

实例方法的引用

格式:对象名::实例方法

如果某个Lambda表达式里只是调用一个实例方法,并且前后参数的形式一致,就可以使用实例方法引用。

1
2
3
4
5
6
//compareByAgeDesc是上述CompareByData类的实例方法
CompareByData compare = new CompareByData();
Arrays.sort(student, (o1, o2) -> compare.compareByAgeDesc(o1, o2));//调用CompareByData的实例方法

Arrays.sort(student, compare::compareByAgeDesc);//实例方法引用
System.out.println(Arrays.toString(student));

特定类型的方法引用

格式:类型::方法

如果某个Lambda表达式里只是调用一个实例方法,并且前面参数列表中的第一个参数是作为方法的主调,后面的所有参数都是作为该实例方法的入参的,则此时就可以使用特定类型的方法引用。

1
2
3
4
5
6
7
8
9
10
11
12
String[] names = {"srr", "Jack", "Lin", "Su", "irina", "Anna"};
Arrays.sort(names, new Comparator<String>() {//常规方法
@Override
public int compare(String o1, String o2) {
return o1.compareToIgnoreCase(o2);//忽略首字母大小写进行排序
}
});

Arrays.sort(names, (o1, o2) -> o1.compareToIgnoreCase(o2));//调用String类的compareToIgnoreCase方法

Arrays.sort(names, String::compareToIgnoreCase);//特点类型的方法引用
System.out.println(Arrays.toString(names));

构造器引用

格式:类名::new

如果某个Lambda表达式里只是在创建对象,并且前后参数情况一致,就可以使用构造器引用。(开发中用的少,了解就行)

1
2
3
4
5
6
7
8
9
10
public class Car {
private String name;
private double price;

public Car() {}
public Car(String name, double price) {
this.name = name;
this.price = price;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Test {
public static void main(String[] args){
CreateCar cc1 = new CreateCar() {//原始写法
@Override
public Car create(String name, double price) {
return new Car(name, price);
}
};
Car c = cc1.create("奔驰", 50);//再通过CreateCar接口的create得到Car,很鸡肋的用法,直接Car c = new ("奔驰", 50);就可以实现了

CreateCar cc2 = (name, price) -> new Car(name, price);//Lambda表达式
CreateCar cc3 = Car::new;//构造器引用
}
}

interface CreateCar{
Car create(String name, double price);
}

算法

排序

冒泡排序:每次从数组中找出最大值放在数组的后面去。

选择排序:每轮选择当前位置,开始找出后面的较小值与该位置交换

查找

二分查找Arrays.binarySearch

前提条件:数组中的数据必须是有序的

核心思想:每次排除一半的数据。

正则表达式

String提供了一个匹配正则表达式的方法:

1
public boolean matches(String regex)	//判断字符串是否匹配正则表达式,匹配返回true,不匹配返回false。

符号 含义 举例
? 0次或1次 \d?
* 0次或多次 \d* (abc)*
+ 1次或多次 \d+ (abc)+
{} 具体次数 a{7} \d{7,19}
(?i) 忽略后面字符的大小写 (?i)abc
a((?i)b)c 只忽略b的大小写 a((?i)b)c
[] 里面的内容出现一次 [abc]
^ 取反 [^abc]
&& 交集,不能写单个的& [a-z&&m-p]
. 任意字符 \n 回车符号不匹配
\ 转义字符 \d
\d 0-9 \d+
\D 非0-9 \D+
\s 空白字符
\S 非空白字符 [^\s]
\w 单词字符 [a-zA-Z_0-9]
\W 非单词字符 [^\w]
() 分组 a(bc)+
| 写在方括号外面表示并集 ab|AB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
//正则表达式实例代码
public class RegexTest2 {
public static void main(String[] args) {
// 1、字符类(只能匹配单个字符)
System.out.println("a".matches("[abc]")); // true [abc]只能匹配a、b、c
System.out.println("e".matches("[abcd]")); // false

System.out.println("d".matches("[^abc]")); // true [^abc] 不能是abc
System.out.println("a".matches("[^abc]")); // false

System.out.println("b".matches("[a-zA-Z]")); // true [a-zA-Z] 只能是a-z A-Z的字符
System.out.println("2".matches("[a-zA-Z]")); // false

System.out.println("k".matches("[a-z&&[^bc]]")); // true : a到z,除了b和c
System.out.println("b".matches("[a-z&&[^bc]]")); // false

System.out.println("ab".matches("[a-zA-Z0-9]")); // false 注意:以上带 [内容] 的规则都只能用于匹配单个字符

// 2、预定义字符(只能匹配单个字符) . \d \D \s \S \w \W
System.out.println("徐".matches(".")); // .可以匹配任意字符
System.out.println("徐徐".matches(".")); // false

// \转义
System.out.println("\"");
// \n \t
System.out.println("3".matches("\\d")); // true \d: 0-9
System.out.println("a".matches("\\d")); //false

System.out.println(" ".matches("\\s")); // true \s: 代表一个空白字符
System.out.println("a".matches("\s")); // false

System.out.println("a".matches("\\S")); // true \S: 代表一个非空白字符
System.out.println(" ".matches("\\S")); // false

System.out.println("a".matches("\\w")); // true \w: [a-zA-Z_0-9]
System.out.println("_".matches("\\w")); // true
System.out.println("徐".matches("\\w")); // false

System.out.println("徐".matches("\\W")); // true [^\w]不能是a-zA-Z_0-9
System.out.println("a".matches("\\W")); // false

System.out.println("23232".matches("\\d")); // false 注意:以上预定义字符都只能匹配单个字符。

// 3、数量词: ? * + {n} {n, } {n, m}
System.out.println("a".matches("\\w?")); // true ? 代表0次或1次
System.out.println("".matches("\\w?")); // true
System.out.println("abc".matches("\\w?")); // false

System.out.println("abc12".matches("\\w*")); // true * 代表0次或多次
System.out.println("".matches("\\w*")); // true
System.out.println("abc12张".matches("\\w*")); // false

System.out.println("abc12".matches("\\w+")); // true + 代表1次或多次
System.out.println("".matches("\\w+")); // false
System.out.println("abc12张".matches("\\w+")); // false

System.out.println("a3c".matches("\\w{3}")); // true {3} 代表要正好是n次
System.out.println("abcd".matches("\\w{3}")); // false
System.out.println("abcd".matches("\\w{3,}")); // true {3,} 代表是>=3次
System.out.println("ab".matches("\\w{3,}")); // false
System.out.println("abcde徐".matches("\\w{3,}")); // false
System.out.println("abc232d".matches("\\w{3,9}")); // true {3, 9} 代表是 大于等于3次,小于等于9次

// 4、其他几个常用的符号:(?i)忽略大小写 、 或:| 、 分组:()
System.out.println("abc".matches("(?i)abc")); // true
System.out.println("ABC".matches("(?i)abc")); // true
System.out.println("aBc".matches("a((?i)b)c")); // true
System.out.println("ABc".matches("a((?i)b)c")); // false

// 需求1:要求要么是3个小写字母,要么是3个数字。
System.out.println("abc".matches("[a-z]{3}|\\d{3}")); // true
System.out.println("ABC".matches("[a-z]{3}|\\d{3}")); // false
System.out.println("123".matches("[a-z]{3}|\\d{3}")); // true
System.out.println("A12".matches("[a-z]{3}|\\d{3}")); // false

// 需求2:必须是”我爱“开头,中间可以是至少一个”编程“,最后至少是1个”666“
System.out.println("我爱编程编程666666".matches("我爱(编程)+(666)+")); // true
System.out.println("我爱编程编程66666".matches("我爱(编程)+(666)+")); // false
}
}

案例:使用正则表达式查找一段文本中的内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class RegexTest4 {
public static void main(String[] args) {
method1();
}
// 需求1:从以下内容中爬取出,手机,邮箱,座机、400电话等信息。
public static void method1(){
String data = " 来黑马程序员学习Java,\n" +
" 电话:1866668888,18699997777\n" +
" 或者联系邮箱:boniu@itcast.cn,\n" +
" 座机电话:01036517895,010-98951256\n" +
" 邮箱:bozai@itcast.cn,\n" +
" 邮箱:dlei0009@163.com,\n" +
" 热线电话:400-618-9090 ,400-618-4000,4006184000,4006189090";
// 1、定义爬取规则
String regex = "(1[3-9]\\d{9})|(0\\d{2,7}-?[1-9]\\d{4,19})|(\\w{2,}@\\w{2,20}(\\.\\w{2,10}){1,2})"
+ "|(400-?\\d{3,7}-?\\d{3,7})";
// 2、把正则表达式封装成一个Pattern对象
Pattern pattern = Pattern.compile(regex);
// 3、通过pattern对象去获取查找内容的匹配器对象。
Matcher matcher = pattern.matcher(data);
// 4、定义一个循环开始爬取信息
while (matcher.find()){
String rs = matcher.group(); // 获取到了找到的内容了。
System.out.println(rs);
}
}
}

正则表达式用于搜索替换、分割内容,需要结合String提供的如下方法完成:

1
2
public String replaceAll(String regex , String newStr)	//按照正则表达式匹配的内容进行替换
public String[] split(String regex): //按照正则表达式匹配的内容进行分割字符串,反回一个字符串数组。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class RegexTest6 {
public static void main(String[] args) {
// 1、public String replaceAll(String regex , String newStr):按照正则表达式匹配的内容进行替换
// 需求1:请把 古力娜扎ai8888迪丽热巴999aa5566马尔扎哈fbbfsfs42425卡尔扎巴,中间的非中文字符替换成 “-”
String s1 = "古力娜扎ai8888迪丽热巴999aa5566马尔扎哈fbbfsfs42425卡尔扎巴";
System.out.println(s1.replaceAll("\\w+", "-"));//古力娜扎-迪丽热巴-马尔扎哈-卡尔扎巴

// 需求2(拓展):某语音系统,收到一个口吃的人说的“我我我喜欢编编编编编编编编编编编编程程程!”,需要优化成“我喜欢编程!”。
String s2 = "我我我喜欢编编编编编编编编编编编编程程程";
/**
* (.)一组:.匹配任意字符的。
* \\1 :为这个组声明一个组号:1号
* +:声明必须是重复的字
* $1可以去取到第1组代表的那个重复的字
*/
System.out.println(s2.replaceAll("(.)\\1+", "$1"));//我喜欢编程

// 2、public String[] split(String regex):按照正则表达式匹配的内容进行分割字符串,反回一个字符串数组。
// 需求1:请把 古力娜扎ai8888迪丽热巴999aa5566马尔扎哈fbbfsfs42425卡尔扎巴,中的人名获取出来。
String s3 = "古力娜扎ai8888迪丽热巴999aa5566马尔扎哈fbbfsfs42425卡尔扎巴";
String[] names = s3.split("\\w+");
System.out.println(Arrays.toString(names));//[古力娜扎, 迪丽热巴, 马尔扎哈, 卡尔扎巴]
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//爬取用户的名字
public class RegexTest7 {
public static void main(String[] args) {
String data = "欢迎张全蛋光临本系统!他删库并跑路,欢迎李二狗子光临本系统!" +
"欢迎马六子光临本系统!它浏览了很多好看的照片!欢迎夏洛光临本系统!他在六点钟购买了一台拖拉机!";
// 1、定义爬取规则
String regex = "欢迎(.+)光临"; // .+是贪婪匹配"
String regex2 = "欢迎(.+?)光临"; // .+?是非贪婪匹配
// 2、把正则表达式封装成一个Pattern对象
Pattern pattern = Pattern.compile(regex2);
// 3、通过pattern对象去获取查找内容的匹配器对象。
Matcher matcher = pattern.matcher(data);
// 4、定义一个循环开始爬取信息
while (matcher.find()) {
System.out.println(matcher.group()); // 获取到了找到的内容了。
System.out.println(matcher.group(1)); // 获取第一组内容(就是人的名字)
//group(0)指的整个串,group(1)指的是第一个括号里的东西,group(2)指的第二个括号里的东西。 以此类推
}
/*
欢迎张全蛋光临
张全蛋
欢迎李二狗子光临
李二狗子
欢迎马六子光临
马六子
欢迎夏洛光临
夏洛
*/
}
}

异常

Error:代表的系统级别错误(属于严重问题),也就是说系统一旦出现问题,sun公司会把这些问题封装成Error对象给出来,Error是给sun公司自己用的,不是给程序员用的,开发人员不用管它。

Exception:异常,代表程序可能出现的问题,程序员通常会用Exception以及它的子类来封装程序出现的问题。

运行时异常RuntimeException及其子类,编译阶段不会出现错误提醒,运行时出现的异常(如:数组索引越界异常)。

1
2
3
Integer.valueOf("abc");// 运行时异常:java.lang.NumberFormatException
int [] arr = {1, 2, 3};
System.out.println(arr[3]);// 运行时异常:java.lang.ArrayIndexOutOfBoundsException

编译时异常:编译阶段就会出现错误提醒的。(如:日期解析异常)。

1
2
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = sdf.parse("2024-9-18 12:28:22");//编译时异常:未运行时就会报错

编译时异常的解决方法

1.抛出异常(throws):在方法上使用throws关键字,可以将方法内部出现的异常抛出去给调用者处理。使用throws把异常抛给main方法,main方法不是最终调用者,main方法会把异常抛给JVM进行处理,JVM无法处理异常就会显示出错误。

1
2
3
4
5
6
public class Test {
public static void main(String[] args) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = sdf.parse("2024-9-18 12:28");
}
}

2.捕获异常(try…catch):直接捕获程序出现的异常。

1
2
3
4
5
6
7
8
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = sdf.parse("2024-9-18 12:28");
} catch (ParseException e) {
e.printStackTrace();
//throw new RuntimeException(e);
//上述两句都可以输出报错原因
}

自定义异常

自定义运行时异常
1
2
3
1.定义一个异常类继承RuntimeException
2.重写构造器。
3.通过throw new 异常类(xxx)来创建异常对象并抛出。

自定义运行时异常编译阶段不报错,提醒不强烈,运行时才可能出现。

1
2
3
4
5
6
7
8
//自定义运行时异常,该类必须继承自RuntimeException才能成为运行时异常
public class AgeIllegalRuntimeException extends RuntimeException {
public AgeIllegalRuntimeException() {}

public AgeIllegalRuntimeException(String message) {
super(message);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class Test {
public static void main(String[] args){
try {
checkAge(188);
System.out.println("执行成功");
} catch (Exception e) {
e.printStackTrace();
System.out.println("执行失败");
}
}

public static void checkAge(int age){
if(age > 0 && age < 150){
System.out.println("年龄合法" + age);
}else {
//用一个异常对象封装这个问题
//throw 抛出去这个异常对象
throw new AgeIllegalRuntimeException("/age is illegal, your age is " + age);
}
}
}
/*运行结果:
com.itheima.Exception_.AgeIllegalRuntimeException: /age is illegal, your age is 188
at com.itheima.Exception_.Test.checkAge(Test.java:33)
at com.itheima.Exception_.Test.main(Test.java:18)
执行失败
*/
自定义编译时异常
1
2
3
1.定义一个异常类继承Exception
2.重写构造器。
3.通过throw new 异常类(xxx)来创建异常对象并抛出。

throw抛出去异常对象。

throws用在方法上,抛出方法内部的异常。

自定义编译时异常编译阶段就报错,提醒更加强烈。

1
2
3
4
5
6
7
8
//自定义编译时异常,该类必须继承自Exception才能成为编译时异常
public class AgeIllegalException extends Exception {
public AgeIllegalException() {}

public AgeIllegalException(String message) {
super(message);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class Test {
public static void main(String[] args){
try {
checkAge2(188);
System.out.println("执行成功");
} catch (AgeIllegalException e) {
e.printStackTrace();
System.out.println("执行失败");
}
}

public static void checkAge2(int age) throws AgeIllegalException{
//需要throws抛出代码内部异常才不会报错,抛出的异常会抛给上层调用者
if(age > 0 && age < 150){
System.out.println("年龄合法" + age);
}else {
//用一个异常对象封装这个问题
//throw 抛出去这个异常对象
//throws 用在方法上,抛出方法内部的异常
throw new AgeIllegalException("/age is illegal, your age is " + age);
}
}
}
/*运行结果:
com.itheima.Exception_.AgeIllegalException: /age is illegal, your age is 188
at com.itheima.Exception_.Test.checkAge2(Test.java:54)
at com.itheima.Exception_.Test.main(Test.java:26)
*/

注意:异常使用try…catch进行处理后,还能继续往下进行。

异常的处理

1.捕获异常,记录异常并响应合适的信息给用户。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class Test2 {
public static void main(String[] args) {
try {
test1();
} catch (ParseException e) {
e.printStackTrace();
System.out.println("解析的世界格式有问题");
} catch (FileNotFoundException e) {
e.printStackTrace();
System.out.println("文件不存在");
}
//若test1()和test()均改为throws Exception,则可以改为如下形式:
try {
test1();
} catch (Exception e) {
e.printStackTrace();
System.out.println("操作有误");
}
}


public static void test1() throws ParseException, FileNotFoundException {
//因为Exception是所有异常的父类,所以可以改为throws Exception即可
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = sdf.parse("2025-9-10 13:14:22");
System.out.println(d);
test2();
}

public static void test2() throws FileNotFoundException {//或:throws Exception
InputStream is = new FileInputStream("D:/image.png");
}
}

2.捕获异常,尝试重新修复。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Test3 {
public static void main(String[] args) {
while (true) {
try {
getMoney();//如果遇到不合法输入则会抛出异常,catch捕获后会继续往下执行
break;
} catch (Exception e) {
System.out.println("输入价格有误");
}
}
}

public static double getMoney(){
Scanner sc = new Scanner(System.in);
while(true){
System.out.println("请输入合法的价格:");
double money = sc.nextDouble();//可能会有不合法输入,如abc,则会抛出异常
if(money >= 0){
return money;
}else{
System.out.println("输入价格有误");
}
}
}
}

Java常用API
http://surourou8.github.io/2024/09/22/Java常用API/
作者
Su Rourou
发布于
2024年9月22日
许可协议