背景

本文是《Java 后端从小白到大神》修仙系列第十四篇,正式进入Java后端世界,本篇文章主要聊Java基础。若想详细学习请点击首篇博文,我们开始吧。

文章概览

  1. Arrays 类 - 数组操作工具
  2. Collections 类 - 集合操作工具
  3. Objects 类 - 对象安全操作
  4. Files/Paths 类 - NIO 文件操作
  5. Math 类 - 数学计算工具
  6. Stream API - 函数式数据处理
  7. StringUtils - Apache 字符串工具

一、Arrays 类

1.1 核心定位

Arrays 是 Java 提供的数组工具类,包含操作数组的静态方法。理解其内部实现有助于写出高性能代码。

1.2 常用方法详解

方法 时间复杂度 空间复杂度 核心用途
sort() O(n log n) O(log n) 双轴快排(基本类型)/ TimSort(对象)
binarySearch() O(log n) O(1) 二分查找(需先排序)
copyOf() O(n) O(n) 数组扩容/缩容
fill() O(n) O(1) 批量填充默认值
equals() O(n) O(1) 深度比较数组内容
asList() O(1) O(1) 数组转固定大小 List

1.3 代码示例与原理分析

  1. 数组排序
1
2
3
int[] arr = {5, 3, 1, 4, 2};
Arrays.sort(arr); // 升序排序
// 结果:[1, 2, 3, 4, 5]
  1. 二分查找(必须先排序)
1
2
3
4
5
int[] arr = {1, 2, 3, 4, 5};
int index = Arrays.binarySearch(arr, 4);    // 找到:返回下标 3
// 返回 = -(插入点) - 1
// 现在要找 6,它应该插入在最后面,插入点下标是 5,所以返回 -6
int notFound = Arrays.binarySearch(arr, 6); // 未找到:返回负数 -6
  1. 数组拷贝
1
2
3
4
5
int[] arr = {1, 2, 3, 4, 5};

int[] expanded = Arrays.copyOf(arr, 8);        // 扩容:[1,2,3,4,5,0,0,0]
int[] truncated = Arrays.copyOf(arr, 3);       // 缩容:[1,2,3]
int[] rangeCopy = Arrays.copyOfRange(arr,1,4); // 范围拷贝:[2,3,4]
  1. 数组转 List(重要陷阱)
1
2
3
4
5
6
// 固定大小 List,不能 add/remove
List<Integer> list = Arrays.asList(1, 2, 3);

// 正确:转成可修改 ArrayList
List<Integer> mutableList = new ArrayList<>(Arrays.asList(1,2,3));
mutableList.add(4); // 结果:[1,2,3,4]
  1. 多维数组操作
1
2
3
4
5
6
7
8
int[][] matrix = {{1,2},{3,4}};
int[][] matrix2 = {{1,2},{3,4}};

// 打印嵌套数组
Arrays.deepToString(matrix);  // [[1, 2], [3, 4]]

// 深度比较多维数组
Arrays.deepEquals(matrix, matrix2); // true
  1. 数组 Stream 常用操作
1
2
3
4
5
int[] arr = {1,2,3,4,5};

int sum = Arrays.stream(arr).sum(); // 总和:15
int max = Arrays.stream(arr).max().orElse(0); // 最大值:5
double avg = Arrays.stream(arr).average().orElse(0); // 平均值:3.0

