6.1 简介

Java标准类库(Java Standard Library)是JDK自带的一套丰富的API集合,包含了数千个预定义的类和方法,用于处理字符串、数学计算、日期时间、集合操作等各种常见任务。这些类库组织在java.langjava.utiljava.time等包中,无需额外安装即可使用。

核心特点:

  • 开箱即用:JDK安装后即可使用
  • 跨平台:在所有支持Java的平台上行为一致
  • 高性能:经过多年优化,性能可靠
  • 向后兼容:新版本保持对旧API的兼容

6.2 字符串类

6.2.1 String类

概念介绍:
String类表示不可变的字符序列,是Java中最常用的类之一。String对象一旦创建,其内容就不能被修改。

核心常用API方法:

  • length():返回字符串长度
  • charAt(int index):返回指定索引处的字符
  • substring(int beginIndex, int endIndex):截取子字符串
  • indexOf(String str):查找子字符串位置
  • equals(Object obj):比较字符串内容
  • toUpperCase() / toLowerCase():大小写转换
  • trim():去除首尾空格
  • split(String regex):按正则表达式分割字符串

完整可运行代码示例:

public class StringExample {
    public static void main(String[] args) {
        // 1. 创建字符串
        String str1 = "Hello, Java!";
        String str2 = new String("Hello, World!");
        
        // 2. 基本操作
        System.out.println("字符串长度: " + str1.length()); // 12
        System.out.println("第7个字符: " + str1.charAt(6)); // J
        System.out.println("子字符串: " + str1.substring(7, 11)); // Java
        
        // 3. 查找与比较
        System.out.println("包含Java吗? " + str1.contains("Java")); // true
        System.out.println("Java的位置: " + str1.indexOf("Java")); // 7
        System.out.println("字符串相等吗? " + str1.equals(str2)); // false
        
        // 4. 转换操作
        System.out.println("大写: " + str1.toUpperCase()); // HELLO, JAVA!
        System.out.println("小写: " + str1.toLowerCase()); // hello, java!
        
        // 5. 分割字符串
        String csv = "苹果,香蕉,橙子,葡萄";
        String[] fruits = csv.split(",");
        System.out.println("水果列表:");
        for (String fruit : fruits) {
            System.out.println("  - " + fruit);
        }
    }
}

运行结果:

字符串长度: 12
第7个字符: J
子字符串: Java
包含Java吗? true
Java的位置: 7
字符串相等吗? false
大写: HELLO, JAVA!
小写: hello, java!
水果列表:
  - 苹果
  - 香蕉
  - 橙子
  - 葡萄

使用场景与易错点:

  • 适用场景:文本处理、用户输入验证、配置文件读取、日志输出等
  • 易错点1:使用==比较字符串内容(应使用equals()方法)
  • 易错点2:在循环中频繁拼接字符串(应使用StringBuilder)
  • 易错点3:忽略字符串不可变性,误以为修改了原字符串

6.2.2 StringBuffer类

概念介绍:
StringBuffer类表示可变的字符序列,可以在原对象上修改内容,适用于需要频繁修改字符串的场景。

核心常用API方法:

  • append(String str):追加字符串
  • insert(int offset, String str):在指定位置插入
  • delete(int start, int end):删除指定范围的字符
  • reverse():反转字符串
  • toString():转换为String对象

完整可运行代码示例:

public class StringBufferExample {
    public static void main(String[] args) {
        // 创建StringBuffer对象
        StringBuffer sb = new StringBuffer("Hello");
        
        // 追加操作
        sb.append(" World");
        System.out.println("追加后: " + sb); // Hello World
        
        // 插入操作
        sb.insert(5, ",");
        System.out.println("插入后: " + sb); // Hello, World
        
        // 删除操作
        sb.delete(5, 6);
        System.out.println("删除后: " + sb); // Hello World
        
        // 替换操作
        sb.replace(6, 11, "Java");
        System.out.println("替换后: " + sb); // Hello Java
        
        // 反转操作
        sb.reverse();
        System.out.println("反转后: " + sb); // avaJ olleH
        
        // 转换回String
        String result = sb.toString();
        System.out.println("最终字符串: " + result);
    }
}

运行结果:

