Java 常用 API 与字符串、时间处理

本文系统整理 Java 常用 API 与字符串、日期时间处理知识,覆盖 MathSystem、包装类、BigDecimalArraysString.join()StringJoinerString.format()DateSimpleDateFormatLocalDateTimeDateTimeFormatterChronoUnit 等高频内容。文章通过使用场景、代码示例和常见坑说明,帮助读者理解这些工具类解决什么问题、什么时候该用,以及真实开发中如何正确使用。

第一章 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...
Java
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 的随机小数。生成整数范围时使用公式:

Text
(int) (Math.random() * 个数) + 起始值
Java
public class RandomDemo {
    public static void main(String[] args) {
        int number = (int) (Math.random() * 100) + 1;
        System.out.println(number); // 1 到 100
    }
}

实际开发中更推荐 ThreadLocalRandom,可读性更好:

Java
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 统计代码耗时

Java
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

Java
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]
    }
}

参数含义:

Java
System.arraycopy(源数组, 源数组起始索引, 目标数组, 目标数组起始索引, 拷贝个数);

注意类型兼容、索引合法、目标数组空间足够。


第二章 包装类

2.1 为什么需要包装类

基本类型不是对象,不能调用方法,也不能直接用于泛型。包装类就是把基本类型包装成对象。

基本类型包装类
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
charCharacter
booleanBoolean

常见用途:

  • 集合只能存对象,例如 List<Integer>
  • 包装类提供字符串转数字的方法。
  • 包装类可以表示 null,基本类型不可以。
Java
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 自动装箱与自动拆箱

Java
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

Java
public class UnboxNullDemo {
    public static void main(String[] args) {
        Integer count = null;
        // int result = count; // 自动拆箱时会调用 count.intValue()
    }
}

2.3 常用转换方法

Java
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);
    }
}

数字转字符串:

Java
String s1 = Integer.toString(100);
String s2 = String.valueOf(200);
String s3 = 300 + "";

2.4 Integer 缓存机制

Integer-128 到 127 之间的整数做了缓存。自动装箱时,范围内的值会复用对象。

Java
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 不适合精确计算

floatdouble 是二进制浮点数,很多十进制小数无法被精确表示。

Java
public class DoubleProblemDemo {
    public static void main(String[] args) {
        System.out.println(0.1 + 0.2); // 0.30000000000000004
    }
}

金额、税率、积分、库存单价等需要精确计算的场景,应使用 BigDecimal

3.2 正确创建 BigDecimal

推荐使用字符串创建:

Java
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

Java
BigDecimal value = new BigDecimal(0.1);

因为传入前的 0.1 已经是不精确的 double。也可以使用:

Java
BigDecimal value = BigDecimal.valueOf(0.1);

3.3 常用运算

Java
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 只比较数值大小。

Java
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 金额计算工具示例

Java
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 打印、排序、查找

Java
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 拷贝和填充

Java
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 对象数组排序

Java
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,不能添加或删除元素。

Java
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
    }
}

基本类型数组会被当成一个整体:

Java
int[] numbers = {1, 2, 3};
System.out.println(Arrays.asList(numbers).size()); // 1

第五章 字符串处理 API

5.1 String.join()

适合把多个字符串按固定分隔符拼起来,写法简洁,业务里很常见。

Java
String result1 = String.join(", ", "Java", "Spring", "MySQL");
System.out.println(result1); // Java, Spring, MySQL

也可以直接拼接集合中的字符串:

Java
import java.util.List;

List<String> names = List.of("张三", "李四", "王五");
String result2 = String.join(" | ", names);
System.out.println(result2); // 张三 | 李四 | 王五

5.2 StringJoiner

适合需要自定义前缀、后缀、分隔符的场景。

Java
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()

适合做模板化字符串拼接,让格式更清晰。

Java
String msg = String.format("用户 %s 的成绩是 %d 分", "小明", 95);
System.out.println(msg);

常见占位符:

  • %s:字符串
  • %d:整数
  • %f:浮点数

例如保留两位小数:

Java
String priceText = String.format("价格:%.2f 元", 19.986);
System.out.println(priceText); // 价格:19.99 元

5.4 formatted()

从较新的 JDK 版本开始,字符串对象本身也可以直接调用 formatted()。本项目推荐使用 JDK 17,因此这个方法是可用的。

Java
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 早期日期时间类,表示一个具体时间点,内部本质上保存毫秒值。

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 与毫秒值

Java
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
HH24 小时制小时
mm分钟
ss
SSS毫秒
Java
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 创建和获取字段

Java
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 不可变对象

Java
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

Java
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 修改指定字段

Java
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 判断时间先后

Java
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 活动结束时间示例

Java
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 中的格式化工具,线程安全,可以放心作为常量复用。

Java
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 用来计算两个时间之间相差多少年、月、日、小时、分钟、秒。

Java
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 订单超时判断示例

Java
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 看起来零散,其实都服务于日常开发中的基础数据处理:

  • MathSystem 解决数学计算、耗时统计、数组拷贝等问题。
  • 包装类解决基本类型和对象之间的转换问题。
  • BigDecimal 适合金额、积分、费率等精确计算。
  • Arrays 提供数组打印、排序、查找、拷贝、填充等能力。
  • 字符串处理 API 解决模板化输出、批量拼接和带边界的字符串组装问题。
  • 日期时间类解决时间表达、格式化、时间加减和时间差计算。

掌握这些内容后,你就能更熟练地处理计算、类型转换、数组操作、字符串拼接和时间逻辑,为后续 IO、集合、Web 开发打好基础。