1.4 性能陷阱与最佳实践

 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
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class ArraysBestPractice {

    // 陷阱1:频繁扩容,性能极差 O(n²)
    public void badPractice() {
        int[] arr = new int[0];
        for (int i = 0; i < 1000; i++) {
            // 每次都扩容复制,效率极低
            arr = Arrays.copyOf(arr, arr.length + 1);
            arr[i] = i;
        }
    }

    // 正确做法1:一次性指定容量
    public void goodPractice() {
        // 直接分配足够空间,一次搞定
        int[] arr = new int[1000];
        for (int i = 0; i < 1000; i++) {
            arr[i] = i;
        }
    }

    // 陷阱2:Arrays.asList 与原数组互相影响,且不能增删
    public void asListTrap() {
        String[] array = {"a", "b", "c"};
        List<String> list = Arrays.asList(array);

        // 修改原数组
        array[0] = "x";
        // List 也跟着变,因为底层共用同一个数组
        System.out.println("陷阱2结果:" + list.get(0)); // 输出 x
    }

    // 正确做法2:转成独立的 ArrayList,数组和List互不影响
    public void asListGoodPractice() {
        String[] array = {"a", "b", "c"};

        // 新建一个真正的 ArrayList,复制数据,完全独立
        List<String> list = new ArrayList<>(Arrays.asList(array));

        // 修改原数组
        array[0] = "x";

        // List 不受影响
        System.out.println("正确做法结果:" + list.get(0)); // 依然是 a
    }

    // 运行测试
    public static void main(String[] args) {
        ArraysBestPractice demo = new ArraysBestPractice();

        System.out.println("===== 陷阱2测试 =====");
        demo.asListTrap();

        System.out.println("===== 正确做法测试 =====");
        demo.asListGoodPractice();
    }
}

二、Collections 类

2.1 核心定位

Collections 提供对集合的静态工具方法,包括排序、查找、同步包装、不可变包装等。

2.2 方法分类

类别 代表方法 用途
排序 sort(), reverse(), shuffle() 改变元素顺序
查找 binarySearch(), max(), min() 极值与搜索
线程安全 synchronizedXxx() 包装线程安全集合
不可变 unmodifiableXxx() 创建只读视图
单例 singletonXxx() 创建单元素集合

2.3 代码示例

  1. 排序、反转、打乱
1
2
3
4
5
List<Integer> list = new ArrayList<>(Arrays.asList(3, 1, 4, 1, 5, 9, 2, 6));

Collections.sort(list);       // [1,1,2,3,4,5,6,9]
Collections.reverse(list);    // [9,6,5,4,3,2,1,1]
Collections.shuffle(list);     // 随机打乱
  1. 最大值、最小值
1
2
3
4
List<Integer> list = Arrays.asList(3,1,4,1,5,9,2,6);

int max = Collections.max(list);  // 9
int min = Collections.min(list);  // 1
  1. 二分查找(必须先排序)
1
2
3
List<Integer> list = Arrays.asList(1,2,3,4,5,6,9);

int index = Collections.binarySearch(list, 5);  // 下标 4
  1. 线程安全集合包装
1
2
3
4
List<String> unsafeList = new ArrayList<>();

// 包装成线程安全 List(加 synchronized)
List<String> safeList = Collections.synchronizedList(unsafeList);
  1. 不可变(只读)集合
1
2
3
4
// 只读,不能 add/remove/set
List<String> readOnly = Collections.unmodifiableList(Arrays.asList("a", "b"));

// readOnly.add("c"); → 抛异常
  1. 单元素集合(内存最优)
1
2
3
Set<String> singleSet    = Collections.singleton("only");
List<String> singleList  = Collections.singletonList("only");
Map<String,Integer> map = Collections.singletonMap("key", 1);
  1. 全部填充为同一个值
1
2
3
List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));

Collections.fill(list, "x");  // [x, x, x]
  1. 批量替换元素
1
2
3
List<Integer> list = new ArrayList<>(Arrays.asList(1,2,1,3,1));

Collections.replaceAll(list, 1, 9);  // [9,2,9,3,9]
  1. 统计元素出现次数
1
2
3
List<Integer> list = Arrays.asList(9,2,9,3,9);

int freq = Collections.frequency(list, 9);  // 3
  1. 判断是否无交集
1
2
3
4
5
List<String> list1 = Arrays.asList("a", "b", "c");
List<String> list2 = Arrays.asList("b", "c", "d");

// 无交集返回 true,有交集返回 false
boolean disjoint = Collections.disjoint(list1, list2);  // false
  1. 集合复制
1
2
3
4
5
6
List<String> src = Arrays.asList("a", "b", "c");
// 生成一个包含 3 个空字符串 "" 的不可变集合,结果 = ["", "", ""]
// 作用就是 快速创建一个指定长度、初始值都一样的集合
List<String> dst = new ArrayList<>(Collections.nCopies(3, "")); 
// Collections.copy(目标, 来源),dst = 目标(往这里贴),src = 来源(从这里拿)
Collections.copy(dst, src);  // dst 变为 [a, b, c]