追加后: Hello World
插入后: Hello, World
删除后: Hello World
替换后: Hello Java
反转后: avaJ olleH
最终字符串: avaJ olleH

String vs StringBuffer对比:

特性 String StringBuffer
可变性 不可变 可变
线程安全 线程安全 线程安全
性能 拼接性能差 拼接性能好
内存 每次修改创建新对象 在原对象上修改
适用场景 不频繁修改的字符串 频繁修改的字符串

使用场景与易错点:

  • 适用场景:大量字符串拼接、动态构建SQL语句、处理用户输入流
  • 易错点1:在单线程环境下使用StringBuffer(应使用StringBuilder)
  • 易错点2:忘记调用toString()方法转换
  • 易错点3:在多线程环境下使用StringBuilder(应使用StringBuffer)

6.2.3 正则表达式

概念介绍:
正则表达式(Regular Expression)是一种用于匹配字符串模式的强大工具,Java通过java.util.regex包提供支持。

核心常用API方法:

  • Pattern.compile(String regex):编译正则表达式
  • Matcher.matches():尝试匹配整个字符串
  • Matcher.find():查找下一个匹配项
  • Matcher.group():返回匹配的字符串
  • String.matches(String regex):快速匹配方法

常用正则表达式模式:

  • \d:数字
  • \w:单词字符(字母、数字、下划线)
  • \s:空白字符
  • [abc]:a、b或c中的任意一个
  • [^abc]:除了a、b、c的任意字符
  • a{3}:恰好3个a
  • a{3,}:至少3个a
  • a{3,5}:3到5个a

完整可运行代码示例:

import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class RegexExample {
    public static void main(String[] args) {
        System.out.println("=== 1. 验证邮箱格式 ===");
        
        // 定义邮箱正则表达式
        String emailRegex = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$";
        Pattern emailPattern = Pattern.compile(emailRegex);
        
        // 测试邮箱地址
        String[] emails = {
            "user@example.com",      // 有效
            "john.doe123@gmail.com", // 有效
            "admin@company.co.uk",   // 有效
            "invalid-email",         // 无效:缺少@和域名
            "user@.com",             // 无效:@后直接点
            "@example.com",          // 无效:缺少用户名
            "user@com",              // 无效:域名太短
            "user@example.c"         // 无效:顶级域名太短
        };
        
        System.out.println("邮箱验证结果:");
        for (String email : emails) {
            Matcher matcher = emailPattern.matcher(email);
            boolean isValid = matcher.matches();
            System.out.printf("  %-25s -> %s%n", email, isValid ? "有效" : "无效");
        }
        
        System.out.println("\n=== 2. 提取电话号码 ===");
        
        // 定义电话号码正则表达式(支持多种格式)
        String phoneRegex = "\\b(\\+?86)?[1][3-9]\\d{9}\\b|\\b0\\d{2,3}-?\\d{7,8}\\b";
        Pattern phonePattern = Pattern.compile(phoneRegex);
        
        // 测试文本
        String text = "联系方式:张三 13812345678,李四 +8613912345678," +
                     "公司电话:010-12345678,客服:400-888-9999," +
                     "无效号码:12345,手机:12-34567890";
        
        System.out.println("原文:" + text);
        System.out.println("\n提取到的电话号码:");
        
        Matcher phoneMatcher = phonePattern.matcher(text);
        int count = 0;
        while (phoneMatcher.find()) {
            count++;
            System.out.println("  " + count + ". " + phoneMatcher.group());
        }
        System.out.println("共找到 " + count + " 个有效电话号码");
        
        System.out.println("\n=== 3. Pattern和Matcher高级用法 ===");
        
        // 复杂文本提取示例
        String logText = "2023-10-25 10:30:15 [INFO] User login: user123 from IP 192.168.1.100\n" +
                        "2023-10-25 10:35:22 [ERROR] Database connection failed: timeout after 5000ms\n" +
                        "2023-10-25 10:40:10 [WARN] Memory usage high: 85%";
        
        // 提取日志中的时间、级别、消息
        String logRegex = "(\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}) \\[([A-Z]+)\\] (.+)";
        Pattern logPattern = Pattern.compile(logRegex);
        Matcher logMatcher = logPattern.matcher(logText);
        
        System.out.println("日志解析结果:");
        while (logMatcher.find()) {
            String timestamp = logMatcher.group(1);
            String level = logMatcher.group(2);
            String message = logMatcher.group(3);
            System.out.printf("  时间: %s | 级别: %-5s | 消息: %s%n", 
                             timestamp, level, message);
        }
        
        System.out.println("\n=== 4. 分组和替换 ===");
        
        // 分组捕获和替换
        String dateText = "今天是2023-10-25,明天是2023-10-26";
        String dateRegex = "(\\d{4})-(\\d{2})-(\\d{2})";
        Pattern datePattern = Pattern.compile(dateRegex);
        Matcher dateMatcher = datePattern.matcher(dateText);
        
        // 将yyyy-mm-dd格式替换为dd/mm/yyyy格式
        String replacedText = dateMatcher.replaceAll("$3/$2/$1");
        System.out.println("原文本: " + dateText);
        System.out.println("替换后: " + replacedText);
        
        // 使用String的matches方法快速验证
        System.out.println("\n=== 5. 快速验证(String.matches())===");
        String quickTest = "Hello123";
        boolean isAlphanumeric = quickTest.matches("[a-zA-Z0-9]+");
        System.out.println("字符串 \"" + quickTest + "\" 是否只包含字母数字: " + isAlphanumeric);
    }
}

