Java 常用 API 与字符串、时间处理
本文系统整理 Java 常用 API 与字符串、日期时间处理知识,覆盖 Math、System、包装类、BigDecimal、Arrays、String.join()、StringJoiner、String.format()、Date、SimpleDateFormat、LocalDateTime、DateTimeFormatter 和 ChronoUnit 等高频内容。文章通过使用场景、代码示例和常见坑说明,帮助读者理解这些工具类解决什么问题、什么时候该用,以及真实开发中如何正确使用。
第一章 Math 类和 System 类
1.1 Math 类的定位
Math 是 Java 提供的数学工具类,位于 java.lang 包下,不需要手动导包。它不能创建对象,常用方法都是静态方法,所以直接用 Math.xxx() 调用。
常用方法:
| 方法 | 作用 | 示例 |
|---|---|---|
Math.abs(x) | 取绝对值 | Math.abs(-10) 得到 10 |
Math.ceil(x) | 向上取整 | Math.ceil(3.1) 得到 4.0 |
Math.floor(x) | 向下取整 | Math.floor(3.9) 得到 3.0 |
Math.round(x) | 四舍五入 | Math.round(3.5) 得到 4 |
Math.max(a, b) | 较大值 | Math.max(10, 20) 得到 20 |
Math.min(a, b) | 较小值 | Math.min(10, 20) 得到 10 |
Math.pow(a, b) | a 的 b 次方 | Math.pow(2, 3) 得到 8.0 |
Math.sqrt(x) | 平方根 | Math.sqrt(16) 得到 4.0 |
Math.random() | [0.0, 1.0) 随机小数 | 可能得到 0.382... |
public class MathDemo {
public static void main(String[] args) {
System.out.println(Math.abs(-18));
System.out.println(Math.ceil(3.14));
System.out.println(Math.floor(3.99));
System.out.println(Math.round(4.5));
System.out.println(Math.pow(2, 10));
System.out.println(Math.sqrt(81));
}
}
1.2 生成指定范围随机数
Math.random() 只能生成 0.0 <= x < 1.0 的随机小数。生成整数范围时使用公式:
(int) (Math.random() * 个数) + 起始值
public class RandomDemo {
public static void main(String[] args) {
int number = (int) (Math.random() * 100) + 1;
System.out.println(number); // 1 到 100
}
}
实际开发中更推荐 ThreadLocalRandom,可读性更好:
import java.util.concurrent.ThreadLocalRandom;
public class ThreadLocalRandomDemo {
public static void main(String[] args) {
int number = ThreadLocalRandom.current().nextInt(1, 101);
System.out.println(number);
}
}
1.3 System 类的定位
System 代表系统级工具,常用来打印、获取时间、数组拷贝、读取系统属性等。
| 成员 | 作用 |
|---|---|
System.out | 标准输出流 |
System.err | 标准错误输出流 |
System.in | 标准输入流 |
System.currentTimeMillis() | 当前时间毫秒值 |
System.nanoTime() | 高精度耗时统计 |
System.arraycopy(...) | 数组拷贝 |
System.exit(status) | 退出 JVM |
System.getProperty(key) | 获取系统属性 |
1.4 统计代码耗时
public class TimeMillisDemo {
public static void main(String[] args) {
long start = System.currentTimeMillis();
long sum = 0;
for (int i = 1; i <= 1000000; i++) {
sum += i;
}
long end = System.currentTimeMillis();
System.out.println("求和结果:" + sum);
System.out.println("耗时:" + (end - start) + " 毫秒");
}
}
currentTimeMillis() 适合获取时间戳;nanoTime() 适合统计代码耗时,两次结果相减才有意义。
1.5 System.arraycopy
import java.util.Arrays;
public class ArrayCopyDemo {
public static void main(String[] args) {
int[] source = {10, 20, 30, 40, 50};
int[] target = new int[5];
System.arraycopy(source, 1, target, 0, 3);
System.out.println(Arrays.toString(target)); // [20, 30, 40, 0, 0]
}
}
参数含义:
System.arraycopy(源数组, 源数组起始索引, 目标数组, 目标数组起始索引, 拷贝个数);
注意类型兼容、索引合法、目标数组空间足够。
第二章 包装类
2.1 为什么需要包装类
基本类型不是对象,不能调用方法,也不能直接用于泛型。包装类就是把基本类型包装成对象。
| 基本类型 | 包装类 |
|---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
常见用途:
- 集合只能存对象,例如
List<Integer>。 - 包装类提供字符串转数字的方法。
- 包装类可以表示
null,基本类型不可以。
import java.util.ArrayList;
import java.util.List;
public class WrapperNeedDemo {
public static void main(String[] args) {
List<Integer> scores = new ArrayList<>();
scores.add(95);
scores.add(88);
System.out.println(scores);
}
}
2.2 自动装箱与自动拆箱
public class BoxDemo {
public static void main(String[] args) {
Integer a = 100; // 自动装箱,等价于 Integer.valueOf(100)
int b = a; // 自动拆箱,等价于 a.intValue()
System.out.println(a);
System.out.println(b);
}
}
自动拆箱遇到 null 会抛出 NullPointerException:
public class UnboxNullDemo {
public static void main(String[] args) {
Integer count = null;
// int result = count; // 自动拆箱时会调用 count.intValue()
}
}
2.3 常用转换方法
public class ParseDemo {
public static void main(String[] args) {
int age = Integer.parseInt("18");
double price = Double.parseDouble("19.9");
boolean enabled = Boolean.parseBoolean("true");
System.out.println(age + 1);
System.out.println(price);
System.out.println(enabled);
}
}
数字转字符串:
String s1 = Integer.toString(100);
String s2 = String.valueOf(200);
String s3 = 300 + "";
2.4 Integer 缓存机制
Integer 对 -128 到 127 之间的整数做了缓存。自动装箱时,范围内的值会复用对象。
public class IntegerCacheDemo {
public static void main(String[] args) {
Integer a = 127;
Integer b = 127;
Integer c = 128;
Integer d = 128;
System.out.println(a == b); // true
System.out.println(c == d); // false
System.out.println(c.equals(d)); // true
}
}
结论:包装类比较数值,优先使用 equals 或拆成基本类型比较,不要依赖 ==。
第三章 BigDecimal 类
3.1 为什么 double 不适合精确计算
float 和 double 是二进制浮点数,很多十进制小数无法被精确表示。
public class DoubleProblemDemo {
public static void main(String[] args) {
System.out.println(0.1 + 0.2); // 0.30000000000000004
}
}
金额、税率、积分、库存单价等需要精确计算的场景,应使用 BigDecimal。
3.2 正确创建 BigDecimal
推荐使用字符串创建:
import java.math.BigDecimal;
public class BigDecimalCreateDemo {
public static void main(String[] args) {
BigDecimal a = new BigDecimal("0.1");
BigDecimal b = new BigDecimal("0.2");
System.out.println(a.add(b)); // 0.3
}
}
不要直接传入 double:
BigDecimal value = new BigDecimal(0.1);
因为传入前的 0.1 已经是不精确的 double。也可以使用:
BigDecimal value = BigDecimal.valueOf(0.1);
3.3 常用运算
import java.math.BigDecimal;
import java.math.RoundingMode;
public class BigDecimalCalculateDemo {
public static void main(String[] args) {
BigDecimal a = new BigDecimal("10.00");
BigDecimal b = new BigDecimal("3.00");
System.out.println(a.add(b));
System.out.println(a.subtract(b));
System.out.println(a.multiply(b));
System.out.println(a.divide(b, 2, RoundingMode.HALF_UP));
}
}
BigDecimal 是不可变对象,每次运算都会返回新对象。
3.4 比较和舍入
equals 会比较数值和小数位数,compareTo 只比较数值大小。
import java.math.BigDecimal;
public class BigDecimalCompareDemo {
public static void main(String[] args) {
BigDecimal a = new BigDecimal("1.0");
BigDecimal b = new BigDecimal("1.00");
System.out.println(a.equals(b)); // false
System.out.println(a.compareTo(b) == 0); // true
}
}
常用舍入模式:
| 模式 | 含义 |
|---|---|
RoundingMode.HALF_UP | 四舍五入,最常用 |
RoundingMode.UP | 远离 0 的方向进位 |
RoundingMode.DOWN | 靠近 0 的方向截断 |
RoundingMode.CEILING | 向正无穷方向取整 |
RoundingMode.FLOOR | 向负无穷方向取整 |
3.5 金额计算工具示例
import java.math.BigDecimal;
import java.math.RoundingMode;
public class MoneyUtils {
/**
* 计算商品总价,并按金额常见规则保留两位小数。
*
* @param price 商品单价,不能为 null
* @param count 商品数量
* @return 保留两位小数后的总价
*/
public static BigDecimal calculateTotal(BigDecimal price, int count) {
if (price == null) {
throw new IllegalArgumentException("商品单价不能为空");
}
if (count < 0) {
throw new IllegalArgumentException("商品数量不能为负数");
}
// 关键业务逻辑:金额计算统一在最后一步做舍入,避免中间过程过早丢失精度。
return price.multiply(BigDecimal.valueOf(count))
.setScale(2, RoundingMode.HALF_UP);
}
}
第四章 Arrays 数组工具类
4.1 Arrays 类的定位
Arrays 位于 java.util 包下,专门操作数组。数组本身只有长度和下标访问,打印、排序、查找、拷贝、比较等操作都可以交给 Arrays。
| 方法 | 作用 |
|---|---|
Arrays.toString(array) | 打印一维数组 |
Arrays.deepToString(array) | 打印多维数组 |
Arrays.sort(array) | 排序 |
Arrays.binarySearch(array, key) | 二分查找 |
Arrays.copyOf(array, newLength) | 拷贝并指定新长度 |
Arrays.copyOfRange(array, from, to) | 拷贝指定范围 |
Arrays.fill(array, value) | 填充数组 |
Arrays.equals(a, b) | 比较一维数组内容 |
Arrays.asList(array) | 数组转 List |
4.2 打印、排序、查找
import java.util.Arrays;
public class ArraysDemo {
public static void main(String[] args) {
int[] numbers = {5, 2, 9, 1, 3};
System.out.println(Arrays.toString(numbers));
Arrays.sort(numbers);
System.out.println(Arrays.toString(numbers));
System.out.println(Arrays.binarySearch(numbers, 3));
}
}
binarySearch 的前提是数组已经升序排序,否则结果没有意义。
4.3 拷贝和填充
import java.util.Arrays;
public class ArraysCopyDemo {
public static void main(String[] args) {
int[] oldArray = {10, 20, 30};
int[] newArray = Arrays.copyOf(oldArray, 5);
System.out.println(Arrays.toString(newArray)); // [10, 20, 30, 0, 0]
int[] rangeArray = Arrays.copyOfRange(oldArray, 1, 3);
System.out.println(Arrays.toString(rangeArray)); // [20, 30]
Arrays.fill(newArray, 99);
System.out.println(Arrays.toString(newArray));
}
}
4.4 对象数组排序
import java.util.Arrays;
import java.util.Comparator;
public class StudentSortDemo {
public static void main(String[] args) {
Student[] students = {
new Student("张三", 18),
new Student("李四", 20),
new Student("王五", 19)
};
Arrays.sort(students, Comparator.comparingInt(Student::getAge));
System.out.println(Arrays.toString(students));
}
}
class Student {
private final String name;
private final int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return name + ":" + age;
}
}
4.5 Arrays.asList 的坑
Arrays.asList 返回的是固定长度 List,不能添加或删除元素。
import java.util.Arrays;
import java.util.List;
public class AsListDemo {
public static void main(String[] args) {
List<String> names = Arrays.asList("张三", "李四", "王五");
names.set(0, "赵六");
System.out.println(names);
// names.add("小明"); // UnsupportedOperationException
}
}
基本类型数组会被当成一个整体:
int[] numbers = {1, 2, 3};
System.out.println(Arrays.asList(numbers).size()); // 1
第五章 字符串处理 API
5.1 String.join()
适合把多个字符串按固定分隔符拼起来,写法简洁,业务里很常见。
String result1 = String.join(", ", "Java", "Spring", "MySQL");
System.out.println(result1); // Java, Spring, MySQL
也可以直接拼接集合中的字符串:
import java.util.List;
List<String> names = List.of("张三", "李四", "王五");
String result2 = String.join(" | ", names);
System.out.println(result2); // 张三 | 李四 | 王五
5.2 StringJoiner
适合需要自定义前缀、后缀、分隔符的场景。
import java.util.StringJoiner;
StringJoiner joiner = new StringJoiner(", ", "[", "]");
joiner.add("张三");
joiner.add("李四");
joiner.add("王五");
System.out.println(joiner.toString()); // [张三, 李四, 王五]
如果你需要拼出带边界符号的结果,例如列表展示字符串、SQL 片段或 JSON 风格片段,StringJoiner 会比手动控制分隔符更方便。
5.3 String.format()
适合做模板化字符串拼接,让格式更清晰。
String msg = String.format("用户 %s 的成绩是 %d 分", "小明", 95);
System.out.println(msg);
常见占位符:
%s:字符串%d:整数%f:浮点数
例如保留两位小数:
String priceText = String.format("价格:%.2f 元", 19.986);
System.out.println(priceText); // 价格:19.99 元
5.4 formatted()
从较新的 JDK 版本开始,字符串对象本身也可以直接调用 formatted()。本项目推荐使用 JDK 17,因此这个方法是可用的。
String msg = "用户 %s 的成绩是 %d 分".formatted("小明", 95);
System.out.println(msg);
它和 String.format() 的作用很接近,但写法更自然,模板字符串在前面,可读性更好。
5.5 常见拼接方式怎么选
| 方式 | 是否常用 | 适用场景 | 说明 |
|---|---|---|---|
+ | 很常用 | 少量、临时拼接 | 写法最直接,业务代码里最常见 |
StringBuilder | 很常用 | 循环、批量、性能敏感场景 | 单线程下最常用的显式拼接工具 |
String.join() | 常用 | 按固定分隔符拼接多个字符串 | 简洁,适合列表展示 |
StringJoiner | 较常用 | 需要前缀、后缀、分隔符 | 比手动判断最后一个分隔符更省心 |
String.format() / formatted() | 常用 | 模板化输出、报表文案、提示信息 | 可读性好,但大量循环拼接不如 StringBuilder |
实际开发里可以这样记:
- 一两段简单文本,直接用
+。 for循环里持续追加,优先用StringBuilder。- 多个元素按分隔符拼接,优先考虑
String.join()。 - 需要前后缀时,优先考虑
StringJoiner。 - 需要模板化输出时,使用
String.format()或formatted()。 - 如果是日志输出,优先使用日志框架的
{}占位符,而不是手动字符串拼接。
第六章 Date 类和 SimpleDateFormat 类
6.1 Date 类
Date 是 Java 早期日期时间类,表示一个具体时间点,内部本质上保存毫秒值。
import java.util.Date;
public class DateDemo {
public static void main(String[] args) {
Date now = new Date();
Date start = new Date(0L);
System.out.println(now);
System.out.println(start);
System.out.println(now.getTime());
}
}
new Date(0L) 表示 1970-01-01 00:00:00 UTC。在中国时区显示时通常是 1970-01-01 08:00:00。
6.2 Date 与毫秒值
import java.util.Date;
public class DateTimeDemo {
public static void main(String[] args) {
Date date = new Date();
long time = date.getTime();
date.setTime(time + 24 * 60 * 60 * 1000L);
System.out.println(date);
}
}
Date 是可变对象,这也是它在复杂项目中不够安全的原因之一。
6.3 SimpleDateFormat
SimpleDateFormat 用来在 Date 和字符串之间转换。
常用模式:
| 字母 | 含义 |
|---|---|
yyyy | 年 |
MM | 月 |
dd | 日 |
HH | 24 小时制小时 |
mm | 分钟 |
ss | 秒 |
SSS | 毫秒 |
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class SimpleDateFormatDemo {
public static void main(String[] args) throws ParseException {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String text = format.format(new Date());
System.out.println(text);
Date date = format.parse("2026-05-14 21:30:00");
System.out.println(date);
}
}
SimpleDateFormat 线程不安全,现代项目里更推荐 java.time。
第七章 LocalDateTime 类
7.1 java.time 常用类型
JDK8 引入 java.time 包,新日期类大多不可变、线程安全。
| 类型 | 说明 |
|---|---|
LocalDate | 日期,例如 2026-05-14 |
LocalTime | 时间,例如 21:30:00 |
LocalDateTime | 日期加时间 |
Instant | 时间戳 |
ZoneId | 时区 |
ZonedDateTime | 带时区的日期时间 |
Duration | 时分秒间隔 |
Period | 年月日间隔 |
7.2 创建和获取字段
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
public class LocalDateTimeDemo {
public static void main(String[] args) {
LocalDate today = LocalDate.now();
LocalTime nowTime = LocalTime.now();
LocalDateTime now = LocalDateTime.now();
LocalDateTime custom = LocalDateTime.of(2026, 5, 14, 21, 30, 10);
System.out.println(today);
System.out.println(nowTime);
System.out.println(now);
System.out.println(custom.getYear());
System.out.println(custom.getMonthValue());
System.out.println(custom.getDayOfMonth());
System.out.println(custom.getHour());
}
}
7.3 不可变对象
import java.time.LocalDateTime;
public class ImmutableDateTimeDemo {
public static void main(String[] args) {
LocalDateTime now = LocalDateTime.now();
LocalDateTime nextWeek = now.plusWeeks(1);
System.out.println(now);
System.out.println(nextWeek);
}
}
plusWeeks 不会修改原对象,而是返回新对象。
第八章 修改时间相关的方法
8.1 plus 和 minus
import java.time.LocalDateTime;
public class PlusMinusDemo {
public static void main(String[] args) {
LocalDateTime now = LocalDateTime.of(2026, 5, 14, 21, 30);
System.out.println(now.plusYears(1));
System.out.println(now.plusMonths(2));
System.out.println(now.plusDays(10));
System.out.println(now.minusHours(3));
}
}
8.2 with 修改指定字段
import java.time.LocalDateTime;
public class WithDemo {
public static void main(String[] args) {
LocalDateTime now = LocalDateTime.of(2026, 5, 14, 21, 30);
LocalDateTime firstDay = now.withDayOfMonth(1);
LocalDateTime startOfDay = now.withHour(0).withMinute(0).withSecond(0).withNano(0);
System.out.println(firstDay);
System.out.println(startOfDay);
}
}
8.3 判断时间先后
import java.time.LocalDateTime;
public class CompareDateTimeDemo {
public static void main(String[] args) {
LocalDateTime start = LocalDateTime.of(2026, 5, 14, 9, 0);
LocalDateTime end = LocalDateTime.of(2026, 5, 14, 18, 0);
System.out.println(start.isBefore(end));
System.out.println(end.isAfter(start));
System.out.println(start.isEqual(end));
}
}
8.4 活动结束时间示例
import java.time.LocalDateTime;
public class ActivityTimeUtils {
/**
* 根据活动开始时间和持续天数计算活动结束时间。
*
* @param start 活动开始时间,不能为 null
* @param days 持续天数,必须大于 0
* @return 活动结束时间
*/
public static LocalDateTime calculateEndTime(LocalDateTime start, int days) {
if (start == null) {
throw new IllegalArgumentException("活动开始时间不能为空");
}
if (days <= 0) {
throw new IllegalArgumentException("持续天数必须大于 0");
}
// 关键业务逻辑:活动持续 N 天时,结束时间按开始时间向后推 N 天计算。
return start.plusDays(days);
}
}
第九章 DateTimeFormatter 类和 ChronoUnit 类
9.1 DateTimeFormatter
DateTimeFormatter 是新日期 API 中的格式化工具,线程安全,可以放心作为常量复用。
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class DateTimeFormatterDemo {
public static void main(String[] args) {
LocalDateTime now = LocalDateTime.of(2026, 5, 14, 21, 30, 10);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String text = now.format(formatter);
LocalDateTime parsed = LocalDateTime.parse(text, formatter);
System.out.println(text);
System.out.println(parsed);
}
}
9.2 ChronoUnit
ChronoUnit 用来计算两个时间之间相差多少年、月、日、小时、分钟、秒。
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
public class ChronoUnitDemo {
public static void main(String[] args) {
LocalDateTime start = LocalDateTime.of(2026, 5, 1, 8, 0);
LocalDateTime end = LocalDateTime.of(2026, 5, 14, 21, 30);
System.out.println(ChronoUnit.DAYS.between(start, end));
System.out.println(ChronoUnit.HOURS.between(start, end));
System.out.println(ChronoUnit.MINUTES.between(start, end));
}
}
9.3 订单超时判断示例
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
public class OrderTimeoutUtils {
/**
* 判断订单是否已经超过指定分钟数未支付。
*
* @param createTime 订单创建时间,不能为 null
* @param currentTime 当前时间,不能为 null
* @param timeoutMinutes 超时时长,单位分钟
* @return 已超时返回 true,否则返回 false
*/
public static boolean isPaymentTimeout(LocalDateTime createTime, LocalDateTime currentTime, long timeoutMinutes) {
if (createTime == null || currentTime == null) {
throw new IllegalArgumentException("时间参数不能为空");
}
if (timeoutMinutes <= 0) {
throw new IllegalArgumentException("超时时长必须大于 0");
}
long minutes = ChronoUnit.MINUTES.between(createTime, currentTime);
return minutes >= timeoutMinutes;
}
}
总结
常用 API 看起来零散,其实都服务于日常开发中的基础数据处理:
Math和System解决数学计算、耗时统计、数组拷贝等问题。- 包装类解决基本类型和对象之间的转换问题。
BigDecimal适合金额、积分、费率等精确计算。Arrays提供数组打印、排序、查找、拷贝、填充等能力。- 字符串处理 API 解决模板化输出、批量拼接和带边界的字符串组装问题。
- 日期时间类解决时间表达、格式化、时间加减和时间差计算。
掌握这些内容后,你就能更熟练地处理计算、类型转换、数组操作、字符串拼接和时间逻辑,为后续 IO、集合、Web 开发打好基础。