2.4 线程安全 vs 并发集合

  1. Collections.synchronizedList
1
List<String> syncList = Collections.synchronizedList(new ArrayList<>());
  • 原理:所有方法加 synchronized
  • 优点:简单、兼容旧代码
  • 缺点:锁粒度粗,并发性能差
  • 适用:低并发、简单场景
  1. CopyOnWriteArrayList(推荐:读多写少)
1
List<String> cowList = new CopyOnWriteArrayList<>();
  • 原理:写时复制新数组,读操作无锁
  • 优点:读性能极高,线程安全
  • 缺点:写性能低,内存开销大
  • 适用:读多写少(白名单、配置、缓存)
  1. ConcurrentLinkedQueue(高并发队列)
1
Queue<String> concurrentQueue = new ConcurrentLinkedQueue<>();
  • 原理:CAS 无锁算法
  • 优点:高并发性能优秀
  • 缺点size() 慢,需要遍历
  • 适用:高并发任务队列、消息队列

三、Objects 类

3.1 核心定位

Objects(空安全工具类),专门做空安全的对象操作,避免空指针异常(NPE),是日常写健壮代码最常用的工具类。

3.2 核心方法

方法 用途 替代方案
equals(a, b) 空安全比较 a != null && a.equals(b)
hashCode(o) 空安全哈希 o != null ? o.hashCode() : 0
requireNonNull(o) 参数校验 if (o == null) throw ...
isNull(o) / nonNull(o) 空值判断 o == null / o != null
compare(a, b, c) 空安全比较 自定义比较器

3.3 代码示例

  1. Objects.equals(a, b) 空安全相等判断
1
2
3
4
5
6
String a = null;
String b = "Hello";

// 安全比较,不会 NPE
boolean eq = Objects.equals(a, b);        // false
boolean bothNull = Objects.equals(null, null); // true
  • 优点:不用自己写 if (a != null) 判空
  • 等价安全写法:a != null && a.equals(b)
  1. Objects.isNull / nonNull 判断空
1
2
3
4
String str = null;

boolean isNull = Objects.isNull(str);     // true
boolean nonNull = Objects.nonNull(str);   // false

常用于 Stream 过滤:

1
2
3
4
5
6
7
List<String> list = Arrays.asList("a", null, "b", null);

// 统计 null 数量
long nullCount = list.stream().filter(Objects::isNull).count(); // 2

// 过滤掉 null
List<String> noNull = list.stream().filter(Objects::nonNull).toList();
  1. Objects.requireNonNull 非空校验(最常用)
1
2
3
4
String name = null;

// 为空直接抛 NPE
String result = Objects.requireNonNull(name, "用户名不能为空");

构造方法里做参数校验:

1
2
3
4
5
6
7
class User {
    private final String username;

    public User(String username) {
        this.username = Objects.requireNonNull(username, "username 不能为 null");
    }
}
  1. Objects.hashCode / Objects.hash 计算哈希
1
2
3
4
5
6
7
String str = "hello";

// 单个对象 hashCode(空时返回 0,不抛异常)
int hash = Objects.hashCode(str);

// 多个字段组合 hashCode(写 hashCode() 方法专用)
int combinedHash = Objects.hash("Tom", 18, "Shanghai");
  1. 排序时处理 null(nullsFirst / nullsLast)
1
2
3
4
5
6
7
8
9
List<String> list = Arrays.asList("banana", null, "apple", null);

// null 放前面
list.sort(Comparator.nullsFirst(Comparator.naturalOrder()));
// [null, null, apple, banana]

// null 放后面
list.sort(Comparator.nullsLast(Comparator.naturalOrder()));
// [apple, banana, null, null]
  1. equals() + hashCode() 标准写法
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
class User {
    private String username;

    @Override
    public boolean equals(Object o) {
        // this = 当前正在调用这个方法的那个对象
        // this 不是 “类”,是 “当前正在调用 equals 的那个对象”
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return Objects.equals(username, user.username);
    }

    @Override
    public int hashCode() {
        return Objects.hash(username);
    }
}

四、Files 与 Paths 类(NIO.2)

4.1 核心定位

Java 7+ 推荐的文件操作工具,完全替代旧的 File 类。优点:简洁、强大、空安全、异常明确、支持大文件、支持流式操作。