运行结果:

=== 1. 验证邮箱格式 ===
邮箱验证结果:
  user@example.com           -> 有效
  john.doe123@gmail.com     -> 有效
  admin@company.co.uk       -> 有效
  invalid-email             -> 无效
  user@.com                 -> 无效
  @example.com              -> 无效
  user@com                  -> 无效
  user@example.c            -> 无效

=== 2. 提取电话号码 ===
原文:联系方式:张三 13812345678,李四 +8613912345678,公司电话:010-12345678,客服:400-888-9999,无效号码:12345,手机:12-34567890

提取到的电话号码:
  1. 13812345678
  2. +8613912345678
  3. 010-12345678
  4. 400-888-9999
共找到 4 个有效电话号码

=== 3. Pattern和Matcher高级用法 ===
日志解析结果:
  时间: 2023-10-25 10:30:15 | 级别: INFO  | 消息: User login: user123 from IP 192.168.1.100
  时间: 2023-10-25 10:35:22 | 级别: ERROR | 消息: Database connection failed: timeout after 5000ms
  时间: 2023-10-25 10:40:10 | 级别: WARN  | 消息: Memory usage high: 85%

=== 4. 分组和替换 ===
原文本: 今天是2023-10-25,明天是2023-10-26
替换后: 今天是25/10/2023,明天是26/10/2023

=== 5. 快速验证(String.matches()) ===
字符串 "Hello123" 是否只包含字母数字: true

