十、常用API
不要重复造轮子
1. Object类
Java中所有类的对象都可以直接使用Object类中提供的一些方法。
常见方法:
public String toString()——返回对象的字符串表示形式
作用: 返回对象的字符串形式
意义: 让子类重写,以便返回子类对象的内容
public boolean equals(Object o)——判断两个对象是否相等
作用: 判断两个对象的地址是否相同
意义: 让子类重写,以便比较两个对象的内容是否相同
protected Object clone()——对象克隆
作用: 当某个对象调用这个方法时,这个方法会复制一个一摸一样的新对象返回
2. Objects类——工具类,有很多操作对象的静态方法以供使用,static实用 程序方法
常见方法:
public static boolean equals(Object a, Object b)——先做非空判断,再比较两个对象,内部做了非空校验
public static boolean isNull(Object obj)——判断对象是否为null,为null返回true
public static boolean nonNull(Object obj)——判断对象是否不为null,不为null返回true
public class Test {
public static void main(String[] args) {
String s1 = null;
String s2 = "itheima";
// System.out.println(s1.equals(s2)); // 会报空指针错误,调用不了了
System.out.println(s2.equals(s1)); // false
System.out.println(Objects.equals(s1, s2)); // false
System.out.println(Objects.isNull(s1)); // true
System.out.println(Objects.isNull(s2)); // false
System.out.println(Objects.nonNull(s1)); // false
System.out.println(Objects.nonNull(s2)); // true
}
}
3. 包装类
把基本类型的数据包装成对象
泛型和集合中不支持基本数据类型,只支持引用数据类型。
数转字符串:包装类.toString(str)
字符串转数:包装类.valueOf(num)
public class Test {
public static void main(String[] args) {
// Integer a1 = new Integer(12); // 已过时
Integer a2 = Integer.valueOf(12);
System.out.println(a2);
// 自动装箱机制:把基本类型的数据转换成对象
Integer a3 = 12;
// 自动拆箱:自动把包装类型的对象转换成对应的基本数据类型
int a4 = a3;
// 方法
// 1. 把基本类型的数据转换成字符串
Integer a = 23;
String rs1 = Integer.toString(a);
System.out.println(rs1 + 4); // 234
String rs2 = Objects.toString(23);
System.out.println(rs2 + 1); // 231
// 更优雅的做法
String rs3 = a + "";
System.out.println(rs3 + 6); // 236
// 2. 把字符串类型的数值转换成对应的基本类型——重要
String ageStr = "29";
// int age = Integer.parseInt(ageStr);
int age = Integer.valueOf(ageStr);
System.out.println(age + 1); // 30
}
}
4. StringBuilder
可变的字符序列,字符串拼接、修改等(用来操作字符串的)
StringBuilder比String更适合做字符串的修改
常用方法:
- 构造器:
- public StringBuilder()
- public StringBuilder(String str)
- 方法:
- public StringBulider append(任意类型):添加数据并返回对象本身
- public StringBulider reverse():将对象的内容反转
- public int length():返回对象类型的长度
- public String toString():把StringBuilder转换为String
public class Test {
public static void main(String[] args) {
StringBuilder s = new StringBuilder();
StringBuilder s1 = new StringBuilder("itheima");
// 1. 拼接操作
s1.append("黑马");
s1.append('a');
s1.append(888);
System.out.println(s1);
// 2. 反转操作
s1.reverse();
System.out.println(s1);
// 3. 返回对象长度
System.out.println(s1.length());
// 4. 返回String类型的变量
String s2 = s1.toString();
System.out.println(s2);
}
}
为什么操作字符串建议使用StringBuilder,而不是String?
- String频繁拼接、修改使用StringBuilder,效率更高
- 但是定义一些字符串变量的情况,String效率更高
5. StringBuffer
与StringBuilder用法一样,但是StringBuilder线程是不安全的,StringBuffer线程是安全的
6. StringJoiner
原因: 拼接操作String太慢,StringBuilder太麻烦。
概念: 同上,但JDK8开始才有的
好处: 代码高效简洁
public class Test3 {
public static void main(String[] args) {
// 只有间隔符的构造器
StringJoiner s = new StringJoiner(",");
s.add("java1");
s.add("java2");
s.add("java3");
System.out.println(s); //java1,java2,java3
// 有间隔符、开始符号、结束符号的有参构造器
StringJoiner s1 = new StringJoiner(",", "[", "]");
s1.add("y");
s1.add("x");
s1.add("g");
System.out.println(s1.length()); // 7
String s2 = s1.toString();
System.out.println(s2); //[y,x,g]
// 调用方法
System.out.println(getArrayData(new int[]{1, 2, 3}));
}
public static String getArrayData(int[] arr) {
// 1. 判断arr是否为null
if (arr == null) {
return null;
}
StringJoiner ss = new StringJoiner(",", "[", "]");
for (int i = 0; i < arr.length; i++) {
ss.add(arr[i] + "");
}
return ss.toString();
}
}
7. Math
数学工具类,对数据进行操作的静态方法
public class MathTest {
public static void main(String[] args) {
// abs()得到绝对值
System.out.println(Math.abs(-12.3));
System.out.println(Math.abs(1));
// 向上取整
System.out.println(Math.ceil(1.0)); // 1.0
System.out.println(Math.ceil(1.00000001)); // 2.0
// 向下取整
System.out.println(Math.floor(4.9999)); // 4.0
System.out.println(Math.floor(4.0000)); // 4.0
// 四舍五入
System.out.println(Math.round(3.49999)); // 3
System.out.println(Math.round(3.50000)); // 4
// 取最值
System.out.println(Math.max(10, 20)); // 20
System.out.println(Math.min(10, 20)); // 10
// 取次方
System.out.println(Math.pow(2, 3)); // 8.0
// 取随机数,[0.0, 1.0)
System.out.println(Math.random()); // 0.805434885364831
}
}
8. System
代表程序所在的系统,也是一个工具类
public class SystemTest {
public static void main(String[] args) {
// 终止当前运行的Java虚拟机
// System.exit(0);
System.out.println("--");
// 获取当前系统的时间,从1970年1月1日 0:0:0开始计算——前后计算差得到程序运行时间,程序性能分析
long time = System.currentTimeMillis();
System.out.println(time);
}
}
9. Runtime
Java程序所在的运行环境
单例类:对外只需要一个对象
public class RuntimeTest {
public static void main(String[] args) throws IOException, InterruptedException {
// 得到运行时对象
Runtime r = Runtime.getRuntime();
// 终止当前运行的虚拟机,该参数用作状态代码。非零状态表示异常终止
// r.exit(0);
// 获取虚拟机能够使用的处理器数
System.out.println(r.availableProcessors()); // 12
// 获取虚拟机的内存总数,long字节
System.out.println(r.totalMemory());
// 返回Java虚拟机中的可用内存量
System.out.println(r.freeMemory());
// 启动某个程序,并返回代表该程序的对象
Process p = r.exec("D:\\Zhiyun\\ZhiyunTranslator\\ZhiYunTranslator.exe");
Thread.sleep(5000);
p.destroy();
}
}
10. BigDecimal
开发中经常遇到,要掌握
概念: 解决浮点运算时,会出现结果失真
public class BigDecimalDemo1 {
public static void main(String[] args) {
// 浮点数运算失真,不是每种情况下都会失真??why
// double a = 0.1;
// double b = 0.3;
// double c = a + b;
// System.out.println(c); // 0.4
double a = 0.1;
double b = 0.2;
double c = a + b;
System.out.println(c); // 0.30000000000000004
// 解决失真问题
// 1. 先变成字符串,再封装成BigDecimal对象
// BigDecimal a1 = new BigDecimal(Double.toString(a));
// BigDecimal b1 = new BigDecimal(Double.toString(b));
BigDecimal a1 = BigDecimal.valueOf(a); // 相当于上一行代码的封装
BigDecimal b1 = BigDecimal.valueOf(b);
// // 计算+
// BigDecimal c1 = a1.add(b1);
// System.out.println(c1); // 0.3
// // 计算-
// BigDecimal c1 = a1.subtract(b1);
// System.out.println(c1); // -0.1
// // 计算*
// BigDecimal c1 = a1.multiply(b1);
// System.out.println(c1); // 0.02
// 计算/
BigDecimal c1 = a1.divide(b1);
System.out.println(c1); // 0.5
// 除不尽的情况
BigDecimal i = BigDecimal.valueOf(0.1);
BigDecimal j = BigDecimal.valueOf(0.3);
// BigDecimal k = i.divide(j); //Non-terminating decimal expansion; no exact representable decimal result.
// BigDecimal k = i.divide(j, 2); // 默认是向上取保留一位小数
BigDecimal k = i.divide(j, 2, RoundingMode.HALF_UP); // 四舍五入
System.out.println(k);
// 把BigDecimal转换成double
double rs = k.doubleValue();
System.out.println(rs);
}
}
11. 传统时间
11.1 Date
系统当前的日期和时间
public class Test1Date {
public static void main(String[] args) {
// 创建一个Date的对象,代表当前系统时间信息
Date d = new Date();
System.out.println(d);
// 拿到时间毫秒值
long time = d.getTime();
System.out.println(time);
// 把时间毫秒值转化为日期对象
time += 2 * 1000;
Date d2 = new Date(time);
System.out.println(d2);
// 直接把日期对象的时间通过setTime方法进行修改
Date d3 = new Date();
d3.setTime(time);
System.out.println(d3);
}
}
11.2 SimpleDateFormat
把得到的时间格式化成用户喜欢的形式
public class Test2SimpleDateFormat {
public static void main(String[] args) throws ParseException {
// 1. 准备一些时间
Date d = new Date();
System.out.println(d);
long time = d.getTime();
System.out.println(time);
// 2. 格式化日期对象——前端展示
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss EEE a");
String rs1 = sdf.format(d);
String rs2 = sdf.format(time);
System.out.println(rs1);
System.out.println(rs2);
// 3. 把字符串时间解析成日期对象——后端分析
String dateStr = "2022-12-12 12:12:12";
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d2 = sdf2.parse(dateStr); // 时间格式
System.out.println(d2);
long time2 = da.getTime(); // 时间毫秒值
}
}
11.3 Calender
代表的是系统此刻时间对应的日历
可以单独获取、修改时间中的年、月、日、时、分、秒
Calendar时一个抽象类,但是提供了获取日历对象的方法
public class Test4Calendar {
public static void main(String[] args) {
// 1. 得到系统此刻时间对应的日历对象
Calendar now = Calendar.getInstance(); // 返回的是Calendar子类的实例
System.out.println(now); // 月份是从0开始计算的,要想得到现在的月份,要+1
// 2. 获取日历中的某个信息
int year = now.get(Calendar.YEAR);
System.out.println(year);
// 3.拿到日历中记录的日期对象
Date d = now.getTime();
System.out.println(d);
// 4. 拿到时间毫秒值
long time = now.getTimeInMillis();
System.out.println(time);
// 5. 修改日历中的某个信息
now.set(Calendar.DAY_OF_YEAR, 100); // 修改月份为10月份
System.out.println(now);
}
}
问题:修改了之后其他参数没变,按道理应该会发生相应的变化????
12. JDK8新增的日期、时间
区别:
JDK8之前:
- 设计不合理、使用不方便、很多被淘汰
- 都是可变对象,修改后会丢失最开始的时间信息
- 线程不安全
- 只能精确到毫秒
JDK8之后:
- 设计更合理、功能丰富、使用更方便
- 都是不可变对象,修改后返回新的时间对象,不会丢失最开始的时间
- 线程安全
- 能精确到毫秒、纳秒
代替Calendar
12.1 LocalDate:年、月、日
12.2 LocalTime:时、分、秒
12.3 LocalDateTime:年、月、日 时、分、秒
- public LocalDate toLocalDate()
- public LocalTime toLocalTime()
- public static LocalDateTime of(LocalDate date, LocalTime time)
类名 对象名 = 类名.now()——>得到对象
LocalDate
public class Test1_LocalDate {
public static void main(String[] args) {
LocalDate ld = LocalDate.now();
System.out.println(ld);
// 获取日期对象中的信息 get开头
int year = ld.getYear(); // 年
int mouth = ld.getMonthValue(); // 月1-12
int day = ld.getDayOfMonth(); // 日
int dayOfYear = ld.getDayOfYear(); // 一年中的第几天
int dayOfWeek = ld.getDayOfWeek().getValue(); // 星期几
// 修改某个信息 with开头
LocalDate ld2 = LocalDate.now();
ld2 = ld.withYear(2099);
System.out.println(ld); // 2023-12-12
System.out.println(ld2); // 2099-12-12
// 把某个信息加多少 plus开头
LocalDate ld3 = LocalDate.now();
ld3 = ld2.plusMonths(1);
// 把某个信息减多少 minus开头
// 获取指定日期的LocalDate对象 public static LocalDate of(int year, int month, int dayOfMonth)
LocalDate ld4 = LocalDate.of(2099, 12, 13);
System.out.println(ld4);
// 判断两个日期对象是否相等,在前还是在后:equals、isBefore、isAfter
System.out.println(ld.equals(ld2));
}
}
12.4 ZoneId:时区
ZoneId:代表时区ID
世界标准时间(UTC)
中国标准时间:UTC+8
类型:
洲名/城市名:Asia/Shanghai
国家名/城市名:Americal/New_York
ZoneId是一个抽象类,调用ZoneId.systemDefault();
12.5 ZonedDateTime:带时区的时间
import java.time.Clock;
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class Test4_ZoneId_ZoneIDDateTime {
public static void main(String[] args) {
// 获取系统默认时区
ZoneId zoneId = ZoneId.systemDefault();
System.out.println(zoneId);
System.out.println(zoneId.getId());
// Java支持的全部时区ID——类方法
System.out.println(ZoneId.getAvailableZoneIds());
// 把某个时区ID封装成ZoneID对象
ZoneId zoneId1 = ZoneId.of("America/New_York");
// 获取带时区的时间
ZonedDateTime now = ZonedDateTime.now(zoneId1);
System.out.println(now);
// 获得UTC
ZonedDateTime now1 = ZonedDateTime.now(Clock.systemUTC());
System.out.println(now1);
// 获得系统默认时区的时间
ZonedDateTime now2 = ZonedDateTime.now();
System.out.println(now2);
}
}
代替Date
12.6 Instant:时间戳/时间线
代替SimpleDateFormat
可以精确到纳秒级。可以用来记录代码的执行时间,或者用于记录用户操作某个事件的时间点。
public class Test5_Instant {
public static void main(String[] args) {
// 创建
Instant now = Instant.now();
System.out.println(now);
// 获取总秒数
long second = now.getEpochSecond();
System.out.println(second);
// 获取不够1秒的纳秒数
int nano = now.getNano();
System.out.println(nano);
}
}
12.7 DateTimeFormatter:用于时间的格式化和解析
其他补充SimpleDateFormat线程不安全
public class Test_DateTimeFormatter {
public static void main(String[] args) {
// 创建一个日期时间格式化器对象
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
// 对时间进行格式化
LocalDateTime now = LocalDateTime.now();
System.out.println(now);
String rs = formatter.format(now);
System.out.println(rs);
}
}
12.8 Duration:时间间隔(时、分、秒、纳秒)
public class Test {
public static void main(String[] args) {
LocalDateTime start = LocalDateTime.of(2025, 11, 11, 11, 10, 10);
LocalDateTime end = LocalDateTime.of(2025, 11, 11, 11, 11, 11);
// 得到Duration对象
Duration duration = Duration.between(start,end);
// 获取间隔信息
System.out.println(duration.toDays());
System.out.println(duration.toHours());
}
}
12.9 Period:时间间隔(年、月、日)
倒计时相关的需求
计算两个LocalDate对象相差的年数、月数、天数
public class Test8_Duration {
public static void main(String[] args) {
LocalDate start = LocalDate.of(2029, 8, 10);
LocalDate end = LocalDate.of(2029, 8, 15);
// 创建Period对象,封装两个日期对象
Period period = Period.between(start, end);
// 获取时间差
System.out.println(period.getYears());
System.out.println(period.getMonths());
System.out.println(period.getDays());
}
}
13. Arrays类
概念: 用来操作数组的工具类
public class ArraysTest1 {
public static void main(String[] args) {
// toString()返回数组的内容
int[] arr = {10, 20, 30, 40, 50};
System.out.println(Arrays.toString(arr));
// copyOfRange(数组, 起始索引,结束索引)——包前不包后
int[] arr1 = Arrays.copyOfRange(arr, 0, 3);
System.out.println(Arrays.toString(arr1));
// copyOf(数组, 新数组的长度),长度可以比新数组长,也可以比新数组短
int[] arr2 = Arrays.copyOf(arr, 10);
System.out.println(Arrays.toString(arr2));
// 把数组中的元数据改为新数据又存进去setAll(double[] array, IntToDoubleFunction generator)
double[] prices = {99.8, 128, 100};
Arrays.setAll(prices, new IntToDoubleFunction() {
@Override
public double applyAsDouble(int value) {
return prices[value] * 0.8;
}
});
System.out.println(Arrays.toString(prices));
// 对数组进行排序(默认是升序排序)
Arrays.sort(prices);
System.out.println(Arrays.toString(prices));
}
}
如果数组中存储的是对象,应该如何进行排序?
在类中使用Comparable接口,重写compareTo()方法
public static void sort(T[] arr, Comparator<? duper T> c)
自定义排序规则时,需要遵循的官方约定:
- 如果认为左边对象 大于 右边对象 应该返回正整数
- 如果认为左边对象 小于 右边对象 应该返回负整数
- 如果认为左边对象 等于 右边对象 应该返回0整数
14. 正则表达式
概念: 由一些特定的字符组成,代表的是一个规则——更简单,更便捷
作用:
- 用来校验数据格式是否合法
- 在一段文本中查找满足要求的内容
- 用于搜索替换、分割内容
案例:
public class RegexTest1 {
public static void main(String[] args) {
// 需求:校验QQ号码是否正确,要求全部都是数字,长度是6-20之间,不能以0开头
System.out.println(check(null));
System.out.println(check("28256"));
System.out.println(check("2825625257"));
System.out.println(check("02825625257"));
System.out.println(check("a2825625257"));
}
public static boolean check(String qq) {
return qq != null && qq.matches("[1-9]\\d{5,19}");
}
}
String匹配正则表达式的规则:
[内容]——只能用于匹配单个字符
.——可以匹配任意字符
在Java中,\由特殊用途,会把后面的一起当整体看,所以如果是\,转义回去
\\d
(?i)——忽略大小写:“abc”.matches(“(?i)abc”)
|——或
()——分组:括号内的内容出现一次或两次,可以加数量词
利用正则表达式查找内容:
- 定义爬取规则,String类型
- 把正则表达式封装成Pattern对象
- 通过Pattern对象获取查找内容的匹配器对象
- 用匹配器对象在数据中不断寻找
String regex = "(1[3-9]\ \d{9})|(\\w{2,}@\\w{2,20}(\ \.\\w{2,20}){1,2})"
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(data);
if (matcher.find()) {
String s = matcher.group();
}
利用正则表达式替换、分割内容:
public class RegexTest2 {
public static void main(String[] args) {
// 去掉字符串中重复的字
String s1 = "我我我喜喜喜喜欢编程程程程";
System.out.println(s1.replaceAll("(.)\\1+", "$1")); // 我喜欢编程
System.out.println(s1); // 我我我喜喜喜喜欢编程程程程
String s2 = "古力娜扎aa888马儿扎哈bb222迪丽热巴";
String[] s = s2.split("\\w+");
System.out.println(Arrays.toString(s));
}
}
15. 异常
异常就是代表程序出现的问题
异常的体系:
- 异常的祖宗类:Java.lang.Throwable
- 直接子类:
- Error——系统级别的错误,面向的是sun公司,不是面向程序员的
- Exception——异常,程序可能出现的问题,通常用Exception以及它的孩子来封装程序出现的问题
Exception分类:
- 运行时异常: 运行时才会出现的异常
- 编译时异常: 编译阶段就会出现错误提醒
public class ExceptionTest1 {
public static void main(String[] args) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// try {
Date d = sdf.parse("2020-11-22 10:12");
// } catch (ParseException e) {
// e.printStackTrace();
// }
}
}
自定义异常:
try——内部存放程序运行的代码
catch——可以输出信息,也可以进行修复操作
throws——不建议抛具体的异常,全部用Exception;运行时才抛出的异常不用throws
自己定义的异常类要继承RuntimeException
异常处理:
开发中处理方式:
- 捕获异常,记录异常并响应合适的信息给用户
- 捕获异常,尝试重新修复