4.2 核心方法对比

操作 传统 IO (java.io.File) NIO.2 (Files / Paths)
创建路径对象 new File("path") Paths.get("path")
读全部字节 FileInputStream Files.readAllBytes()
读全部文本行 BufferedReader Files.readAllLines()
写入文件 FileOutputStream Files.write()
文件复制 手动流拷贝 Files.copy()
文件移动/改名 file.renameTo() Files.move()
遍历目录 file.listFiles() Files.walk() / Files.find()
判断是否存在 file.exists() Files.exists()
判断是否文件 file.isFile() Files.isRegularFile()
判断是否目录 file.isDirectory() Files.isDirectory()
文件大小 file.length() Files.size()
删除文件 file.delete() Files.delete()
创建单级目录 file.mkdir() Files.createDirectory()
创建多级目录 递归手动创建 Files.createDirectories()

4.3 代码示例

  1. 路径操作 Paths.get()
1
2
3
4
5
6
7
8
9
// 创建路径对象 /tmp/test/file.txt(不创建文件)
Path path = Paths.get("/tmp", "test", "file.txt");

// 获取父目录 / 文件名 / 根路径
Path parent = path.getParent();       // /tmp/test
Path fileName = path.getFileName();   // file.txt

// 路径拼接 /tmp/test/file.txt
Path resolved = Paths.get("/tmp").resolve("test/file.txt");
  1. 快速读写文件(最常用)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
Path path = Paths.get("test.txt");
String content = "Hello NIO.2";

// 写入文件(自动创建,自动关闭)
Files.write(path, content.getBytes());

// 读取文件全部内容 → String
String readContent = Files.readString(path);

// 读取所有行
List<String> lines = Files.readAllLines(path);
  1. 大文件逐行读取(Stream 方式)
1
2
3
4
5
6
7
Path path = Paths.get("large.txt");

// 逐行读,不占内存(大文件首选)
try (Stream<String> lines = Files.lines(path)) {
    lines.filter(s -> s.contains("Java"))
         .forEach(System.out::println);
}
  1. 文件复制 / 移动
1
2
3
4
5
6
7
8
Path src = Paths.get("a.txt");
Path dst = Paths.get("b.txt");

// 复制(覆盖已存在)
Files.copy(src, dst, StandardCopyOption.REPLACE_EXISTING);

// 移动/重命名
Files.move(src, dst);
  1. 目录遍历(walk 递归遍历)
1
2
3
4
5
6
7
8
Path dir = Paths.get("/tmp");

// 递归遍历所有文件(深度3层)
try (Stream<Path> stream = Files.walk(dir, 3)) {
    stream.filter(Files::isRegularFile)  // 只看文件
          .filter(p -> p.toString().endsWith(".txt"))
          .forEach(System.out::println);
}
  1. 文件属性判断
1
2
3
4
5
Path path = Paths.get("test.txt");

boolean exists = Files.exists(path);        // 是否存在
boolean isFile = Files.isRegularFile(path); // 是否是文件
long size = Files.size(path);               // 文件大小
  1. 创建目录 / 多级目录
1
2
3
4
5
// 创建单级目录
Files.createDirectory(Paths.get("/tmp/test"));

// 创建多级目录(自动创建父目录)
Files.createDirectories(Paths.get("/tmp/a/b/c"));
  1. 创建临时文件 / 删除文件
1
2
3
4
5
// 创建临时文件
Path temp = Files.createTempFile("demo", ".txt");

// 删除文件
Files.deleteIfExists(temp); // 不存在也不报错
  1. 文件追加写入
1
2
3
Path path = Paths.get("test.txt");

Files.write(path, "追加内容".getBytes(), StandardOpenOption.APPEND);

4.4 异常处理与资源管理

 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
import java.nio.file.*;
import java.io.IOException;

public class FilesExceptionHandling {
    