使用场景与易错点:

  • 适用场景:表单验证、日志分析、数据清洗、文本提取、URL路由匹配
  • 易错点1:正则表达式中的特殊字符需要转义(如.\[]等)
  • 易错点2:贪婪匹配 vs 非贪婪匹配(.* vs .*?
  • 易错点3:性能问题 - 避免在循环中重复编译Pattern对象
  • 易错点4:忘记处理边界情况(如空字符串、null值)
  • 最佳实践:复杂正则表达式添加注释,使用Pattern.COMMENTS标志提高可读性

6.2.4 实用案例6.1:使用正则表达式检查IP地址

完整可运行代码示例:

import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class IPAddressValidator {
    public static void main(String[] args) {
        // 定义IP地址的正则表达式
        // 解释:每个部分为0-255,用点分隔
        String ipPattern = "^((25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)\\.){3}" +
                          "(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)$";
        
        // 测试用例
        String[] testIPs = {
            "192.168.1.1",      // 有效
            "255.255.255.255",  // 有效
            "0.0.0.0",          // 有效
            "256.100.100.100",  // 无效:256>255
            "192.168.1",        // 无效:只有3部分
            "192.168.1.1.1",    // 无效:有5部分
            "abc.def.ghi.jkl",  // 无效:包含字母
            "192.168.01.001"    // 无效:前导0(实际中可能允许,这里严格限制)
        };
        
        Pattern pattern = Pattern.compile(ipPattern);
        
        System.out.println("IP地址验证结果:");
        System.out.println("========================");
        
        for (String ip : testIPs) {
            Matcher matcher = pattern.matcher(ip);
            boolean isValid = matcher.matches();
            System.out.printf("%-20s -> %s%n", ip, isValid ? "有效" : "无效");
        }
        
        // 额外示例:提取IP地址
        String text = "服务器1: 192.168.1.100, 服务器2: 10.0.0.1, 无效: 999.888.777.666";
        System.out.println("\n从文本中提取IP地址:");
        System.out.println("原文:" + text);
        
        // 简化的IP模式(用于提取)
        String extractPattern = "\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b";
        Pattern extractor = Pattern.compile(extractPattern);
        Matcher extractMatcher = extractor.matcher(text);
        
        System.out.print("提取结果:");
        while (extractMatcher.find()) {
            System.out.print(extractMatcher.group() + " ");
        }
    }
}

运行结果:

IP地址验证结果:
========================
192.168.1.1          -> 有效
255.255.255.255      -> 有效
0.0.0.0              -> 有效
256.100.100.100      -> 无效
192.168.1            -> 无效
192.168.1.1.1        -> 无效
abc.def.ghi.jkl      -> 无效
192.168.01.001       -> 无效

从文本中提取IP地址:
原文:服务器1: 192.168.1.100, 服务器2: 10.0.0.1, 无效: 999.888.777.666
提取结果:192.168.1.100 10.0.0.1 999.888.777.666 

使用场景与易错点:

  • 适用场景:表单验证、日志分析、数据清洗、文本提取
  • 易错点1:正则表达式过于复杂难以维护
  • 易错点2:忘记转义特殊字符(如.\等)
  • 易错点3:性能问题(避免在循环中重复编译Pattern)

6.3 数据类型包装器类

6.3.1 整型包装器类

概念介绍:
包装器类(Wrapper Classes)将基本数据类型封装成对象,使基本类型具有对象的特性。Java为8种基本类型提供了对应的包装器类。

基本类型与包装器类对应关系:

基本类型 包装器类 字节数 取值范围
byte Byte 1 -128 ~ 127
short Short 2 -32768 ~ 32767
int Integer 4 -2³¹ ~ 2³¹-1
long Long 8 -2⁶³ ~ 2⁶³-1
float Float 4 单精度浮点数
double Double 8 双精度浮点数
char Character 2 Unicode字符
boolean Boolean 1 true/false

核心常用API方法:

  • valueOf():将基本类型或字符串转换为包装器对象
  • parseXxx():将字符串转换为基本类型
  • xxxValue():获取包装器对象的基本类型值
  • compareTo():比较两个包装器对象
  • toString():转换为字符串

6.3.2 实用案例6.2:字符串和数字的相互转换

完整可运行代码示例:

public class StringNumberConversion {
    public static void main(String[] args) {
        System.out.println("=== 字符串转数字 ===");
        
        // 1. 字符串转int
        String strNum1 = "123";
        int num1 = Integer.parseInt(strNum1);
        System.out.println("字符串\"" + strNum1 + "\"转int: " + num1);
        
        // 2. 字符串转Integer对象
        Integer integerObj = Integer.valueOf(strNum1);
        System.out.println("字符串转Integer对象: " + integerObj);
        
        // 3. 处理进制转换
        String binaryStr = "1010";  // 二进制
        int decimalFromBinary = Integer.parseInt(binaryStr, 2);
        System.out.println("二进制\"" + binaryStr + "\"转十进制: " + decimalFromBinary);
        
        String hexStr = "FF";  // 十六进制
        int decimalFromHex = Integer.parseInt(hexStr, 16);
        System.out.println("十六进制\"" + hexStr + "\"转十进制: " + decimalFromHex);
        
        // 4. 处理异常情况
        try {
            String invalidStr = "123abc";
            int invalidNum = Integer.parseInt(invalidStr);
            System.out.println("转换结果: " + invalidNum);
        } catch (NumberFormatException e) {
            System.out.println("错误:\"" + invalidStr + "\"不是有效的整数");
        }
        
        System.out.println("\n=== 数字转字符串 ===");
        
        // 5. int转字符串(多种方式)
        int num2 = 456;
        
        // 方式1:使用Integer.toString()
        String str1 = Integer.toString(num2);
        System.out.println("Integer.toString(): " + str1);
        
        // 方式2:使用String.valueOf()
        String str2 = String.valueOf(num2);
        System.out.println("String.valueOf(): " + str2);
        
        // 方式3:使用字符串拼接(隐式转换)
        String str3 = "" + num2;
        System.out.println("字符串拼接: " + str3);
        
        // 方式4:格式化转换
        String str4 = String.format("%d", num2);
        System.out.println("String.format(): " + str4);
        
        // 6. 进制转换
        int num3 = 255;
        System.out.println("\n数字" + num3 + "的不同进制表示:");
        System.out.println("二进制: " + Integer.toBinaryString(num3));
        System.out.println("八进制: " + Integer.toOctalString(num3));
        System.out.println("十六进制: " + Integer.toHexString(num3));
        
        System.out.println("\n=== 其他类型转换示例 ===");
        
        // 7. double转换
        String doubleStr = "3.14159";
        double pi = Double.parseDouble(doubleStr);
        System.out.println("字符串转double: " + pi);
        System.out.println("double转字符串: " + Double.toString(pi));
        
        // 8. boolean转换
        String boolStr = "true";
        boolean flag = Boolean.parseBoolean(boolStr);
        System.out.println("字符串转boolean: " + flag);
        System.out.println("注意:Boolean.parseBoolean()不区分大小写,'True'、'TRUE'都有效");
        
        // 9. 自动装箱与拆箱
        System.out.println("\n=== 自动装箱与拆箱 ===");
        Integer autoBoxed = 100;  // 自动装箱:int -> Integer
        int autoUnboxed = autoBoxed;  // 自动拆箱:Integer -> int
        System.out.println("自动装箱: " + autoBoxed);
        System.out.println("自动拆箱: " + autoUnboxed);
        
        // 10. 比较注意事项
        Integer a = 127;
        Integer b = 127;
        Integer c = 128;
        Integer d = 128;
        
        System.out.println("\n=== 包装器对象比较注意事项 ===");
        System.out.println("a == b (127): " + (a == b));  // true,缓存范围内
        System.out.println("c == d (128): " + (c == d));  // false,超出缓存范围
        System.out.println("c.equals(d): " + c.equals(d)); // true,值相等
        System.out.println("建议:比较包装器对象时使用equals()方法");
    }
}

运行结果:

=== 字符串转数字 ===
字符串"123"转int: 123
字符串转Integer对象: 123
二进制"1010"转十进制: 10
十六进制"FF"转十进制: 255
错误:"123abc"不是有效的整数

=== 数字转字符串 ===
Integer.toString(): 456
String.valueOf(): 456
字符串拼接: 456
String.format(): 456

数字255的不同进制表示:
二进制: 11111111
八进制: 377
十六进制: ff

=== 其他类型转换示例 ===
字符串转double: 3.14159
double转字符串: 3.14159
字符串转boolean: true
注意:Boolean.parseBoolean()不区分大小写,'True'、'TRUE'都有效

## 6.4 本章总结与练习

### 本章核心要点总结

#### 1. 字符串类(String & StringBuffer)
- **String类**:不可变字符序列,适用于不频繁修改的字符串操作
  - 常用方法:`length()`、`charAt()`、`substring()`、`indexOf()`、`equals()`、`split()`等
  - 易错点:使用`==`比较内容、循环中频繁拼接、忽略不可变性
- **StringBuffer类**:可变字符序列,线程安全,适用于频繁修改的字符串
  - 常用方法:`append()`、`insert()`、`delete()`、`reverse()`、`toString()`
  - 与StringBuilder区别:StringBuffer线程安全,StringBuilder非线程安全但性能更好
- **正则表达式**:强大的字符串模式匹配工具
  - 核心类:`Pattern`(编译正则)、`Matcher`(执行匹配)
  - 常用方法:`matches()`、`find()`、`group()`、`replaceAll()`
  - 易错点:特殊字符转义、贪婪/非贪婪匹配、性能优化

#### 2. 数据类型包装器类
- **包装器类作用**:将基本数据类型封装为对象,实现面向对象操作
- **8种基本类型对应包装器**:Byte、Short、Integer、Long、Float、Double、Character、Boolean
- **核心转换方法**:
  - 字符串转基本类型:`parseXxx()`(如`Integer.parseInt()`)
  - 字符串转包装器对象:`valueOf()`(如`Integer.valueOf()`)
  - 基本类型转字符串:`toString()`、`String.valueOf()`、字符串拼接
- **自动装箱与拆箱**:Java自动在基本类型和包装器类型间转换
- **比较注意事项**:包装器对象比较应使用`equals()`而非`==`(缓存范围外)

#### 3. 核心编程思想
- **不可变对象优势**:线程安全、缓存友好、适合作为Map键
- **可变对象适用场景**:频繁修改、性能敏感的操作
- **异常处理**:转换失败时正确处理`NumberFormatException`
- **性能优化**:避免在循环中重复创建对象、编译正则表达式

### 编程练习题

#### 练习题1:统计字符串中每个字符出现的次数

**题目要求:**
编写一个方法`countCharacters(String str)`,统计给定字符串中每个字符出现的次数(区分大小写),并返回一个Map<Character, Integer>。

**示例输入输出:**

输入: “Hello World”
输出: {H=1, e=1, l=3, o=2, =1, W=1, r=1, d=1}


**参考实现:**
```java
import java.util.HashMap;
import java.util.Map;

public class CharacterCounter {
    public static Map<Character, Integer> countCharacters(String str) {
        Map<Character, Integer> charCount = new HashMap<>();
        
        // 遍历字符串中的每个字符
        for (int i = 0; i < str.length(); i++) {
            char ch = str.charAt(i);
            
            // 如果字符已存在,计数加1;否则初始化为1
            if (charCount.containsKey(ch)) {
                charCount.put(ch, charCount.get(ch) + 1);
            } else {
                charCount.put(ch, 1);
            }
        }
        
        return charCount;
    }
    
    public static void main(String[] args) {
        String testStr = "Hello World";
        Map<Character, Integer> result = countCharacters(testStr);
        
        System.out.println("字符串: \"" + testStr + "\"");
        System.out.println("字符统计结果:");
        for (Map.Entry<Character, Integer> entry : result.entrySet()) {
            char ch = entry.getKey();
            int count = entry.getValue();
            System.out.printf("  '%c' : %d次%n", ch, count);
        }
    }
}

运行结果:

字符串: "Hello World"
字符统计结果:
  'H' : 1次
  'e' : 1次
  'l' : 3次
  'o' : 2次
  ' ' : 1次
  'W' : 1次
  'r' : 1次
  'd' : 1次

扩展挑战:

  1. 修改方法,使其不区分大小写(将字符统一转为小写)
  2. 只统计字母字符,忽略空格和标点符号
  3. 按字符出现次数降序排序输出
练习题3:字符串处理综合应用

题目要求:
编写一个程序,实现以下功能:

  1. 从用户输入读取一段文本
  2. 统计文本中的单词数量(以空格分隔)
  3. 找出出现频率最高的3个单词
  4. 将所有数字替换为"[NUMBER]"
  5. 将处理后的文本保存到文件

提示:

  • 使用Scanner类读取用户输入
  • 使用String.split()方法分割单词
  • 使用Map<String, Integer>统计词频
  • 使用正则表达式\\d+匹配数字
  • 使用FileWriterBufferedWriter写入文件

学习建议

  1. 动手实践:亲自编写并运行所有示例代码,理解每个API的用法
  2. 调试技巧:使用IDE的调试功能,观察字符串和包装器对象在内存中的变化
  3. 性能测试:对比String、StringBuffer、StringBuilder在不同场景下的性能差异
  4. 扩展学习:查阅Java官方文档,了解每个类的完整API列表
  5. 实际应用:尝试将所学知识应用到实际项目中,如用户输入验证、数据清洗等

通过本章学习,你应该掌握了Java标准类库中字符串和包装器类的核心用法,能够熟练处理字符串操作、正则表达式匹配以及数据类型转换等常见任务。这些知识是Java编程的基础,将在后续的学习和开发中频繁使用。

更多推荐