    public static void safeFileOperation() {
        Path path = Paths.get("/tmp/data.txt");
        
        // 方式1:传统 try-catch
        try {
            String content = Files.readString(path);
            System.out.println(content);
        } catch (NoSuchFileException e) {
            System.err.println("文件不存在: " + e.getFile());
        } catch (AccessDeniedException e) {
            System.err.println("权限不足: " + e.getFile());
        } catch (IOException e) {
            System.err.println("IO 错误: " + e.getMessage());
        }
        
        // 方式2:使用 try-with-resources 确保流关闭
        try (var lines = Files.lines(path)) {
            lines.forEach(System.out::println);
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        // 方式3:先检查再操作(避免异常)
        if (Files.exists(path) && Files.isReadable(path)) {
            try {
                String content = Files.readString(path);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    // 原子文件写入(防止写入中断导致文件损坏)
    public static void atomicWrite(Path path, String content) throws IOException {
        // Files.createTempFile(前缀, 后缀),中间系统自动加随机数字,防止重名,temp + 随机数 + .tmp;例如:/tmp/temp123456789.tmp
        Path temp = Files.createTempFile("temp", ".tmp");
        try {
            Files.writeString(temp, content);
            Files.move(temp, path, StandardCopyOption.ATOMIC_MOVE, 
                      StandardCopyOption.REPLACE_EXISTING);
        } catch (IOException e) {
            Files.deleteIfExists(temp);
            throw e;
        }
    }
}

五、Math 类

5.1 核心定位

Java 提供的基础数学运算工具类,包含极值、绝对值、取整、随机数等方法。重点注意:浮点数精度问题、整数溢出陷阱,金融计算必须用 BigDecimal

5.2 方法分类

类别 方法 说明
极值 max(), min() 比较大小
绝对值 abs() 处理负数
幂运算 pow(), sqrt(), cbrt() 平方、立方根
取整 ceil(), floor(), round() 向上/向下/四舍五入
三角函数 sin(), cos(), tan() 弧度制
随机数 random() [0.0, 1.0)

5.3 代码示例

  1. 基础运算
1
2
3
4
5
6
7
int max = Math.max(10, 20);        // 20
int min = Math.min(10, 20);        // 10
int abs = Math.abs(-10);           // 10

double sqrt = Math.sqrt(25);       // 5.0
double pow = Math.pow(2, 10);      // 1024.0
double cbrt = Math.cbrt(27);       // 3.0
  1. 取整运算(重点)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
double num = 3.7;

Math.ceil(num);     // 4.0   向上取整
Math.floor(num);    // 3.0   向下取整
Math.round(num);    // 4     四舍五入(返回 long)

// 负数取整
Math.ceil(-3.7);    // -3.0
Math.floor(-3.7);   // -4.0
Math.round(-3.7);   // -4
  1. 浮点数精度陷阱
1
2
3
4
5
6
7
8
// 精度丢失
0.1 + 0.2;              // 0.30000000000000004
Math.pow(0.1, 2);       // 0.010000000000000002

// 精确计算必须用 BigDecimal
BigDecimal a = new BigDecimal("0.1");
BigDecimal b = new BigDecimal("0.2");
a.add(b);               // 0.3  完全精确
  1. 绝对值溢出陷阱(重点)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Math.abs(Integer.MAX_VALUE);       // 2147483647 正常

// 溢出陷阱:MIN_VALUE 取绝对值超出 int 范围
Math.abs(Integer.MIN_VALUE);       // -2147483648 错误结果

// 安全处理:先转 long 再取绝对值
long safeAbs = Math.abs((long) Integer.MIN_VALUE); // 2147483648

// 安全处理:Integer.absExact,抛异常提示溢出
int safeAbs = Integer.absExact(Integer.MAX_VALUE); // 超出则抛异常提示溢出,否则正常处理
  1. Math.round 返回类型陷阱
1
2
long rounded = Math.round(3.7);   // 返回 long,不是 int
// int wrong = Math.round(3.7);   // 编译报错
  1. 随机数
1
2
3
4
5
6
7
8
// [0.0, 1.0)
double r = Math.random();

// [10, 50] 随机整数
int randomInt = 10 + (int)(Math.random() * 41);

// Java 7+ 推荐:ThreadLocalRandom
int better = ThreadLocalRandom.current().nextInt(10, 51);
  1. Math vs StrictMath
1
2
3
4
5
// Math:平台优化,速度快,精度略有差异
double mathSin = Math.sin(Math.PI / 2);    // 1.0

// StrictMath:严格 IEEE 754,跨平台结果完全一致
double strictSin = StrictMath.sin(Math.PI / 2); // 1.0
  1. BigDecimal 精确计算(金融专用)
1
2
3
4
5
6
7
8
BigDecimal price = new BigDecimal("19.99");
BigDecimal quantity = new BigDecimal("3");

// 乘法
BigDecimal total = price.multiply(quantity);  // 59.97

// 除法(指定精度 + 舍入模式)
BigDecimal result = total.divide(new BigDecimal("3"), 2, RoundingMode.HALF_UP); // 19.99

六、Stream API

6.1 核心定位

链式操作、惰性执行、支持并行,专门用于集合/数组数据处理(过滤、转换、统计、查找),代码极简优雅。三大阶段:创建流 → 中间操作 → 终止操作。

6.2 核心方法

概念 说明 示例
创建流 从集合、数组、IO 等创建 list.stream(), Arrays.stream(arr)
中间操作 返回新流,惰性执行 filter(), map(), sorted()
终止操作 触发执行,返回结果 collect(), forEach(), reduce()
短路操作 提前结束,提高效率 findFirst(), anyMatch(), limit()

6.3. 创建 Stream

下面是创建 Stream 最常用的方式:

 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
// 1. 集合创建
List<String> list = Arrays.asList("a","b","c");
Stream<String> stream = list.stream();          // 串行
Stream<String> parallel = list.parallelStream();// 并行

// 2. Map 转流
Map<String, Integer> map = Map.of("a", 1, "b", 2);
Stream<Map.Entry<String, Integer>> entryStream = map.entrySet().stream();

// 3. 数组创建
int[] arr = {1,2,3};
IntStream intStream = Arrays.stream(arr);

// 4. 静态方法
Stream<String> stream1 = Stream.of("a","b","c");
Stream<Integer> empty = Stream.empty();

// 5. 基本类型流(推荐,无装箱)
IntStream.of(1,2,3);
LongStream.of(1L,2L);
DoubleStream.of(1.1,2.2);

// 6. 无限流(必须加 limit)
Stream.iterate(0, n -> n+1).limit(10);
Stream.generate(Math::random).limit(5);

// 7. IO 流(必须 try-with-resources 自动关闭)
try (Stream<String> lines = Files.lines(Paths.get("file.txt"))) {
    lines.forEach(System.out::println);
}

6.4. 中间操作

中间操作是惰性的,就是不调用终止操作,中间操作不执行。

  1. 过滤 / 去重
1
2
3
4
5
6
7
List<Integer> list = Arrays.asList(1,2,2,3,4,4);

// filter:条件过滤
list.stream().filter(n -> n%2==0); // 保留偶数

// distinct:去重
list.stream().distinct(); // [1,2,3,4]
  1. 映射(转换数据)
1
2
3
4
5
6
7
8
9
// map:一对一转换
list.stream().map(n -> n*2); // 1→2, 2→4...

// flatMap:扁平化(嵌套集合展开)
List<List<Integer>> nested = Arrays.asList(Arrays.asList(1,2), Arrays.asList(3,4));
nested.stream().flatMap(Collection::stream); // [1,2,3,4]

// 基本类型流(性能最优)
list.stream().mapToInt(Integer::intValue);
  1. 排序
1
2
3
4
5
// 自然排序
list.stream().sorted();

// 自定义排序
list.stream().sorted(Comparator.reverseOrder()); // 倒序
  1. 截断 / 跳过
1
2
3
4
5
list.stream().limit(3);  // 取前3个
list.stream().skip(2);   // 跳过前2个

// 分页标准写法
stream.skip((page-1)*size).limit(size);
  1. 调试 peek(不影响流,打印日志)
1
2
3
4
list.stream()
    .filter(n->n>2)
    .peek(System.out::println) // 调试
    .map(n->n*3);

6.5 终止操作

终止操作,执行后流关闭,返回结果。

  1. 聚合统计
1
2
3
4
5
6
7
List<Integer> list = Arrays.asList(1,2,3,4,5);

long count = list.stream().count();       // 5
int sum = list.stream().mapToInt(Integer::intValue).sum(); // 15
int max = list.stream().mapToInt(Integer::intValue).max().orElse(0); //5
int min = list.stream().mapToInt(Integer::intValue).min().orElse(0); //1
double avg = list.stream().mapToInt(Integer::intValue).average().orElse(0); //3.0
  1. 归约 reduce(累加、拼接、乘积)
1
2
3
4
5
// 求和
int total = list.stream().reduce(0, Integer::sum);

// 字符串拼接
String str = Stream.of("a","b","c").reduce("", String::concat);
  1. 收集 collect(最常用 → 转 List/Set/Map)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// 转集合
List<Integer> resultList = stream.collect(Collectors.toList());
Set<Integer> resultSet = stream.collect(Collectors.toSet());

// 字符串拼接
String join = stream.map(String::valueOf).collect(Collectors.joining(","));

// 分组
Map<String, List<Integer>> group = list.stream()
    .collect(Collectors.groupingBy(n->n%2==0?"偶数":"奇数"));

// 分区(true/false两组),Map<Boolean, List<元素>,key 只有两个:true /false
// {
//    false = [1, 2, 3],
//    true  = [4, 5]
// }
Map<Boolean, List<Integer>> part = list.stream()
    .collect(Collectors.partitioningBy(n->n>3));
  1. 查找与匹配(短路操作)
1
2
3
4
5
6
7
8
// 查找
Optional<Integer> first = list.stream().findFirst(); // 第一个
Optional<Integer> any = list.stream().findAny();     // 任意一个

// 匹配
boolean anyMatch = list.stream().anyMatch(n->n>3);   // 存在一个满足
boolean allMatch = list.stream().allMatch(n->n>0);   // 全部满足
boolean noneMatch = list.stream().noneMatch(n->n<0); // 都不满足
  1. 遍历
1
2
list.stream().forEach(System.out::println);
list.parallelStream().forEachOrdered(System.out::println); // 保证顺序

6.5 性能陷阱与最佳实践

  1. 流只能使用一次
1
2
3
Stream<Integer> s = list.stream();
s.count();
// s.forEach(...); // 报错:流已关闭
  1. 基本类型流比包装流快
1
2
3
4
5
// 慢(装箱/拆箱)
list.stream().reduce(0, Integer::sum);

// 快(推荐)
list.stream().mapToInt(Integer::intValue).sum();
  1. 并行流不是万能的
1
2
3
4
5
// 小数据量不要用并行
smallList.parallelStream(); // 浪费性能

// 适合:大数据量 + 数组/ArrayList
IntStream.range(0,1000000).parallel().sum();
  1. null 必须手动过滤
1
2
3
list.stream()
    .filter(Objects::nonNull) // 必须加
    .forEach(...);
  1. 完整标准示例(最常用模板)
1
2
3
4
5
6
7
// 需求:过滤偶数 → 平方 → 排序 → 转集合
List<Integer> result = list.stream()
    .filter(Objects::nonNull)
    .filter(n -> n % 2 == 0)
    .map(n -> n * n)
    .sorted()
    .collect(Collectors.toList());

七、StringUtils(Apache Commons Lang)

7.1 核心定位

Java 原生 String 增强工具类,最大优势:空安全(传 null 不抛 NPE),日常开发字符串处理首选。必须依赖:commons-lang3

7.2 与原生 Java 对比

操作 原生 Java StringUtils 优势
判空 str == null || str.isEmpty() StringUtils.isEmpty(str) 简洁、可读
判空白 str == null || str.trim().isEmpty() StringUtils.isBlank(str) 包含全空白判断
默认值 str != null ? str : default StringUtils.defaultString(str) 简洁
截取 手动检查边界 StringUtils.substring(str, 0, 5) 安全(不抛异常)
分割 split()(正则) split()(按字符) 性能更好

7.3 代码示例

  1. 最核心:空值判断(最常用)
1
2
3
4
5
6
7
8
9
// isEmpty:null 或 "" → true;"   " → false
StringUtils.isEmpty(null);    // true
StringUtils.isEmpty("");      // true
StringUtils.isEmpty("   ");   // false

// isBlank:null / "" / 全是空格 → 都返回 true(工作最常用)
StringUtils.isBlank(null);    // true
StringUtils.isBlank("");      // true
StringUtils.isBlank("   ");   // true
  1. 空值默认值(防止 null)
1
2
3
4
5
6
// null 转 ""
StringUtils.defaultString(null);   // ""

// null 或空白 → 用默认值
StringUtils.defaultIfBlank(null, "未知");   // "未知"
StringUtils.defaultIfBlank("   ", "默认");  // "默认"
  1. 安全截取(不会越界异常)
1
2
3
4
5
6
7
8
String str = "Hello";

// 超出长度不会报错,自动截断
StringUtils.substring(str, 0, 100);  // "Hello"
StringUtils.substring(str, 2);       // "llo"

// 取两个字符串中间的内容
StringUtils.substringBetween("[123]", "[", "]");  // "123"
  1. 字符串分割(非正则,性能高)
1
2
3
4
5
6
7
String str = "a,b,c,d";

// 按字符分割(不是正则,比原生 String.split 快)
StringUtils.split(str, ",");   // [a, b, c, d]

// 限制分割次数
StringUtils.split("a,b,c,d", ",", 2);  // [a, b,c,d]
  1. 字符串连接(数组/集合拼接)
1
2
3
4
5
List<String> list = Arrays.asList("a","b","c");

// 用分隔符连接
StringUtils.join(list, ", ");   // "a, b, c"
StringUtils.join(new String[]{"a","b"}, "-");  // "a-b"
  1. 去空格 / 删除内容
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
String str = "  Hello  World  ";

// 去首尾空格
StringUtils.trim(str);   // "Hello  World"

// 删除所有空格
StringUtils.deleteWhitespace(str);  // "HelloWorld"

// 删除指定子串
StringUtils.remove("Hello", "e");   // "Hllo"
  1. 包含判断(空安全)
1
2
3
4
5
6
7
8
9
// 包含子串(传 null 也不报错)
StringUtils.contains("Hello", "H");   // true
StringUtils.contains(null, "a");       // false

// 忽略大小写
StringUtils.containsIgnoreCase("Hello", "h");  // true

// 统计子串出现次数
StringUtils.countMatches("ababa", "a");  // 3
  1. 填充、补齐、重复
1
2
3
4
5
6
7
8
// 左侧补 0(常用:编号、序号)
StringUtils.leftPad("5", 3, "0");   // "005"

// 右侧补齐
StringUtils.rightPad("Hi", 5, "!"); // "Hi!!!"

// 重复字符串
StringUtils.repeat("ab", 3);        // "ababab"
  1. 大小写转换
1
2
3
StringUtils.upperCase("hello");    // "HELLO"
StringUtils.lowerCase("HELLO");    // "hello"
StringUtils.capitalize("hello");    // "Hello"(首字母大写)
  1. Maven 依赖(必须加)
1
2
3
4
5
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.12.0</version>
</dependency>

八、工具类选择速查表

场景 推荐工具类 说明
数组排序/查找 Arrays 双轴快排、二分查找
集合排序/同步 Collections 线程安全包装、不可变视图
空值处理 Objects 空安全比较、参数校验
文件读写 Files/Paths NIO.2,支持 Stream
数学计算 Math / BigDecimal 基本运算 / 精确计算
数据处理 Stream API 函数式、链式操作
字符串处理 StringUtils Apache Commons,更强大

九、总结

核心要点

  1. Arrays:掌握 asList() 的陷阱,优先使用 copyOf() 进行数组扩容
  2. Collections:理解同步包装与并发集合的区别,善用不可变集合
  3. Objects:防御式编程的基础,所有参数校验都应使用 requireNonNull()
  4. Files/Paths:NIO.2 是现代 Java 文件操作的标准,务必掌握 try-with-resources
  5. Math:金融计算必须使用 BigDecimal,注意浮点数精度问题
  6. Stream:理解惰性求值和短路操作,避免并行流误用
  7. StringUtils:项目中引入 Apache Commons Lang 可大幅提升字符串处理效率

性能建议

  • 小数据量:直接使用循环,避免 Stream overhead
  • 大数据量:使用 Stream 并行处理,但确保数据源可高效拆分
  • 频繁操作:优先使用基本类型流(IntStream 等)避免装箱
  • 字符串处理:大量操作时,Apache Commons Lang 性能优于原生方法