Java常用API

Posted by Comet on May 15, 2025

Java常用API学习日志

Java常用API学习

本系列日志将记录Java常用API的学习过程,涵盖Java标准库中的核心API,包括字符串处理、集合框架、IO流、多线程、反射、注解、日期时间处理等常用功能。

学习目标

  • 掌握Java标准库中常用API的使用方法
  • 理解各种API的设计思想和适用场景
  • 熟练运用API解决实际编程问题
  • 了解API的性能特性和最佳实践
  • 为后续框架学习打下坚实基础

学习计划

  1. 字符串处理API:String、StringBuilder、StringBuffer、StringJoiner等
  2. 集合框架API:List、Set、Map及其实现类
  3. IO流API:字节流、字符流、缓冲流、转换流等
  4. 多线程API:Thread、Runnable、线程池、同步机制
  5. 反射与注解API:Class、Method、Field、注解处理器
  6. 日期时间API:Date、Calendar、LocalDateTime、DateTimeFormatter
  7. 工具类API:Arrays、Collections、Objects、Optional等
  8. 大数运算:BigInteger、BigDecimal
  9. 正则表达式:Pattern、Matcher、常用正则模式
  10. 包装类:Integer、Character、自动装箱拆箱
  11. Lambda表达式:函数式接口、Stream API、方法引用
  12. Apache Commons IO:FileUtils、IOUtils、文件操作
  13. Hutool工具库:StrUtil、DateUtil、CollUtil、HttpUtil、JSONUtil
  14. 网络编程API:Socket、URL、HTTP客户端等

学习内容

1. 字符串处理API

1.1 String类常用方法

字符串创建与基本操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 字符串创建
String str1 = "Hello";
String str2 = new String("World");
String str3 = String.valueOf(123);

// 基本操作
String str = "Hello World";
int length = str.length();           // 获取长度
char ch = str.charAt(0);            // 获取字符
String sub = str.substring(0, 5);   // 截取子串
String upper = str.toUpperCase();    // 转大写
String lower = str.toLowerCase();    // 转小写

// 输出结果
System.out.println("str1: " + str1);           // 输出: str1: Hello
System.out.println("str2: " + str2);           // 输出: str2: World
System.out.println("str3: " + str3);           // 输出: str3: 123
System.out.println("length: " + length);       // 输出: length: 11
System.out.println("ch: " + ch);               // 输出: ch: H
System.out.println("sub: " + sub);             // 输出: sub: Hello
System.out.println("upper: " + upper);         // 输出: upper: HELLO WORLD
System.out.println("lower: " + lower);         // 输出: lower: hello world

字符串查找与替换:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
String str = "Hello World";
boolean contains = str.contains("World");    // 是否包含
int index = str.indexOf("o");               // 查找字符位置
int lastIndex = str.lastIndexOf("o");       // 从后查找
String replaced = str.replace("World", "Java"); // 替换
String[] parts = str.split(" ");            // 分割

// 输出结果
System.out.println("contains: " + contains);     // 输出: contains: true
System.out.println("index: " + index);           // 输出: index: 4
System.out.println("lastIndex: " + lastIndex);   // 输出: lastIndex: 7
System.out.println("replaced: " + replaced);     // 输出: replaced: Hello Java
System.out.println("parts[0]: " + parts[0]);     // 输出: parts[0]: Hello
System.out.println("parts[1]: " + parts[1]);     // 输出: parts[1]: World

字符串比较:

1
2
3
4
5
6
7
8
9
10
String s1 = "Hello";
String s2 = "hello";
boolean equals = s1.equals(s2);             // 内容比较
boolean ignoreCase = s1.equalsIgnoreCase(s2); // 忽略大小写比较
int compare = s1.compareTo(s2);             // 字典序比较

// 输出结果
System.out.println("equals: " + equals);           // 输出: equals: false
System.out.println("ignoreCase: " + ignoreCase);   // 输出: ignoreCase: true
System.out.println("compare: " + compare);         // 输出: compare: -32 (H的ASCII码比h小32)
1.2 StringBuilder与StringBuffer

StringBuilder(非线程安全):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
StringBuilder sb = new StringBuilder();
sb.append("Hello");
sb.append(" ");
sb.append("World");
String result = sb.toString();

// 链式调用
StringBuilder sb2 = new StringBuilder()
    .append("Hello")
    .append(" ")
    .append("World");

// 输出结果
System.out.println("result: " + result);           // 输出: result: Hello World
System.out.println("sb2: " + sb2.toString());      // 输出: sb2: Hello World

StringBuffer(线程安全):

1
2
3
4
5
6
7
8
StringBuffer buffer = new StringBuffer();
buffer.append("Hello");
buffer.append(" ");
buffer.append("World");
String result = buffer.toString();

// 输出结果
System.out.println("result: " + result);           // 输出: result: Hello World

常用方法:

1
2
3
4
5
6
7
8
9
10
11
12
StringBuilder sb = new StringBuilder("Hello");
sb.insert(5, " World");     // 插入
System.out.println("insert: " + sb);               // 输出: insert: Hello World

sb.delete(5, 11);           // 删除
System.out.println("delete: " + sb);               // 输出: delete: Hello

sb.reverse();               // 反转
System.out.println("reverse: " + sb);              // 输出: reverse: olleH

sb.setCharAt(0, 'h');      // 设置字符
System.out.println("setCharAt: " + sb);            // 输出: setCharAt: hlleH
1.3 StringJoiner

基本使用:

1
2
3
4
5
6
7
8
StringJoiner joiner = new StringJoiner(", ", "[", "]");
joiner.add("Apple");
joiner.add("Banana");
joiner.add("Orange");
String result = joiner.toString();

// 输出结果
System.out.println("result: " + result);           // 输出: result: [Apple, Banana, Orange]

简化字符串拼接:

1
2
3
4
5
String[] names = {"Alice", "Bob", "Charlie"};
String result = String.join(", ", names);

// 输出结果
System.out.println("result: " + result);           // 输出: result: Alice, Bob, Charlie

2. 集合框架API

2.1 List接口及实现

ArrayList(动态数组):

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
List<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.add("Orange");

// 遍历方式
System.out.println("=== 遍历方式 ===");
for (String item : list) {
    System.out.println(item);
}
// 输出:
// Apple
// Banana
// Orange

list.forEach(System.out::println);
// 输出:
// Apple
// Banana
// Orange

// 常用操作
String first = list.get(0);                    // 获取元素
list.set(0, "Grape");                         // 设置元素
boolean contains = list.contains("Apple");     // 是否包含
int size = list.size();                       // 大小

// 输出结果
System.out.println("first: " + first);         // 输出: first: Apple
System.out.println("contains Apple: " + contains); // 输出: contains Apple: false
System.out.println("size: " + size);           // 输出: size: 3
System.out.println("list after set: " + list); // 输出: list after set: [Grape, Banana, Orange]

LinkedList(链表):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
LinkedList<String> linkedList = new LinkedList<>();
linkedList.addFirst("First");   // 头部添加
linkedList.addLast("Last");     // 尾部添加
linkedList.add("Middle");       // 中间添加

// 输出结果
System.out.println("linkedList: " + linkedList); // 输出: linkedList: [First, Middle, Last]

String first = linkedList.removeFirst();       // 头部删除
String last = linkedList.removeLast();        // 尾部删除
String peek = linkedList.peek();              // 查看头部元素

// 输出结果
System.out.println("removed first: " + first); // 输出: removed first: First
System.out.println("removed last: " + last);   // 输出: removed last: Last
System.out.println("peek: " + peek);           // 输出: peek: Middle
System.out.println("final list: " + linkedList); // 输出: final list: [Middle]
2.2 Set接口及实现

HashSet(哈希集合):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Set<String> set = new HashSet<>();
set.add("Apple");
set.add("Banana");
set.add("Apple"); // 重复元素不会添加

// 遍历
System.out.println("=== HashSet遍历 ===");
set.forEach(System.out::println);
// 输出:
// Apple
// Banana

// 常用操作
boolean contains = set.contains("Apple");          // 是否包含
boolean removed = set.remove("Apple");            // 删除
int size = set.size();                            // 大小

// 输出结果
System.out.println("contains Apple: " + contains); // 输出: contains Apple: true
System.out.println("removed Apple: " + removed);   // 输出: removed Apple: true
System.out.println("size: " + size);               // 输出: size: 1
System.out.println("final set: " + set);           // 输出: final set: [Banana]

TreeSet(有序集合):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
TreeSet<String> treeSet = new TreeSet<>();
treeSet.add("Zebra");
treeSet.add("Apple");
treeSet.add("Banana");
// 自动排序:Apple, Banana, Zebra

// 输出结果
System.out.println("treeSet: " + treeSet); // 输出: treeSet: [Apple, Banana, Zebra]

// 获取第一个和最后一个
String first = treeSet.first();
String last = treeSet.last();

// 输出结果
System.out.println("first: " + first); // 输出: first: Apple
System.out.println("last: " + last);   // 输出: last: Zebra
2.3 Map接口及实现

HashMap(哈希映射):

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
Map<String, Integer> map = new HashMap<>();
map.put("Apple", 1);
map.put("Banana", 2);
map.put("Orange", 3);

// 遍历方式
System.out.println("=== HashMap遍历 ===");
map.forEach((key, value) -> 
    System.out.println(key + ": " + value));
// 输出:
// Apple: 1
// Banana: 2
// Orange: 3

for (Map.Entry<String, Integer> entry : map.entrySet()) {
    System.out.println(entry.getKey() + " -> " + entry.getValue());
}
// 输出:
// Apple -> 1
// Banana -> 2
// Orange -> 3

// 常用操作
Integer appleValue = map.get("Apple");              // 获取值
boolean containsKey = map.containsKey("Apple");     // 是否包含键
boolean containsValue = map.containsValue(1);       // 是否包含值
Integer removed = map.remove("Apple");              // 删除

// 输出结果
System.out.println("appleValue: " + appleValue);           // 输出: appleValue: 1
System.out.println("containsKey Apple: " + containsKey);   // 输出: containsKey Apple: true
System.out.println("containsValue 1: " + containsValue);   // 输出: containsValue 1: true
System.out.println("removed: " + removed);                 // 输出: removed: 1
System.out.println("final map: " + map);                   // 输出: final map: {Banana=2, Orange=3}

TreeMap(有序映射):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
TreeMap<String, Integer> treeMap = new TreeMap<>();
treeMap.put("Zebra", 3);
treeMap.put("Apple", 1);
treeMap.put("Banana", 2);
// 按键自动排序

// 输出结果
System.out.println("treeMap: " + treeMap); // 输出: treeMap: {Apple=1, Banana=2, Zebra=3}

// 获取第一个和最后一个
Map.Entry<String, Integer> first = treeMap.firstEntry();
Map.Entry<String, Integer> last = treeMap.lastEntry();

// 输出结果
System.out.println("first: " + first.getKey() + "=" + first.getValue()); // 输出: first: Apple=1
System.out.println("last: " + last.getKey() + "=" + last.getValue());   // 输出: last: Zebra=3

3. IO流API

3.1 字节流

FileInputStream(文件输入流):

1
2
3
4
5
6
7
8
9
10
try (FileInputStream fis = new FileInputStream("input.txt")) {
    byte[] buffer = new byte[1024];
    int bytesRead;
    while ((bytesRead = fis.read(buffer)) != -1) {
        // 处理读取的数据
        System.out.write(buffer, 0, bytesRead);
    }
} catch (IOException e) {
    e.printStackTrace();
}

FileOutputStream(文件输出流):

1
2
3
4
5
6
try (FileOutputStream fos = new FileOutputStream("output.txt")) {
    String data = "Hello World";
    fos.write(data.getBytes());
} catch (IOException e) {
    e.printStackTrace();
}
3.2 字符流

FileReader(文件字符输入流):

1
2
3
4
5
6
7
8
9
try (FileReader reader = new FileReader("input.txt")) {
    char[] buffer = new char[1024];
    int charsRead;
    while ((charsRead = reader.read(buffer)) != -1) {
        System.out.print(new String(buffer, 0, charsRead));
    }
} catch (IOException e) {
    e.printStackTrace();
}

FileWriter(文件字符输出流):

1
2
3
4
5
try (FileWriter writer = new FileWriter("output.txt")) {
    writer.write("Hello World");
} catch (IOException e) {
    e.printStackTrace();
}
3.3 缓冲流

BufferedReader(缓冲字符输入流):

1
2
3
4
5
6
7
8
9
try (BufferedReader reader = new BufferedReader(
        new FileReader("input.txt"))) {
    String line;
    while ((line = reader.readLine()) != null) {
        System.out.println(line);
    }
} catch (IOException e) {
    e.printStackTrace();
}

BufferedWriter(缓冲字符输出流):

1
2
3
4
5
6
7
8
try (BufferedWriter writer = new BufferedWriter(
        new FileWriter("output.txt"))) {
    writer.write("Line 1");
    writer.newLine();
    writer.write("Line 2");
} catch (IOException e) {
    e.printStackTrace();
}

4. 多线程API

4.1 线程创建

继承Thread类:

1
2
3
4
5
6
7
8
9
10
class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("Thread running: " + Thread.currentThread().getName());
    }
}

// 使用
MyThread thread = new MyThread();
thread.start();

实现Runnable接口:

1
2
3
4
5
6
7
8
9
10
class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("Runnable running: " + Thread.currentThread().getName());
    }
}

// 使用
Thread thread = new Thread(new MyRunnable());
thread.start();

Lambda表达式:

1
2
3
4
Thread thread = new Thread(() -> {
    System.out.println("Lambda thread running");
});
thread.start();
4.2 线程控制

基本控制:

1
2
3
4
5
6
7
8
9
10
11
12
13
Thread thread = new Thread(() -> {
    for (int i = 0; i < 5; i++) {
        System.out.println("Count: " + i);
        try {
            Thread.sleep(1000); // 休眠1秒
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
});

thread.start();
thread.join(); // 等待线程结束

线程状态:

1
2
3
4
5
6
7
Thread thread = new Thread(() -> {
    // 线程任务
});

System.out.println("State: " + thread.getState()); // NEW
thread.start();
System.out.println("State: " + thread.getState()); // RUNNABLE
4.3 线程同步

synchronized关键字:

1
2
3
4
5
6
7
8
9
10
11
class Counter {
    private int count = 0;
    
    public synchronized void increment() {
        count++;
    }
    
    public synchronized int getCount() {
        return count;
    }
}

ReentrantLock:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import java.util.concurrent.locks.ReentrantLock;

class Counter {
    private int count = 0;
    private ReentrantLock lock = new ReentrantLock();
    
    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }
}

5. 反射与注解API

5.1 反射基础

获取Class对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 方式1:通过类名
Class<?> clazz1 = String.class;

// 方式2:通过对象
String str = "Hello";
Class<?> clazz2 = str.getClass();

// 方式3:通过全限定名
try {
    Class<?> clazz3 = Class.forName("java.lang.String");
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}

获取构造方法:

1
2
3
4
5
6
7
8
9
10
11
12
Class<?> clazz = String.class;

// 获取所有公共构造方法
Constructor<?>[] constructors = clazz.getConstructors();

// 获取指定构造方法
try {
    Constructor<?> constructor = clazz.getConstructor(String.class);
    String obj = (String) constructor.newInstance("Hello");
} catch (Exception e) {
    e.printStackTrace();
}

获取方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Class<?> clazz = String.class;

// 获取所有公共方法
Method[] methods = clazz.getMethods();

// 获取指定方法
try {
    Method method = clazz.getMethod("length");
    String str = "Hello";
    int length = (int) method.invoke(str);
    System.out.println("Length: " + length);
} catch (Exception e) {
    e.printStackTrace();
}

获取字段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Person {
    private String name;
    public int age;
}

Class<?> clazz = Person.class;

// 获取所有公共字段
Field[] fields = clazz.getFields();

// 获取所有字段(包括私有)
Field[] allFields = clazz.getDeclaredFields();

// 访问私有字段
try {
    Field nameField = clazz.getDeclaredField("name");
    nameField.setAccessible(true); // 设置可访问
    Person person = new Person();
    nameField.set(person, "Alice");
    String name = (String) nameField.get(person);
} catch (Exception e) {
    e.printStackTrace();
}
5.2 注解使用

自定义注解:

1
2
3
4
5
6
7
8
9
import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAnnotation {
    String value() default "";
    int count() default 1;
}

使用注解:

1
2
3
4
5
6
class TestClass {
    @MyAnnotation(value = "test", count = 3)
    public void testMethod() {
        System.out.println("Test method");
    }
}

注解处理器:

1
2
3
4
5
6
7
8
9
10
Class<?> clazz = TestClass.class;
Method[] methods = clazz.getMethods();

for (Method method : methods) {
    if (method.isAnnotationPresent(MyAnnotation.class)) {
        MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
        System.out.println("Value: " + annotation.value());
        System.out.println("Count: " + annotation.count());
    }
}

6. 日期时间API

6.1 新日期时间API(Java 8+)

LocalDate(日期):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

LocalDate today = LocalDate.now();
LocalDate specificDate = LocalDate.of(2025, 5, 15);

// 日期操作
LocalDate tomorrow = today.plusDays(1);
LocalDate yesterday = today.minusDays(1);
LocalDate nextMonth = today.plusMonths(1);

// 格式化
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
String formatted = today.format(formatter);
LocalDate parsed = LocalDate.parse("2025-05-15", formatter);

LocalTime(时间):

1
2
3
4
5
6
7
8
9
10
11
12
import java.time.LocalTime;

LocalTime now = LocalTime.now();
LocalTime specificTime = LocalTime.of(14, 30, 45);

// 时间操作
LocalTime plusHours = now.plusHours(2);
LocalTime minusMinutes = now.minusMinutes(30);

// 格式化
DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss");
String formatted = now.format(timeFormatter);

LocalDateTime(日期时间):

1
2
3
4
5
6
7
8
9
10
11
12
import java.time.LocalDateTime;

LocalDateTime now = LocalDateTime.now();
LocalDateTime specific = LocalDateTime.of(2025, 5, 15, 14, 30, 45);

// 日期时间操作
LocalDateTime plusDays = now.plusDays(1);
LocalDateTime minusHours = now.minusHours(2);

// 格式化
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formatted = now.format(formatter);
6.2 传统日期时间API

Date类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import java.util.Date;
import java.text.SimpleDateFormat;

Date now = new Date();
Date specific = new Date(2025 - 1900, 4, 15); // 月份从0开始

// 格式化
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String formatted = sdf.format(now);

// 解析
try {
    Date parsed = sdf.parse("2025-05-15 14:30:45");
} catch (ParseException e) {
    e.printStackTrace();
}

Calendar类:

1
2
3
4
5
6
7
8
9
10
11
12
13
import java.util.Calendar;

Calendar cal = Calendar.getInstance();
cal.set(2025, Calendar.MAY, 15); // 月份从0开始

// 获取字段
int year = cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH);
int day = cal.get(Calendar.DAY_OF_MONTH);

// 操作
cal.add(Calendar.DAY_OF_MONTH, 1); // 加一天
cal.add(Calendar.MONTH, 1);        // 加一月

7. 工具类API

7.1 Arrays工具类

数组操作:

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

int[] arr = {3, 1, 4, 1, 5, 9, 2, 6};

// 排序
Arrays.sort(arr);
System.out.println("sorted: " + Arrays.toString(arr)); // 输出: sorted: [1, 1, 2, 3, 4, 5, 6, 9]

// 二分查找(需要先排序)
int index = Arrays.binarySearch(arr, 5);
System.out.println("index of 5: " + index); // 输出: index of 5: 5

// 填充
Arrays.fill(arr, 0);
System.out.println("filled: " + Arrays.toString(arr)); // 输出: filled: [0, 0, 0, 0, 0, 0, 0, 0]

// 复制
int[] original = {1, 2, 3, 4, 5};
int[] copy = Arrays.copyOf(original, original.length);
System.out.println("copy: " + Arrays.toString(copy)); // 输出: copy: [1, 2, 3, 4, 5]

// 比较
boolean equals = Arrays.equals(original, copy);
System.out.println("equals: " + equals); // 输出: equals: true

// 转换为字符串
String str = Arrays.toString(original);
System.out.println("string: " + str); // 输出: string: [1, 2, 3, 4, 5]
7.2 Collections工具类

集合操作:

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
import java.util.*;

List<String> list = Arrays.asList("Apple", "Banana", "Orange");

// 排序
Collections.sort(list);
System.out.println("sorted: " + list); // 输出: sorted: [Apple, Banana, Orange]

// 反转
Collections.reverse(list);
System.out.println("reversed: " + list); // 输出: reversed: [Orange, Banana, Apple]

// 随机打乱
Collections.shuffle(list);
System.out.println("shuffled: " + list); // 输出: shuffled: [Banana, Apple, Orange] (顺序随机)

// 查找最大最小值
String max = Collections.max(list);
String min = Collections.min(list);
System.out.println("max: " + max); // 输出: max: Orange
System.out.println("min: " + min); // 输出: min: Apple

// 替换
Collections.replaceAll(list, "Apple", "Grape");
System.out.println("replaced: " + list); // 输出: replaced: [Banana, Grape, Orange]

// 频率统计
int frequency = Collections.frequency(list, "Banana");
System.out.println("frequency of Banana: " + frequency); // 输出: frequency of Banana: 1
7.3 Objects工具类

对象操作:

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
import java.util.Objects;

String str = null;

// 空值检查
boolean isNull = Objects.isNull(str);
boolean nonNull = Objects.nonNull(str);
System.out.println("isNull: " + isNull);     // 输出: isNull: true
System.out.println("nonNull: " + nonNull);   // 输出: nonNull: false

// 相等性比较
boolean equals = Objects.equals("Hello", "Hello");
boolean equalsNull = Objects.equals(null, null);
System.out.println("equals: " + equals);         // 输出: equals: true
System.out.println("equalsNull: " + equalsNull); // 输出: equalsNull: true

// 哈希码
int hashCode = Objects.hash("Hello", "World");
System.out.println("hashCode: " + hashCode); // 输出: hashCode: 123456789 (具体值可能不同)

// 要求非空
try {
    String result = Objects.requireNonNull(str, "String cannot be null");
} catch (NullPointerException e) {
    System.out.println("Exception: " + e.getMessage()); // 输出: Exception: String cannot be null
}
7.4 Optional类

空值安全处理:

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
import java.util.Optional;

String str = "Hello";
Optional<String> optional = Optional.of(str);

// 安全获取值
String value = optional.orElse("Default");
System.out.println("value: " + value); // 输出: value: Hello

// 条件处理
optional.ifPresent(System.out::println); // 输出: Hello

// 链式操作
Optional<String> result = optional
    .map(s -> s.toUpperCase())
    .filter(s -> s.length() > 3);
System.out.println("result: " + result.get()); // 输出: result: HELLO

// 创建Optional
Optional<String> empty = Optional.empty();
Optional<String> ofNullable = Optional.ofNullable(str);

// 处理空Optional
String emptyValue = empty.orElse("Empty");
System.out.println("emptyValue: " + emptyValue); // 输出: emptyValue: Empty
7.5 Math类

数学运算方法:

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
62
63
64
65
66
import java.lang.Math;

// 基本数学运算
double abs = Math.abs(-5.5);        // 绝对值
double ceil = Math.ceil(5.3);       // 向上取整
double floor = Math.floor(5.7);     // 向下取整
double round = Math.round(5.5);     // 四舍五入
double max = Math.max(10, 20);      // 最大值
double min = Math.min(10, 20);      // 最小值

// 输出结果
System.out.println("abs(-5.5): " + abs);     // 输出: abs(-5.5): 5.5
System.out.println("ceil(5.3): " + ceil);    // 输出: ceil(5.3): 6.0
System.out.println("floor(5.7): " + floor);  // 输出: floor(5.7): 5.0
System.out.println("round(5.5): " + round);  // 输出: round(5.5): 6.0
System.out.println("max(10,20): " + max);    // 输出: max(10,20): 20.0
System.out.println("min(10,20): " + min);    // 输出: min(10,20): 10.0

// 幂运算
double pow = Math.pow(2, 3);        // 2的3次方
double sqrt = Math.sqrt(16);        // 平方根
double cbrt = Math.cbrt(27);        // 立方根

// 输出结果
System.out.println("pow(2,3): " + pow);   // 输出: pow(2,3): 8.0
System.out.println("sqrt(16): " + sqrt);  // 输出: sqrt(16): 4.0
System.out.println("cbrt(27): " + cbrt);  // 输出: cbrt(27): 3.0

// 三角函数(参数为弧度)
double sin = Math.sin(Math.PI / 2); // 正弦
double cos = Math.cos(0);           // 余弦
double tan = Math.tan(Math.PI / 4); // 正切

// 输出结果
System.out.println("sin(π/2): " + sin);   // 输出: sin(π/2): 1.0
System.out.println("cos(0): " + cos);     // 输出: cos(0): 1.0
System.out.println("tan(π/4): " + tan);   // 输出: tan(π/4): 1.0

// 反三角函数
double asin = Math.asin(1.0);       // 反正弦
double acos = Math.acos(1.0);       // 反余弦
double atan = Math.atan(1.0);       // 反正切

// 角度与弧度转换
double toRadians = Math.toRadians(180); // 角度转弧度
double toDegrees = Math.toDegrees(Math.PI); // 弧度转角度

// 对数函数
double log = Math.log(Math.E);      // 自然对数
double log10 = Math.log10(100);     // 常用对数

// 随机数
double random = Math.random();       // 0.0到1.0之间的随机数
int randomInt = (int)(Math.random() * 100); // 0到99的随机整数

// 输出结果
System.out.println("random: " + random);     // 输出: random: 0.123456789 (具体值随机)
System.out.println("randomInt: " + randomInt); // 输出: randomInt: 45 (具体值随机)

// 常量
double pi = Math.PI;                // 圆周率
double e = Math.E;                  // 自然对数的底

// 输出结果
System.out.println("π: " + pi);     // 输出: π: 3.141592653589793
System.out.println("e: " + e);      // 输出: e: 2.718281828459045

Math类的常用场景:

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
// 生成指定范围的随机数
public static int randomRange(int min, int max) {
    return (int)(Math.random() * (max - min + 1)) + min;
}

// 计算两点间距离
public static double distance(double x1, double y1, double x2, double y2) {
    return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
}

// 判断是否为素数
public static boolean isPrime(int n) {
    if (n <= 1) return false;
    if (n <= 3) return true;
    if (n % 2 == 0 || n % 3 == 0) return false;
    
    int sqrt = (int)Math.sqrt(n);
    for (int i = 5; i <= sqrt; i += 6) {
        if (n % i == 0 || n % (i + 2) == 0) return false;
    }
    return true;
}

// 计算圆的面积
public static double circleArea(double radius) {
    return Math.PI * Math.pow(radius, 2);
}

// 计算球的体积
public static double sphereVolume(double radius) {
    return (4.0 / 3.0) * Math.PI * Math.pow(radius, 3);
}

Math类的注意事项:

  • Math类中的所有方法都是静态的,可以直接通过类名调用
  • 三角函数参数为弧度,不是角度
  • Math.random()生成的是伪随机数,对于需要高安全性的场景应使用SecureRandom
  • 浮点数运算可能存在精度问题,需要特别注意比较操作
7.6 System类

系统相关操作:

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
import java.lang.System;

// 获取当前时间戳
long currentTime = System.currentTimeMillis();  // 毫秒时间戳
long nanoTime = System.nanoTime();              // 纳秒时间戳

// 输出结果
System.out.println("currentTime: " + currentTime); // 输出: currentTime: 1640995200000 (具体值不同)
System.out.println("nanoTime: " + nanoTime);       // 输出: nanoTime: 1234567890123456789 (具体值不同)

// 系统属性
String osName = System.getProperty("os.name");           // 操作系统名称
String javaVersion = System.getProperty("java.version"); // Java版本
String userHome = System.getProperty("user.home");       // 用户主目录

// 输出结果
System.out.println("osName: " + osName);         // 输出: osName: Windows 10 (或Linux、macOS等)
System.out.println("javaVersion: " + javaVersion); // 输出: javaVersion: 17.0.1 (具体版本不同)
System.out.println("userHome: " + userHome);     // 输出: userHome: C:\Users\username (具体路径不同)

// 数组复制
int[] source = {1, 2, 3, 4, 5};
int[] dest = new int[5];
System.arraycopy(source, 0, dest, 0, source.length);
System.out.println("dest: " + Arrays.toString(dest)); // 输出: dest: [1, 2, 3, 4, 5]

// 垃圾回收
System.gc();  // 建议进行垃圾回收

// 程序退出
// System.exit(0);  // 正常退出
// System.exit(1);  // 异常退出

// 安全检查
SecurityManager sm = System.getSecurityManager();

System.out输出流:

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
// 标准输出
System.out.println("Hello World");                    // 输出: Hello World
System.out.print("不换行输出");                        // 输出: 不换行输出
System.out.printf("格式化输出: %s, %d", "字符串", 123); // 输出: 格式化输出: 字符串, 123

// 输出格式控制
System.out.printf("整数: %d%n", 100);                 // 输出: 整数: 100
System.out.printf("浮点数: %.2f%n", 3.14159);         // 输出: 浮点数: 3.14
System.out.printf("字符串: %s%n", "Java");            // 输出: 字符串: Java
System.out.printf("字符: %c%n", 'A');                 // 输出: 字符: A
System.out.printf("布尔值: %b%n", true);              // 输出: 布尔值: true
System.out.printf("十六进制: %x%n", 255);             // 输出: 十六进制: ff
System.out.printf("八进制: %o%n", 255);               // 输出: 八进制: 377

// 重定向输出流
PrintStream originalOut = System.out;
try {
    // 重定向到文件
    PrintStream fileOut = new PrintStream("output.txt");
    System.setOut(fileOut);
    System.out.println("这条消息会写入文件");
} finally {
    // 恢复原始输出流
    System.setOut(originalOut);
}

System.in输入流:

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
// 标准输入
Scanner scanner = new Scanner(System.in);
System.out.print("请输入姓名: ");  // 输出: 请输入姓名: 
String name = scanner.nextLine();  // 等待用户输入
System.out.print("请输入年龄: ");  // 输出: 请输入年龄: 
int age = scanner.nextInt();       // 等待用户输入

// 输出结果
System.out.println("姓名: " + name); // 输出: 姓名: 张三 (用户输入的内容)
System.out.println("年龄: " + age);  // 输出: 年龄: 25 (用户输入的内容)

// 直接读取字节
try {
    System.out.print("请输入一个字符: "); // 输出: 请输入一个字符: 
    int ch = System.in.read();
    System.out.println("输入的字符: " + (char)ch); // 输出: 输入的字符: A (用户输入的内容)
} catch (IOException e) {
    e.printStackTrace();
}

// 重定向输入流
try {
    // 从文件读取输入
    FileInputStream fileIn = new FileInputStream("input.txt");
    System.setIn(fileIn);
    Scanner fileScanner = new Scanner(System.in);
    while (fileScanner.hasNextLine()) {
        String line = fileScanner.nextLine();
        System.out.println("从文件读取: " + line); // 输出: 从文件读取: 文件内容
    }
} catch (FileNotFoundException e) {
    e.printStackTrace();
}

System.err错误输出流:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 错误输出
System.err.println("这是一个错误消息");                    // 输出: 这是一个错误消息 (红色错误输出)
System.err.print("错误信息不换行");                        // 输出: 错误信息不换行 (红色错误输出)

// 格式化错误输出
System.err.printf("错误代码: %d, 错误信息: %s%n", 404, "页面未找到"); 
// 输出: 错误代码: 404, 错误信息: 页面未找到 (红色错误输出)

// 重定向错误流
PrintStream originalErr = System.err;
try {
    PrintStream errorFile = new PrintStream("error.log");
    System.setErr(errorFile);
    System.err.println("错误日志会写入文件");
} finally {
    System.setErr(originalErr);
}

System类的实用工具方法:

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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
public class SystemUtils {
    
    // 获取系统信息
    public static void printSystemInfo() {
        System.out.println("操作系统: " + System.getProperty("os.name"));
        System.out.println("Java版本: " + System.getProperty("java.version"));
        System.out.println("Java供应商: " + System.getProperty("java.vendor"));
        System.out.println("JVM版本: " + System.getProperty("java.vm.version"));
        System.out.println("用户目录: " + System.getProperty("user.dir"));
        System.out.println("用户主目录: " + System.getProperty("user.home"));
    }
    
    // 性能测试工具
    public static void performanceTest(Runnable task, String taskName) {
        long startTime = System.currentTimeMillis();
        long startNano = System.nanoTime();
        
        task.run();
        
        long endTime = System.currentTimeMillis();
        long endNano = System.nanoTime();
        
        System.out.println(taskName + " 执行时间:");
        System.out.println("  毫秒: " + (endTime - startTime) + "ms");
        System.out.println("  纳秒: " + (endNano - startNano) + "ns");
    }
    
    // 内存使用情况
    public static void printMemoryInfo() {
        Runtime runtime = Runtime.getRuntime();
        long totalMemory = runtime.totalMemory();
        long freeMemory = runtime.freeMemory();
        long usedMemory = totalMemory - freeMemory;
        long maxMemory = runtime.maxMemory();
        
        System.out.println("内存使用情况:");
        System.out.println("  总内存: " + (totalMemory / 1024 / 1024) + "MB");
        System.out.println("  已用内存: " + (usedMemory / 1024 / 1024) + "MB");
        System.out.println("  空闲内存: " + (freeMemory / 1024 / 1024) + "MB");
        System.out.println("  最大内存: " + (maxMemory / 1024 / 1024) + "MB");
    }
    
    // 安全退出程序
    public static void safeExit(int code) {
        System.out.println("程序即将退出,代码: " + code);
        System.gc();  // 建议垃圾回收
        System.exit(code);
    }
}

// 使用示例
public class SystemUtilsExample {
    public static void main(String[] args) {
        // 获取系统信息
        SystemUtils.printSystemInfo();
        // 输出:
        // 操作系统: Windows 10
        // Java版本: 17.0.1
        // Java供应商: Oracle Corporation
        // JVM版本: 17.0.1+12-LTS-39
        // 用户目录: C:\Users\username\project
        // 用户主目录: C:\Users\username
        
        // 性能测试
        SystemUtils.performanceTest(() -> {
            for (int i = 0; i < 1000000; i++) {
                Math.sqrt(i);
            }
        }, "计算平方根");
        // 输出:
        // 计算平方根 执行时间:
        //   毫秒: 15ms
        //   纳秒: 15000000ns
        
        // 内存使用情况
        SystemUtils.printMemoryInfo();
        // 输出:
        // 内存使用情况:
        //   总内存: 256MB
        //   已用内存: 45MB
        //   空闲内存: 211MB
        //   最大内存: 4096MB
    }
}

System类的注意事项:

  • System.currentTimeMillis()返回的是毫秒级时间戳,适合一般用途
  • System.nanoTime()返回纳秒级时间戳,适合高精度计时
  • System.exit()会强制终止JVM,谨慎使用
  • System.gc()只是建议进行垃圾回收,不保证立即执行
  • 重定向流后记得恢复原始流,避免影响其他代码
  • 系统属性是全局的,修改会影响整个JVM
7.7 BigInteger和BigDecimal

BigInteger(大整数):

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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import java.math.BigInteger;

// 创建BigInteger
BigInteger bigInt1 = new BigInteger("123456789012345678901234567890");
BigInteger bigInt2 = BigInteger.valueOf(123456789);
BigInteger bigInt3 = BigInteger.ONE;  // 常量1
BigInteger bigInt4 = BigInteger.ZERO; // 常量0
BigInteger bigInt5 = BigInteger.TEN;  // 常量10

// 输出结果
System.out.println("bigInt1: " + bigInt1); // 输出: bigInt1: 123456789012345678901234567890
System.out.println("bigInt2: " + bigInt2); // 输出: bigInt2: 123456789
System.out.println("bigInt3: " + bigInt3); // 输出: bigInt3: 1
System.out.println("bigInt4: " + bigInt4); // 输出: bigInt4: 0
System.out.println("bigInt5: " + bigInt5); // 输出: bigInt5: 10

// 基本运算
BigInteger a = new BigInteger("123456789");
BigInteger b = new BigInteger("987654321");

BigInteger sum = a.add(b);           // 加法
BigInteger diff = b.subtract(a);     // 减法
BigInteger product = a.multiply(b);  // 乘法
BigInteger quotient = b.divide(a);   // 除法
BigInteger remainder = b.remainder(a); // 取余

// 输出结果
System.out.println("sum: " + sum);           // 输出: sum: 1111111110
System.out.println("diff: " + diff);         // 输出: diff: 864197532
System.out.println("product: " + product);   // 输出: product: 121932631112635269
System.out.println("quotient: " + quotient); // 输出: quotient: 8
System.out.println("remainder: " + remainder); // 输出: remainder: 9

// 幂运算
BigInteger base = new BigInteger("2");
BigInteger power = base.pow(100); // 2的100次方
System.out.println("2^100: " + power); // 输出: 2^100: 1267650600228229401496703205376

// 比较操作
BigInteger x = new BigInteger("100");
BigInteger y = new BigInteger("200");
int compare = x.compareTo(y);
boolean equals = x.equals(y);
boolean isZero = x.equals(BigInteger.ZERO);
boolean isPositive = x.compareTo(BigInteger.ZERO) > 0;

// 输出结果
System.out.println("compare: " + compare);     // 输出: compare: -1 (x < y)
System.out.println("equals: " + equals);       // 输出: equals: false
System.out.println("isZero: " + isZero);       // 输出: isZero: false
System.out.println("isPositive: " + isPositive); // 输出: isPositive: true

// 位运算
BigInteger num = new BigInteger("42");
BigInteger and = num.and(new BigInteger("15"));    // 按位与
BigInteger or = num.or(new BigInteger("15"));      // 按位或
BigInteger xor = num.xor(new BigInteger("15"));    // 按位异或
BigInteger not = num.not();                        // 按位非
BigInteger shiftLeft = num.shiftLeft(2);           // 左移2位
BigInteger shiftRight = num.shiftRight(1);         // 右移1位

// 输出结果
System.out.println("and: " + and);           // 输出: and: 10
System.out.println("or: " + or);             // 输出: or: 47
System.out.println("xor: " + xor);           // 输出: xor: 37
System.out.println("not: " + not);           // 输出: not: -43
System.out.println("shiftLeft: " + shiftLeft);     // 输出: shiftLeft: 168
System.out.println("shiftRight: " + shiftRight);   // 输出: shiftRight: 21

// 素数测试
BigInteger prime = new BigInteger("17");
boolean isProbablePrime = prime.isProbablePrime(100); // 概率素数测试
System.out.println("isProbablePrime: " + isProbablePrime); // 输出: isProbablePrime: true

// 最大公约数和最小公倍数
BigInteger gcd = a.gcd(b); // 最大公约数
BigInteger lcm = a.multiply(b).divide(gcd); // 最小公倍数
System.out.println("gcd: " + gcd); // 输出: gcd: 3
System.out.println("lcm: " + lcm); // 输出: lcm: 40623982634538657907

// 转换为其他类型
int intValue = a.intValue();
long longValue = a.longValue();
String stringValue = a.toString();
String hexValue = a.toString(16); // 十六进制
String binaryValue = a.toString(2); // 二进制

// 输出结果
System.out.println("intValue: " + intValue);       // 输出: intValue: 123456789
System.out.println("longValue: " + longValue);     // 输出: longValue: 123456789
System.out.println("stringValue: " + stringValue); // 输出: stringValue: 123456789
System.out.println("hexValue: " + hexValue);       // 输出: hexValue: 75bcd15
System.out.println("binaryValue: " + binaryValue); // 输出: binaryValue: 111010110111100110100010101

BigDecimal(高精度小数):

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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import java.math.BigDecimal;
import java.math.RoundingMode;

// 创建BigDecimal
BigDecimal bd1 = new BigDecimal("3.141592653589793238462643383279");
BigDecimal bd2 = BigDecimal.valueOf(2.718281828459045);
BigDecimal bd3 = new BigDecimal("100.00");
BigDecimal bd4 = BigDecimal.ONE;   // 常量1
BigDecimal bd5 = BigDecimal.ZERO;  // 常量0
BigDecimal bd6 = BigDecimal.TEN;   // 常量10

// 输出结果
System.out.println("bd1: " + bd1); // 输出: bd1: 3.141592653589793238462643383279
System.out.println("bd2: " + bd2); // 输出: bd2: 2.718281828459045
System.out.println("bd3: " + bd3); // 输出: bd3: 100.00
System.out.println("bd4: " + bd4); // 输出: bd4: 1
System.out.println("bd5: " + bd5); // 输出: bd5: 0
System.out.println("bd6: " + bd6); // 输出: bd6: 10

// 基本运算
BigDecimal a = new BigDecimal("10.5");
BigDecimal b = new BigDecimal("3.2");

BigDecimal sum = a.add(b);           // 加法
BigDecimal diff = a.subtract(b);     // 减法
BigDecimal product = a.multiply(b);  // 乘法
BigDecimal quotient = a.divide(b, 10, RoundingMode.HALF_UP); // 除法,保留10位小数
BigDecimal remainder = a.remainder(b); // 取余

// 输出结果
System.out.println("sum: " + sum);           // 输出: sum: 13.7
System.out.println("diff: " + diff);         // 输出: diff: 7.3
System.out.println("product: " + product);   // 输出: product: 33.60
System.out.println("quotient: " + quotient); // 输出: quotient: 3.2812500000
System.out.println("remainder: " + remainder); // 输出: remainder: 0.9

// 幂运算
BigDecimal base = new BigDecimal("2.5");
BigDecimal power = base.pow(3); // 2.5的3次方
System.out.println("2.5^3: " + power); // 输出: 2.5^3: 15.625

// 比较操作
BigDecimal x = new BigDecimal("10.5");
BigDecimal y = new BigDecimal("10.50");
int compare = x.compareTo(y);
boolean equals = x.equals(y);
boolean isZero = x.equals(BigDecimal.ZERO);
boolean isPositive = x.compareTo(BigDecimal.ZERO) > 0;

// 输出结果
System.out.println("compare: " + compare);     // 输出: compare: 0 (x = y)
System.out.println("equals: " + equals);       // 输出: equals: false (精度不同)
System.out.println("isZero: " + isZero);       // 输出: isZero: false
System.out.println("isPositive: " + isPositive); // 输出: isPositive: true

// 精度控制
BigDecimal pi = new BigDecimal("3.141592653589793");
BigDecimal rounded = pi.setScale(2, RoundingMode.HALF_UP); // 保留2位小数
BigDecimal ceiling = pi.setScale(2, RoundingMode.CEILING); // 向上取整
BigDecimal floor = pi.setScale(2, RoundingMode.FLOOR);     // 向下取整

// 输出结果
System.out.println("rounded: " + rounded); // 输出: rounded: 3.14
System.out.println("ceiling: " + ceiling); // 输出: ceiling: 3.15
System.out.println("floor: " + floor);     // 输出: floor: 3.14

// 舍入模式示例
BigDecimal value = new BigDecimal("3.5");
System.out.println("HALF_UP: " + value.setScale(0, RoundingMode.HALF_UP));     // 输出: HALF_UP: 4
System.out.println("HALF_DOWN: " + value.setScale(0, RoundingMode.HALF_DOWN)); // 输出: HALF_DOWN: 3
System.out.println("HALF_EVEN: " + value.setScale(0, RoundingMode.HALF_EVEN)); // 输出: HALF_EVEN: 4
System.out.println("CEILING: " + value.setScale(0, RoundingMode.CEILING));     // 输出: CEILING: 4
System.out.println("FLOOR: " + value.setScale(0, RoundingMode.FLOOR));         // 输出: FLOOR: 3

// 转换为其他类型
int intValue = a.intValue();
long longValue = a.longValue();
float floatValue = a.floatValue();
double doubleValue = a.doubleValue();
String stringValue = a.toString();

// 输出结果
System.out.println("intValue: " + intValue);       // 输出: intValue: 10
System.out.println("longValue: " + longValue);     // 输出: longValue: 10
System.out.println("floatValue: " + floatValue);   // 输出: floatValue: 10.5
System.out.println("doubleValue: " + doubleValue); // 输出: doubleValue: 10.5
System.out.println("stringValue: " + stringValue); // 输出: stringValue: 10.5

// 获取精度信息
int scale = a.scale();           // 小数位数
int precision = a.precision();   // 总位数
BigInteger unscaledValue = a.unscaledValue(); // 去掉小数点的整数值

// 输出结果
System.out.println("scale: " + scale);           // 输出: scale: 1
System.out.println("precision: " + precision);   // 输出: precision: 3
System.out.println("unscaledValue: " + unscaledValue); // 输出: unscaledValue: 105

BigInteger和BigDecimal的实用工具类:

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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
import java.math.BigInteger;
import java.math.BigDecimal;
import java.math.RoundingMode;

public class MathUtils {
    
    // 计算阶乘
    public static BigInteger factorial(int n) {
        if (n < 0) throw new IllegalArgumentException("负数没有阶乘");
        if (n <= 1) return BigInteger.ONE;
        
        BigInteger result = BigInteger.ONE;
        for (int i = 2; i <= n; i++) {
            result = result.multiply(BigInteger.valueOf(i));
        }
        return result;
    }
    
    // 计算斐波那契数列
    public static BigInteger fibonacci(int n) {
        if (n <= 0) return BigInteger.ZERO;
        if (n == 1) return BigInteger.ONE;
        
        BigInteger a = BigInteger.ZERO;
        BigInteger b = BigInteger.ONE;
        for (int i = 2; i <= n; i++) {
            BigInteger temp = a.add(b);
            a = b;
            b = temp;
        }
        return b;
    }
    
    // 计算组合数 C(n,k)
    public static BigInteger combination(int n, int k) {
        if (k > n || k < 0) return BigInteger.ZERO;
        if (k == 0 || k == n) return BigInteger.ONE;
        
        return factorial(n).divide(factorial(k).multiply(factorial(n - k)));
    }
    
    // 计算排列数 P(n,k)
    public static BigInteger permutation(int n, int k) {
        if (k > n || k < 0) return BigInteger.ZERO;
        
        return factorial(n).divide(factorial(n - k));
    }
    
    // 计算平方根(使用牛顿迭代法)
    public static BigDecimal sqrt(BigDecimal value, int scale) {
        if (value.compareTo(BigDecimal.ZERO) < 0) {
            throw new IllegalArgumentException("负数没有实数平方根");
        }
        
        BigDecimal x = value;
        BigDecimal y = BigDecimal.ZERO;
        BigDecimal epsilon = BigDecimal.ONE.divide(BigDecimal.TEN.pow(scale));
        
        while (x.subtract(y).abs().compareTo(epsilon) > 0) {
            y = x;
            x = value.divide(x, scale, RoundingMode.HALF_UP)
                    .add(x)
                    .divide(BigDecimal.valueOf(2), scale, RoundingMode.HALF_UP);
        }
        
        return x;
    }
    
    // 计算e的n次方
    public static BigDecimal exp(BigDecimal x, int scale) {
        BigDecimal result = BigDecimal.ONE;
        BigDecimal term = BigDecimal.ONE;
        BigDecimal factorial = BigDecimal.ONE;
        int n = 1;
        
        while (term.abs().compareTo(BigDecimal.ONE.divide(BigDecimal.TEN.pow(scale))) > 0) {
            factorial = factorial.multiply(BigDecimal.valueOf(n));
            term = x.pow(n).divide(factorial, scale, RoundingMode.HALF_UP);
            result = result.add(term);
            n++;
        }
        
        return result;
    }
    
    // 计算自然对数
    public static BigDecimal ln(BigDecimal x, int scale) {
        if (x.compareTo(BigDecimal.ZERO) <= 0) {
            throw new IllegalArgumentException("对数只能计算正数");
        }
        
        BigDecimal y = x.subtract(BigDecimal.ONE).divide(x.add(BigDecimal.ONE), scale, RoundingMode.HALF_UP);
        BigDecimal result = BigDecimal.ZERO;
        BigDecimal term = y;
        int n = 1;
        
        while (term.abs().compareTo(BigDecimal.ONE.divide(BigDecimal.TEN.pow(scale))) > 0) {
            result = result.add(term.divide(BigDecimal.valueOf(n), scale, RoundingMode.HALF_UP));
            term = term.multiply(y).multiply(y);
            n += 2;
        }
        
        return result.multiply(BigDecimal.valueOf(2));
    }
    
    // 货币计算(避免浮点数精度问题)
    public static BigDecimal calculateInterest(BigDecimal principal, BigDecimal rate, int years) {
        BigDecimal multiplier = BigDecimal.ONE.add(rate.divide(BigDecimal.valueOf(100), 10, RoundingMode.HALF_UP));
        return principal.multiply(multiplier.pow(years)).setScale(2, RoundingMode.HALF_UP);
    }
    
    // 百分比计算
    public static BigDecimal percentage(BigDecimal value, BigDecimal total) {
        return value.multiply(BigDecimal.valueOf(100))
                   .divide(total, 2, RoundingMode.HALF_UP);
    }
}

// 使用示例
public class MathUtilsExample {
    public static void main(String[] args) {
        // 阶乘计算
        System.out.println("5! = " + MathUtils.factorial(5)); // 输出: 5! = 120
        System.out.println("10! = " + MathUtils.factorial(10)); // 输出: 10! = 3628800
        
        // 斐波那契数列
        System.out.println("F(10) = " + MathUtils.fibonacci(10)); // 输出: F(10) = 55
        System.out.println("F(20) = " + MathUtils.fibonacci(20)); // 输出: F(20) = 6765
        
        // 组合数
        System.out.println("C(5,2) = " + MathUtils.combination(5, 2)); // 输出: C(5,2) = 10
        System.out.println("C(10,3) = " + MathUtils.combination(10, 3)); // 输出: C(10,3) = 120
        
        // 平方根
        BigDecimal sqrt2 = MathUtils.sqrt(new BigDecimal("2"), 10);
        System.out.println("√2 = " + sqrt2); // 输出: √2 = 1.4142135624
        
        // 货币计算
        BigDecimal principal = new BigDecimal("10000.00");
        BigDecimal rate = new BigDecimal("5.5"); // 5.5%
        BigDecimal interest = MathUtils.calculateInterest(principal, rate, 3);
        System.out.println("利息: " + interest); // 输出: 利息: 11742.38
        
        // 百分比
        BigDecimal value = new BigDecimal("75");
        BigDecimal total = new BigDecimal("200");
        BigDecimal percentage = MathUtils.percentage(value, total);
        System.out.println("百分比: " + percentage + "%"); // 输出: 百分比: 37.50%
    }
}

BigInteger和BigDecimal的注意事项:

  1. 精度问题
    • BigInteger可以表示任意大的整数
    • BigDecimal可以表示任意精度的十进制数
    • 避免使用double构造BigDecimal,使用字符串构造
  2. 性能考虑
    • BigInteger和BigDecimal运算比基本类型慢
    • 对于简单计算,优先使用基本类型
    • 需要高精度时才使用BigInteger/BigDecimal
  3. 舍入模式
    • HALF_UP:四舍五入(默认)
    • HALF_DOWN:五舍六入
    • HALF_EVEN:银行家舍入法
    • CEILING:向上取整
    • FLOOR:向下取整
  4. 比较操作
    • 使用compareTo()而不是equals()进行比较
    • equals()会考虑精度,compareTo()只比较数值
  5. 应用场景
    • 金融计算(货币、利率)
    • 科学计算(高精度数学)
    • 大数运算(密码学、统计)
    • 避免浮点数精度问题
7.8 正则表达式

Pattern和Matcher类:

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
import java.util.regex.Pattern;
import java.util.regex.Matcher;

// 基本匹配
String text = "Hello World 123";
Pattern pattern = Pattern.compile("\\d+"); // 匹配一个或多个数字
Matcher matcher = pattern.matcher(text);

// 查找匹配
while (matcher.find()) {
    System.out.println("找到数字: " + matcher.group());
    System.out.println("位置: " + matcher.start() + "-" + matcher.end());
}
// 输出:
// 找到数字: 123
// 位置: 12-15

// 完全匹配
String email = "user@example.com";
Pattern emailPattern = Pattern.compile("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$");
boolean isValidEmail = emailPattern.matcher(email).matches();
System.out.println("邮箱有效: " + isValidEmail); // 输出: 邮箱有效: true

// 分组捕获
String phone = "138-1234-5678";
Pattern phonePattern = Pattern.compile("(\\d{3})-(\\d{4})-(\\d{4})");
Matcher phoneMatcher = phonePattern.matcher(phone);
if (phoneMatcher.matches()) {
    System.out.println("区号: " + phoneMatcher.group(1)); // 输出: 区号: 138
    System.out.println("前缀: " + phoneMatcher.group(2)); // 输出: 前缀: 1234
    System.out.println("后缀: " + phoneMatcher.group(3)); // 输出: 后缀: 5678
}

String类的正则方法:

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
// matches方法
String text = "Hello123World";
boolean hasDigits = text.matches(".*\\d+.*");
System.out.println("包含数字: " + hasDigits); // 输出: 包含数字: true

// split方法
String csv = "apple,banana,orange,grape";
String[] fruits = csv.split(",");
System.out.println("水果数量: " + fruits.length); // 输出: 水果数量: 4
for (String fruit : fruits) {
    System.out.println(fruit);
}
// 输出:
// apple
// banana
// orange
// grape

// replaceAll方法
String text = "Hello123World456";
String lettersOnly = text.replaceAll("\\d+", "");
System.out.println("只保留字母: " + lettersOnly); // 输出: 只保留字母: HelloWorld

// replaceFirst方法
String text = "Hello123World123";
String firstReplaced = text.replaceFirst("\\d+", "XXX");
System.out.println("替换第一个数字: " + firstReplaced); // 输出: 替换第一个数字: HelloXXXWorld123

常用正则表达式模式:

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
62
63
64
65
public class RegexPatterns {
    
    // 邮箱验证
    public static final String EMAIL_PATTERN = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$";
    
    // 手机号验证(中国)
    public static final String PHONE_PATTERN = "^1[3-9]\\d{9}$";
    
    // 身份证号验证(中国)
    public static final String ID_CARD_PATTERN = "^[1-9]\\d{5}(18|19|20)\\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$";
    
    // URL验证
    public static final String URL_PATTERN = "^https?://[\\w\\-]+(\\.[\\w\\-]+)+([\\w\\-.,@?^=%&:/~+#]*[\\w\\-@?^=%&/~+#])?$";
    
    // 日期验证(YYYY-MM-DD)
    public static final String DATE_PATTERN = "^\\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01])$";
    
    // 时间验证(HH:MM:SS)
    public static final String TIME_PATTERN = "^([01]\\d|2[0-3]):([0-5]\\d):([0-5]\\d)$";
    
    // 邮政编码验证(中国)
    public static final String POSTAL_CODE_PATTERN = "^[1-9]\\d{5}$";
    
    // 用户名验证(字母开头,允许字母数字下划线,长度3-16)
    public static final String USERNAME_PATTERN = "^[a-zA-Z]\\w{2,15}$";
    
    // 密码验证(至少8位,包含大小写字母和数字)
    public static final String PASSWORD_PATTERN = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)[a-zA-Z\\d@$!%*?&]{8,}$";
    
    // IPv4地址验证
    public static final String IPV4_PATTERN = "^((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)$";
    
    // 十六进制颜色验证
    public static final String HEX_COLOR_PATTERN = "^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$";
}

// 使用示例
public class RegexExample {
    public static void main(String[] args) {
        // 邮箱验证
        String email = "user@example.com";
        boolean isValidEmail = email.matches(RegexPatterns.EMAIL_PATTERN);
        System.out.println("邮箱有效: " + isValidEmail); // 输出: 邮箱有效: true
        
        // 手机号验证
        String phone = "13812345678";
        boolean isValidPhone = phone.matches(RegexPatterns.PHONE_PATTERN);
        System.out.println("手机号有效: " + isValidPhone); // 输出: 手机号有效: true
        
        // URL验证
        String url = "https://www.example.com/path?param=value";
        boolean isValidUrl = url.matches(RegexPatterns.URL_PATTERN);
        System.out.println("URL有效: " + isValidUrl); // 输出: URL有效: true
        
        // 日期验证
        String date = "2025-05-15";
        boolean isValidDate = date.matches(RegexPatterns.DATE_PATTERN);
        System.out.println("日期有效: " + isValidDate); // 输出: 日期有效: true
        
        // 密码验证
        String password = "MyPass123";
        boolean isValidPassword = password.matches(RegexPatterns.PASSWORD_PATTERN);
        System.out.println("密码有效: " + isValidPassword); // 输出: 密码有效: true
    }
}

正则表达式语法详解:

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
public class RegexSyntax {
    
    public static void demonstrateSyntax() {
        String text = "Hello World 123 ABC";
        
        // 字符类
        System.out.println("=== 字符类 ===");
        System.out.println("数字: " + text.replaceAll("\\d", "X")); // 输出: Hello World XXX ABC
        System.out.println("非数字: " + text.replaceAll("\\D", "X")); // 输出: XXXXX XXXXX XXX XXX
        System.out.println("字母: " + text.replaceAll("[a-zA-Z]", "X")); // 输出: XXXXX XXXXX 123 XXX
        System.out.println("非字母: " + text.replaceAll("[^a-zA-Z]", "X")); // 输出: HelloXWorldX123XABC
        
        // 量词
        System.out.println("=== 量词 ===");
        System.out.println("一个或多个数字: " + text.replaceAll("\\d+", "X")); // 输出: Hello World X ABC
        System.out.println("零个或多个字母: " + text.replaceAll("[a-zA-Z]*", "X")); // 输出: X X X X
        System.out.println("1到3个字母: " + text.replaceAll("[a-zA-Z]{1,3}", "X")); // 输出: X X 123 X
        
        // 边界
        System.out.println("=== 边界 ===");
        System.out.println("单词边界: " + text.replaceAll("\\b\\w+\\b", "X")); // 输出: X X 123 X
        System.out.println("行首: " + text.replaceAll("^\\w+", "X")); // 输出: X World 123 ABC
        System.out.println("行尾: " + text.replaceAll("\\w+$", "X")); // 输出: Hello World 123 X
        
        // 分组和引用
        System.out.println("=== 分组和引用 ===");
        String name = "John Doe";
        String result = name.replaceAll("(\\w+)\\s+(\\w+)", "$2, $1");
        System.out.println("姓名格式转换: " + result); // 输出: Doe, John
        
        // 非捕获组
        String text2 = "color colour";
        String result2 = text2.replaceAll("colou?r", "color");
        System.out.println("统一拼写: " + result2); // 输出: color color
        
        // 前瞻和后顾
        System.out.println("=== 前瞻和后顾 ===");
        String numbers = "123 456 789";
        // 匹配后面跟着空格的数字
        String result3 = numbers.replaceAll("\\d+(?=\\s)", "X");
        System.out.println("前瞻: " + result3); // 输出: X X 789
        
        // 匹配前面有数字的空格
        String result4 = numbers.replaceAll("(?<=\\d)\\s", "X");
        System.out.println("后顾: " + result4); // 输出: 123X456X789
    }
}

实用正则表达式工具类:

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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.util.ArrayList;
import java.util.List;

public class RegexUtils {
    
    // 验证字符串是否匹配正则表达式
    public static boolean isValid(String text, String regex) {
        return text != null && Pattern.matches(regex, text);
    }
    
    // 提取所有匹配的字符串
    public static List<String> extractAll(String text, String regex) {
        List<String> results = new ArrayList<>();
        if (text == null) return results;
        
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(text);
        
        while (matcher.find()) {
            results.add(matcher.group());
        }
        
        return results;
    }
    
    // 提取第一个匹配的字符串
    public static String extractFirst(String text, String regex) {
        if (text == null) return null;
        
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(text);
        
        return matcher.find() ? matcher.group() : null;
    }
    
    // 替换所有匹配的字符串
    public static String replaceAll(String text, String regex, String replacement) {
        return text != null ? text.replaceAll(regex, replacement) : null;
    }
    
    // 替换第一个匹配的字符串
    public static String replaceFirst(String text, String regex, String replacement) {
        return text != null ? text.replaceFirst(regex, replacement) : null;
    }
    
    // 分割字符串
    public static String[] split(String text, String regex) {
        return text != null ? text.split(regex) : new String[0];
    }
    
    // 验证邮箱
    public static boolean isValidEmail(String email) {
        return isValid(email, "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$");
    }
    
    // 验证手机号(中国)
    public static boolean isValidPhone(String phone) {
        return isValid(phone, "^1[3-9]\\d{9}$");
    }
    
    // 验证身份证号(中国)
    public static boolean isValidIdCard(String idCard) {
        return isValid(idCard, "^[1-9]\\d{5}(18|19|20)\\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$");
    }
    
    // 验证URL
    public static boolean isValidUrl(String url) {
        return isValid(url, "^https?://[\\w\\-]+(\\.[\\w\\-]+)+([\\w\\-.,@?^=%&:/~+#]*[\\w\\-@?^=%&/~+#])?$");
    }
    
    // 提取邮箱地址
    public static List<String> extractEmails(String text) {
        return extractAll(text, "\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z|a-z]{2,}\\b");
    }
    
    // 提取手机号
    public static List<String> extractPhones(String text) {
        return extractAll(text, "\\b1[3-9]\\d{9}\\b");
    }
    
    // 提取IP地址
    public static List<String> extractIpAddresses(String text) {
        return extractAll(text, "\\b((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\b");
    }
    
    // 提取HTML标签
    public static List<String> extractHtmlTags(String text) {
        return extractAll(text, "<[^>]+>");
    }
    
    // 移除HTML标签
    public static String removeHtmlTags(String text) {
        return replaceAll(text, "<[^>]+>", "");
    }
    
    // 提取数字
    public static List<String> extractNumbers(String text) {
        return extractAll(text, "\\b\\d+\\b");
    }
    
    // 提取小数
    public static List<String> extractDecimals(String text) {
        return extractAll(text, "\\b\\d+\\.\\d+\\b");
    }
    
    // 验证密码强度
    public static boolean isStrongPassword(String password) {
        // 至少8位,包含大小写字母、数字和特殊字符
        return isValid(password, "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8,}$");
    }
    
    // 格式化手机号(添加分隔符)
    public static String formatPhone(String phone) {
        if (!isValidPhone(phone)) return phone;
        return phone.replaceAll("(\\d{3})(\\d{4})(\\d{4})", "$1-$2-$3");
    }
    
    // 隐藏敏感信息
    public static String maskSensitiveInfo(String text, String regex, String mask) {
        return replaceAll(text, regex, mask);
    }
}

// 使用示例
public class RegexUtilsExample {
    public static void main(String[] args) {
        // 验证功能
        System.out.println("邮箱验证: " + RegexUtils.isValidEmail("user@example.com")); // true
        System.out.println("手机号验证: " + RegexUtils.isValidPhone("13812345678")); // true
        System.out.println("URL验证: " + RegexUtils.isValidUrl("https://www.example.com")); // true
        
        // 提取功能
        String text = "联系邮箱:user1@example.com, user2@test.org,手机号:13812345678, 13987654321";
        List<String> emails = RegexUtils.extractEmails(text);
        List<String> phones = RegexUtils.extractPhones(text);
        
        System.out.println("提取的邮箱: " + emails); // [user1@example.com, user2@test.org]
        System.out.println("提取的手机号: " + phones); // [13812345678, 13987654321]
        
        // 替换功能
        String html = "<p>Hello <b>World</b></p>";
        String plainText = RegexUtils.removeHtmlTags(html);
        System.out.println("移除HTML标签: " + plainText); // Hello World
        
        // 格式化功能
        String phone = "13812345678";
        String formatted = RegexUtils.formatPhone(phone);
        System.out.println("格式化手机号: " + formatted); // 138-1234-5678
        
        // 隐藏敏感信息
        String sensitive = "身份证号:123456789012345678,手机号:13812345678";
        String masked = RegexUtils.maskSensitiveInfo(sensitive, "\\d{17}[\\dXx]", "***");
        System.out.println("隐藏敏感信息: " + masked); // 身份证号:***,手机号:13812345678
    }
}

正则表达式性能优化:

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
public class RegexPerformance {
    
    // 编译正则表达式以提高性能
    private static final Pattern EMAIL_PATTERN = Pattern.compile("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$");
    private static final Pattern PHONE_PATTERN = Pattern.compile("^1[3-9]\\d{9}$");
    private static final Pattern URL_PATTERN = Pattern.compile("^https?://[\\w\\-]+(\\.[\\w\\-]+)+([\\w\\-.,@?^=%&:/~+#]*[\\w\\-@?^=%&/~+#])?$");
    
    // 使用预编译的正则表达式
    public static boolean isValidEmailOptimized(String email) {
        return email != null && EMAIL_PATTERN.matcher(email).matches();
    }
    
    public static boolean isValidPhoneOptimized(String phone) {
        return phone != null && PHONE_PATTERN.matcher(phone).matches();
    }
    
    public static boolean isValidUrlOptimized(String url) {
        return url != null && URL_PATTERN.matcher(url).matches();
    }
    
    // 性能测试
    public static void performanceTest() {
        String email = "user@example.com";
        String phone = "13812345678";
        String url = "https://www.example.com";
        
        long startTime = System.currentTimeMillis();
        
        // 测试10000次验证
        for (int i = 0; i < 10000; i++) {
            isValidEmailOptimized(email);
            isValidPhoneOptimized(phone);
            isValidUrlOptimized(url);
        }
        
        long endTime = System.currentTimeMillis();
        System.out.println("优化后耗时: " + (endTime - startTime) + "ms");
        
        // 对比未优化的版本
        startTime = System.currentTimeMillis();
        
        for (int i = 0; i < 10000; i++) {
            email.matches("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$");
            phone.matches("^1[3-9]\\d{9}$");
            url.matches("^https?://[\\w\\-]+(\\.[\\w\\-]+)+([\\w\\-.,@?^=%&:/~+#]*[\\w\\-@?^=%&/~+#])?$");
        }
        
        endTime = System.currentTimeMillis();
        System.out.println("未优化耗时: " + (endTime - startTime) + "ms");
    }
}

正则表达式的注意事项:

  1. 性能考虑
    • 预编译正则表达式以提高性能
    • 避免在循环中重复编译正则表达式
    • 使用非贪婪匹配(*?、+?)避免回溯过多
  2. 语法要点
    • 转义字符:在Java中需要使用双反斜杠
    • 字符类:使用方括号定义字符集合
    • 量词:控制匹配次数
    • 边界:定义匹配位置
  3. 常见陷阱
    • 点号(.)不匹配换行符,需要使用Pattern.DOTALL标志
    • 大小写敏感,需要使用Pattern.CASE_INSENSITIVE标志
    • 多行模式,需要使用Pattern.MULTILINE标志
  4. 应用场景
    • 数据验证:邮箱、手机号、身份证等
    • 文本处理:提取、替换、分割
    • 日志分析:提取关键信息
    • 数据清洗:格式化、标准化
7.9 包装类

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 基本数据类型 -> 包装类
byte -> Byte
short -> Short
int -> Integer
long -> Long
float -> Float
double -> Double
char -> Character
boolean -> Boolean

// 创建包装类对象
Integer intObj = new Integer(100);           // 构造方法(已过时)
Integer intObj2 = Integer.valueOf(100);       // 推荐使用valueOf方法
Integer intObj3 = 100;                        // 自动装箱

// 输出结果
System.out.println("intObj: " + intObj);      // 输出: intObj: 100
System.out.println("intObj2: " + intObj2);    // 输出: intObj2: 100
System.out.println("intObj3: " + intObj3);    // 输出: intObj3: 100

装箱与拆箱:

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
// 自动装箱(Autoboxing)
Integer autoBoxed = 100;                      // 基本类型自动转换为包装类
Double autoBoxedDouble = 3.14;               // 基本类型自动转换为包装类

// 自动拆箱(Unboxing)
int primitive = autoBoxed;                    // 包装类自动转换为基本类型
double primitiveDouble = autoBoxedDouble;     // 包装类自动转换为基本类型

// 输出结果
System.out.println("autoBoxed: " + autoBoxed);           // 输出: autoBoxed: 100
System.out.println("primitive: " + primitive);           // 输出: primitive: 100
System.out.println("autoBoxedDouble: " + autoBoxedDouble); // 输出: autoBoxedDouble: 3.14
System.out.println("primitiveDouble: " + primitiveDouble); // 输出: primitiveDouble: 3.14

// 在集合中使用
List<Integer> numbers = new ArrayList<>();
numbers.add(1);    // 自动装箱
numbers.add(2);    // 自动装箱
numbers.add(3);    // 自动装箱

int first = numbers.get(0);  // 自动拆箱
int second = numbers.get(1); // 自动拆箱

// 输出结果
System.out.println("numbers: " + numbers);     // 输出: numbers: [1, 2, 3]
System.out.println("first: " + first);         // 输出: first: 1
System.out.println("second: " + second);       // 输出: second: 2

包装类的常用方法:

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
// Integer类的常用方法
Integer num = 123;

// 转换为基本类型
int intValue = num.intValue();
long longValue = num.longValue();
float floatValue = num.floatValue();
double doubleValue = num.doubleValue();

// 输出结果
System.out.println("intValue: " + intValue);       // 输出: intValue: 123
System.out.println("longValue: " + longValue);     // 输出: longValue: 123
System.out.println("floatValue: " + floatValue);   // 输出: floatValue: 123.0
System.out.println("doubleValue: " + doubleValue); // 输出: doubleValue: 123.0

// 字符串转换
String str = num.toString();
String hexStr = Integer.toHexString(num);
String binaryStr = Integer.toBinaryString(num);
String octalStr = Integer.toOctalString(num);

// 输出结果
System.out.println("str: " + str);           // 输出: str: 123
System.out.println("hexStr: " + hexStr);     // 输出: hexStr: 7b
System.out.println("binaryStr: " + binaryStr); // 输出: binaryStr: 1111011
System.out.println("octalStr: " + octalStr); // 输出: octalStr: 173

// 解析字符串
int parsed1 = Integer.parseInt("123");
int parsed2 = Integer.parseInt("7b", 16);    // 十六进制
int parsed3 = Integer.parseInt("1111011", 2); // 二进制

// 输出结果
System.out.println("parsed1: " + parsed1);   // 输出: parsed1: 123
System.out.println("parsed2: " + parsed2);   // 输出: parsed2: 123
System.out.println("parsed3: " + parsed3);   // 输出: parsed3: 123

// 比较方法
int compare = Integer.compare(100, 200);
boolean equals = Integer.valueOf(100).equals(Integer.valueOf(100));

// 输出结果
System.out.println("compare: " + compare);   // 输出: compare: -1 (100 < 200)
System.out.println("equals: " + equals);     // 输出: equals: true

// 最大最小值
int max = Integer.max(100, 200);
int min = Integer.min(100, 200);
int sum = Integer.sum(100, 200);

// 输出结果
System.out.println("max: " + max);           // 输出: max: 200
System.out.println("min: " + min);           // 输出: min: 100
System.out.println("sum: " + sum);           // 输出: sum: 300

Character类的特殊方法:

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
char ch = 'A';

// 字符类型判断
boolean isLetter = Character.isLetter(ch);
boolean isDigit = Character.isDigit('5');
boolean isWhitespace = Character.isWhitespace(' ');
boolean isUpperCase = Character.isUpperCase(ch);
boolean isLowerCase = Character.isLowerCase('a');

// 输出结果
System.out.println("isLetter: " + isLetter);         // 输出: isLetter: true
System.out.println("isDigit: " + isDigit);           // 输出: isDigit: true
System.out.println("isWhitespace: " + isWhitespace); // 输出: isWhitespace: true
System.out.println("isUpperCase: " + isUpperCase);   // 输出: isUpperCase: true
System.out.println("isLowerCase: " + isLowerCase);   // 输出: isLowerCase: true

// 字符转换
char upper = Character.toUpperCase('a');
char lower = Character.toLowerCase('A');
int digit = Character.getNumericValue('9');

// 输出结果
System.out.println("upper: " + upper);       // 输出: upper: A
System.out.println("lower: " + lower);       // 输出: lower: a
System.out.println("digit: " + digit);       // 输出: digit: 9

// 字符分类
boolean isJavaIdentifierStart = Character.isJavaIdentifierStart('_');
boolean isJavaIdentifierPart = Character.isJavaIdentifierPart('$');

// 输出结果
System.out.println("isJavaIdentifierStart: " + isJavaIdentifierStart); // 输出: isJavaIdentifierStart: true
System.out.println("isJavaIdentifierPart: " + isJavaIdentifierPart);   // 输出: isJavaIdentifierPart: true

包装类的缓存机制:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Integer缓存(-128到127)
Integer a = 100;
Integer b = 100;
Integer c = 200;
Integer d = 200;

// 输出结果
System.out.println("a == b: " + (a == b));   // 输出: a == b: true(缓存)
System.out.println("c == d: " + (c == d));   // 输出: c == d: false(未缓存)

// 使用equals比较
System.out.println("a.equals(b): " + a.equals(b)); // 输出: a.equals(b): true
System.out.println("c.equals(d): " + c.equals(d)); // 输出: c.equals(d): true

// Boolean缓存(只有true和false两个值)
Boolean bool1 = true;
Boolean bool2 = true;
Boolean bool3 = new Boolean(true);

// 输出结果
System.out.println("bool1 == bool2: " + (bool1 == bool2));     // 输出: bool1 == bool2: true
System.out.println("bool1 == bool3: " + (bool1 == bool3));     // 输出: bool1 == bool3: false
System.out.println("bool1.equals(bool3): " + bool1.equals(bool3)); // 输出: bool1.equals(bool3): true

包装类的实用工具类:

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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
public class WrapperUtils {
    
    // 安全转换字符串为整数
    public static Integer safeParseInt(String str) {
        try {
            return Integer.parseInt(str);
        } catch (NumberFormatException e) {
            return null;
        }
    }
    
    // 安全转换字符串为长整数
    public static Long safeParseLong(String str) {
        try {
            return Long.parseLong(str);
        } catch (NumberFormatException e) {
            return null;
        }
    }
    
    // 安全转换字符串为双精度浮点数
    public static Double safeParseDouble(String str) {
        try {
            return Double.parseDouble(str);
        } catch (NumberFormatException e) {
            return null;
        }
    }
    
    // 检查字符串是否为有效数字
    public static boolean isValidNumber(String str) {
        if (str == null || str.trim().isEmpty()) {
            return false;
        }
        try {
            Double.parseDouble(str);
            return true;
        } catch (NumberFormatException e) {
            return false;
        }
    }
    
    // 获取数字的位数
    public static int getDigitCount(int number) {
        if (number == 0) return 1;
        return (int) Math.log10(Math.abs(number)) + 1;
    }
    
    // 获取数字的各位数字
    public static int[] getDigits(int number) {
        int count = getDigitCount(number);
        int[] digits = new int[count];
        int temp = Math.abs(number);
        
        for (int i = count - 1; i >= 0; i--) {
            digits[i] = temp % 10;
            temp /= 10;
        }
        
        return digits;
    }
    
    // 检查字符是否为元音字母
    public static boolean isVowel(char ch) {
        char lower = Character.toLowerCase(ch);
        return lower == 'a' || lower == 'e' || lower == 'i' || 
               lower == 'o' || lower == 'u';
    }
    
    // 统计字符串中各种字符的数量
    public static void analyzeString(String str) {
        if (str == null) {
            System.out.println("字符串为null");
            return;
        }
        
        int letters = 0, digits = 0, spaces = 0, others = 0;
        
        for (char ch : str.toCharArray()) {
            if (Character.isLetter(ch)) {
                letters++;
            } else if (Character.isDigit(ch)) {
                digits++;
            } else if (Character.isWhitespace(ch)) {
                spaces++;
            } else {
                others++;
            }
        }
        
        System.out.println("字符串分析结果:");
        System.out.println("  字母: " + letters);
        System.out.println("  数字: " + digits);
        System.out.println("  空格: " + spaces);
        System.out.println("  其他: " + others);
    }
    
    // 格式化数字
    public static String formatNumber(Number number, String pattern) {
        if (number == null) return "null";
        
        java.text.DecimalFormat df = new java.text.DecimalFormat(pattern);
        return df.format(number);
    }
    
    // 生成随机包装类对象
    public static Integer randomInteger(int min, int max) {
        return (int)(Math.random() * (max - min + 1)) + min;
    }
    
    public static Double randomDouble(double min, double max) {
        return min + (Math.random() * (max - min));
    }
    
    public static Boolean randomBoolean() {
        return Math.random() < 0.5;
    }
}

// 使用示例
public class WrapperUtilsExample {
    public static void main(String[] args) {
        // 安全解析
        System.out.println("safeParseInt('123'): " + WrapperUtils.safeParseInt("123")); // 输出: 123
        System.out.println("safeParseInt('abc'): " + WrapperUtils.safeParseInt("abc")); // 输出: null
        
        // 数字验证
        System.out.println("isValidNumber('123.45'): " + WrapperUtils.isValidNumber("123.45")); // 输出: true
        System.out.println("isValidNumber('abc'): " + WrapperUtils.isValidNumber("abc")); // 输出: false
        
        // 数字分析
        int number = 12345;
        System.out.println("位数: " + WrapperUtils.getDigitCount(number)); // 输出: 位数: 5
        System.out.println("各位数字: " + Arrays.toString(WrapperUtils.getDigits(number))); // 输出: 各位数字: [1, 2, 3, 4, 5]
        
        // 字符分析
        WrapperUtils.analyzeString("Hello World 123!");
        // 输出:
        // 字符串分析结果:
        //   字母: 10
        //   数字: 3
        //   空格: 2
        //   其他: 1
        
        // 格式化
        System.out.println("格式化: " + WrapperUtils.formatNumber(1234.5678, "#,##0.00")); // 输出: 格式化: 1,234.57
        
        // 随机生成
        System.out.println("随机整数: " + WrapperUtils.randomInteger(1, 100)); // 输出: 随机整数: 45
        System.out.println("随机浮点数: " + WrapperUtils.randomDouble(0.0, 1.0)); // 输出: 随机浮点数: 0.123456789
        System.out.println("随机布尔值: " + WrapperUtils.randomBoolean()); // 输出: 随机布尔值: true
    }
}

包装类的性能考虑:

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
public class WrapperPerformance {
    
    // 性能测试:基本类型 vs 包装类
    public static void performanceTest() {
        int iterations = 10000000;
        
        // 基本类型测试
        long startTime = System.currentTimeMillis();
        int sum = 0;
        for (int i = 0; i < iterations; i++) {
            sum += i;
        }
        long endTime = System.currentTimeMillis();
        System.out.println("基本类型耗时: " + (endTime - startTime) + "ms");
        
        // 包装类测试
        startTime = System.currentTimeMillis();
        Integer sumObj = 0;
        for (int i = 0; i < iterations; i++) {
            sumObj += i; // 自动装箱和拆箱
        }
        endTime = System.currentTimeMillis();
        System.out.println("包装类耗时: " + (endTime - startTime) + "ms");
        
        // 输出结果示例:
        // 基本类型耗时: 5ms
        // 包装类耗时: 45ms
    }
    
    // 避免不必要的装箱拆箱
    public static void avoidUnnecessaryBoxing() {
        // 不好的做法
        Integer sum = 0;
        for (int i = 0; i < 1000; i++) {
            sum += i; // 每次循环都有装箱和拆箱
        }
        
        // 好的做法
        int sum2 = 0;
        for (int i = 0; i < 1000; i++) {
            sum2 += i; // 使用基本类型
        }
        Integer result = sum2; // 最后才装箱
    }
    
    // 使用valueOf而不是构造方法
    public static void useValueOf() {
        // 推荐
        Integer good = Integer.valueOf(100);
        Double good2 = Double.valueOf(3.14);
        
        // 不推荐(已过时)
        // Integer bad = new Integer(100);
        // Double bad2 = new Double(3.14);
    }
}

包装类的常见陷阱:

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
public class WrapperTraps {
    
    public static void demonstrateTraps() {
        // 陷阱1:null值拆箱
        Integer nullInt = null;
        try {
            int value = nullInt; // NullPointerException
        } catch (NullPointerException e) {
            System.out.println("陷阱1:null值拆箱会抛出NullPointerException");
        }
        
        // 陷阱2:比较时使用==而不是equals
        Integer a = 100;
        Integer b = 100;
        Integer c = 200;
        Integer d = 200;
        
        System.out.println("a == b: " + (a == b)); // true(缓存)
        System.out.println("c == d: " + (c == d)); // false(未缓存)
        System.out.println("c.equals(d): " + c.equals(d)); // true
        
        // 陷阱3:自动装箱的性能问题
        Long sum = 0L;
        for (long i = 0; i < 1000000; i++) {
            sum += i; // 每次都有装箱和拆箱
        }
        
        // 更好的做法
        long sum2 = 0L;
        for (long i = 0; i < 1000000; i++) {
            sum2 += i; // 使用基本类型
        }
        Long result = sum2; // 最后才装箱
        
        // 陷阱4:包装类不可变
        Integer num = 100;
        num = 200; // 不是修改原对象,而是创建新对象
        
        // 陷阱5:类型转换问题
        Double dbl = 3.14;
        int intValue = dbl.intValue(); // 截断小数部分
        System.out.println("intValue: " + intValue); // 输出: 3
    }
}

包装类的最佳实践:

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
62
63
64
65
66
67
68
public class WrapperBestPractices {
    
    // 1. 优先使用基本类型
    public static void preferPrimitives() {
        // 好的做法
        int[] numbers = new int[1000];
        double sum = 0.0;
        
        // 避免
        // Integer[] numbers = new Integer[1000];
        // Double sum = 0.0;
    }
    
    // 2. 在集合中使用包装类
    public static void useWrappersInCollections() {
        List<Integer> numbers = new ArrayList<>();
        Map<String, Double> prices = new HashMap<>();
        
        numbers.add(100); // 自动装箱
        prices.put("apple", 2.99); // 自动装箱
    }
    
    // 3. 使用equals比较包装类
    public static void compareWrappers() {
        Integer a = 100;
        Integer b = 100;
        
        // 正确的比较方式
        boolean equals = a.equals(b);
        int compare = a.compareTo(b);
        
        // 避免使用==(除非是缓存范围内的值)
    }
    
    // 4. 处理null值
    public static Integer safeUnboxing(Integer wrapper) {
        return wrapper != null ? wrapper : 0; // 提供默认值
    }
    
    // 5. 使用工具方法
    public static void useUtilityMethods() {
        // 字符串解析
        int num = Integer.parseInt("123");
        double dbl = Double.parseDouble("3.14");
        
        // 格式化
        String hex = Integer.toHexString(255);
        String binary = Integer.toBinaryString(255);
        
        // 比较
        int max = Integer.max(10, 20);
        int min = Integer.min(10, 20);
    }
    
    // 6. 性能优化
    public static void performanceOptimization() {
        // 避免在循环中频繁装箱拆箱
        int sum = 0;
        for (int i = 0; i < 1000000; i++) {
            sum += i; // 使用基本类型
        }
        Integer result = sum; // 最后装箱
        
        // 使用缓存
        Integer cached = Integer.valueOf(100); // 使用缓存
        Integer notCached = Integer.valueOf(200); // 不在缓存范围内
    }
}

包装类的注意事项:

  1. 性能考虑
    • 基本类型比包装类性能更好
    • 避免在循环中频繁装箱拆箱
    • 优先使用基本类型进行数值计算
  2. null值处理
    • 包装类可以为null,基本类型不能
    • 拆箱前要检查null值
    • 提供默认值处理null情况
  3. 比较操作
    • 使用equals()比较包装类内容
    • 使用compareTo()进行排序
    • 避免使用==比较(除非是缓存值)
  4. 缓存机制
    • Integer缓存-128到127
    • Boolean缓存true和false
    • Character缓存0到127
    • 使用valueOf()方法利用缓存
  5. 不可变性
    • 所有包装类都是不可变的
    • 修改操作会创建新对象
    • 适合作为Map的键
  6. 应用场景
    • 集合中存储数值
    • 需要null值的场景
    • 反射和泛型中使用
    • 数据库操作中的null处理
7.10 Lambda表达式

Lambda表达式基础:

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
// Lambda表达式语法:(参数列表) -> {表达式或语句块}

// 1. 无参数Lambda表达式
Runnable runnable = () -> System.out.println("Hello Lambda");
runnable.run(); // 输出: Hello Lambda

// 2. 单参数Lambda表达式
Consumer<String> consumer = (str) -> System.out.println("接收: " + str);
consumer.accept("Hello"); // 输出: 接收: Hello

// 3. 多参数Lambda表达式
BiFunction<Integer, Integer, Integer> add = (a, b) -> a + b;
int result = add.apply(5, 3);
System.out.println("结果: " + result); // 输出: 结果: 8

// 4. 带类型声明的Lambda表达式
BiFunction<String, String, String> concat = (String a, String b) -> a + b;
String result2 = concat.apply("Hello", " World");
System.out.println("拼接结果: " + result2); // 输出: 拼接结果: Hello World

// 5. 多行Lambda表达式
Consumer<String> multiLine = (str) -> {
    System.out.println("处理字符串: " + str);
    System.out.println("字符串长度: " + str.length());
    System.out.println("转换为大写: " + str.toUpperCase());
};
multiLine.accept("hello world");
// 输出:
// 处理字符串: hello world
// 字符串长度: 11
// 转换为大写: HELLO WORLD

函数式接口:

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
// 自定义函数式接口
@FunctionalInterface
interface MathOperation {
    int operate(int a, int b);
}

@FunctionalInterface
interface StringProcessor {
    String process(String input);
}

// 使用自定义函数式接口
MathOperation add = (a, b) -> a + b;
MathOperation subtract = (a, b) -> a - b;
MathOperation multiply = (a, b) -> a * b;
MathOperation divide = (a, b) -> a / b;

// 输出结果
System.out.println("加法: " + add.operate(10, 5));      // 输出: 加法: 15
System.out.println("减法: " + subtract.operate(10, 5)); // 输出: 减法: 5
System.out.println("乘法: " + multiply.operate(10, 5)); // 输出: 乘法: 50
System.out.println("除法: " + divide.operate(10, 5));   // 输出: 除法: 2

// 字符串处理
StringProcessor upper = str -> str.toUpperCase();
StringProcessor reverse = str -> new StringBuilder(str).reverse().toString();
StringProcessor addPrefix = str -> "处理后的: " + str;

// 输出结果
System.out.println("大写: " + upper.process("hello"));           // 输出: 大写: HELLO
System.out.println("反转: " + reverse.process("hello"));         // 输出: 反转: olleh
System.out.println("加前缀: " + addPrefix.process("hello"));     // 输出: 加前缀: 处理后的: hello

Java内置函数式接口:

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
import java.util.function.*;
import java.util.*;

// Predicate<T> - 断言接口
Predicate<String> isLongerThan5 = str -> str.length() > 5;
Predicate<String> startsWithA = str -> str.startsWith("A");
Predicate<String> isLongerThan5AndStartsWithA = isLongerThan5.and(startsWithA);

// 输出结果
System.out.println("长度大于5: " + isLongerThan5.test("Hello"));     // 输出: 长度大于5: false
System.out.println("长度大于5: " + isLongerThan5.test("Hello World")); // 输出: 长度大于5: true
System.out.println("以A开头且长度大于5: " + isLongerThan5AndStartsWithA.test("Apple")); // 输出: 以A开头且长度大于5: false

// Function<T, R> - 函数接口
Function<String, Integer> getLength = str -> str.length();
Function<String, String> toUpperCase = str -> str.toUpperCase();
Function<String, String> addExclamation = str -> str + "!";

// 函数组合
Function<String, String> combined = getLength.andThen(length -> "长度: " + length);
Function<String, String> pipeline = toUpperCase.andThen(addExclamation);

// 输出结果
System.out.println("长度: " + getLength.apply("Hello"));           // 输出: 长度: 5
System.out.println("组合结果: " + combined.apply("Hello"));        // 输出: 组合结果: 长度: 5
System.out.println("管道处理: " + pipeline.apply("hello"));        // 输出: 管道处理: HELLO!

// Consumer<T> - 消费者接口
Consumer<String> print = str -> System.out.println("打印: " + str);
Consumer<String> printLength = str -> System.out.println("长度: " + str.length());
Consumer<String> combinedConsumer = print.andThen(printLength);

// 输出结果
combinedConsumer.accept("Hello");
// 输出:
// 打印: Hello
// 长度: 5

// Supplier<T> - 供应者接口
Supplier<Double> randomDouble = () -> Math.random();
Supplier<String> currentTime = () -> new Date().toString();
Supplier<List<String>> emptyList = ArrayList::new;

// 输出结果
System.out.println("随机数: " + randomDouble.get());     // 输出: 随机数: 0.123456789
System.out.println("当前时间: " + currentTime.get());   // 输出: 当前时间: Wed May 15 20:30:45 CST 2025
System.out.println("空列表: " + emptyList.get());       // 输出: 空列表: []

// BiFunction<T, U, R> - 双参数函数接口
BiFunction<String, String, String> concat = (a, b) -> a + b;
BiFunction<Integer, Integer, Integer> max = Math::max;
BiFunction<String, Integer, String> repeat = (str, times) -> str.repeat(times);

// 输出结果
System.out.println("拼接: " + concat.apply("Hello", " World")); // 输出: 拼接: Hello World
System.out.println("最大值: " + max.apply(10, 20));             // 输出: 最大值: 20
System.out.println("重复: " + repeat.apply("Ha", 3));           // 输出: 重复: HaHaHa

Lambda表达式在集合中的应用:

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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import java.util.*;
import java.util.stream.Collectors;

List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Eve");

// 1. forEach - 遍历
System.out.println("=== forEach遍历 ===");
names.forEach(name -> System.out.println("名字: " + name));
// 输出:
// 名字: Alice
// 名字: Bob
// 名字: Charlie
// 名字: David
// 名字: Eve

// 2. removeIf - 条件删除
List<String> namesCopy = new ArrayList<>(names);
namesCopy.removeIf(name -> name.length() < 4);
System.out.println("删除短名字后: " + namesCopy); // 输出: 删除短名字后: [Alice, Charlie, David]

// 3. replaceAll - 批量替换
List<String> namesCopy2 = new ArrayList<>(names);
namesCopy2.replaceAll(name -> name.toUpperCase());
System.out.println("转换为大写: " + namesCopy2); // 输出: 转换为大写: [ALICE, BOB, CHARLIE, DAVID, EVE]

// 4. sort - 排序
List<String> namesCopy3 = new ArrayList<>(names);
namesCopy3.sort((a, b) -> a.compareTo(b)); // 按字母顺序排序
System.out.println("排序后: " + namesCopy3); // 输出: 排序后: [Alice, Bob, Charlie, David, Eve]

// 按长度排序
namesCopy3.sort((a, b) -> Integer.compare(a.length(), b.length()));
System.out.println("按长度排序: " + namesCopy3); // 输出: 按长度排序: [Bob, Eve, Alice, David, Charlie]

// 5. Map操作
Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 85);
scores.put("Bob", 92);
scores.put("Charlie", 78);

// 遍历Map
System.out.println("=== Map遍历 ===");
scores.forEach((name, score) -> System.out.println(name + ": " + score));
// 输出:
// Alice: 85
// Bob: 92
// Charlie: 78

// 条件操作
scores.entrySet().removeIf(entry -> entry.getValue() < 80);
System.out.println("删除低分后: " + scores); // 输出: 删除低分后: {Alice=85, Bob=92}

// 6. Stream API与Lambda
System.out.println("=== Stream操作 ===");

// 过滤
List<String> longNames = names.stream()
    .filter(name -> name.length() > 4)
    .collect(Collectors.toList());
System.out.println("长名字: " + longNames); // 输出: 长名字: [Alice, Charlie, David]

// 映射
List<Integer> nameLengths = names.stream()
    .map(String::length)
    .collect(Collectors.toList());
System.out.println("名字长度: " + nameLengths); // 输出: 名字长度: [5, 3, 7, 5, 3]

// 归约
int totalLength = names.stream()
    .mapToInt(String::length)
    .sum();
System.out.println("总长度: " + totalLength); // 输出: 总长度: 23

// 分组
Map<Integer, List<String>> groupedByLength = names.stream()
    .collect(Collectors.groupingBy(String::length));
System.out.println("按长度分组: " + groupedByLength); // 输出: 按长度分组: {3=[Bob, Eve], 5=[Alice, David], 7=[Charlie]}

Lambda表达式的高级用法:

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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import java.util.*;
import java.util.concurrent.*;
import java.util.function.*;

// 1. 方法引用
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

// 静态方法引用
names.forEach(System.out::println);
// 输出:
// Alice
// Bob
// Charlie

// 实例方法引用
names.forEach(String::toUpperCase);
names.stream().map(String::length).forEach(System.out::println);

// 构造方法引用
Supplier<ArrayList<String>> listSupplier = ArrayList::new;
ArrayList<String> newList = listSupplier.get();

// 2. 闭包和变量捕获
int factor = 10;
Function<Integer, Integer> multiplier = x -> x * factor;
System.out.println("乘以因子: " + multiplier.apply(5)); // 输出: 乘以因子: 50

// 注意:捕获的变量必须是final或effectively final
// int mutableFactor = 10;
// Function<Integer, Integer> badMultiplier = x -> x * mutableFactor; // 编译错误
// mutableFactor = 20; // 如果这行存在,上面的Lambda表达式会编译错误

// 3. 异常处理
Function<String, Integer> safeParseInt = str -> {
    try {
        return Integer.parseInt(str);
    } catch (NumberFormatException e) {
        return 0;
    }
};

System.out.println("安全解析: " + safeParseInt.apply("123")); // 输出: 安全解析: 123
System.out.println("安全解析: " + safeParseInt.apply("abc")); // 输出: 安全解析: 0

// 4. 递归Lambda
// 使用函数式接口实现递归
Function<Integer, Integer> factorial = new Function<Integer, Integer>() {
    @Override
    public Integer apply(Integer n) {
        return n <= 1 ? 1 : n * this.apply(n - 1);
    }
};

System.out.println("阶乘: " + factorial.apply(5)); // 输出: 阶乘: 120

// 5. 组合模式
Function<String, String> pipeline = ((Function<String, String>) String::toUpperCase)
    .andThen(str -> str + "!")
    .andThen(str -> "处理结果: " + str);

System.out.println("管道处理: " + pipeline.apply("hello")); // 输出: 管道处理: 处理结果: HELLO!

// 6. 条件Lambda
Predicate<String> isLong = str -> str.length() > 5;
Predicate<String> startsWithA = str -> str.startsWith("A");

Function<String, String> conditionalProcessor = str -> {
    if (isLong.test(str)) {
        return str.toUpperCase();
    } else if (startsWithA.test(str)) {
        return str.toLowerCase();
    } else {
        return str + " (默认处理)";
    }
};

System.out.println("条件处理1: " + conditionalProcessor.apply("Hello World")); // 输出: 条件处理1: HELLO WORLD
System.out.println("条件处理2: " + conditionalProcessor.apply("Apple"));      // 输出: 条件处理2: apple
System.out.println("条件处理3: " + conditionalProcessor.apply("Hi"));         // 输出: 条件处理3: Hi (默认处理)

Lambda表达式的性能优化:

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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import java.util.*;
import java.util.stream.*;

public class LambdaPerformance {
    
    // 1. 避免在循环中创建Lambda
    public static void avoidLambdaInLoop() {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
        
        // 不好的做法:每次循环都创建新的Lambda
        for (String name : names) {
            Consumer<String> printer = str -> System.out.println("名字: " + str);
            printer.accept(name);
        }
        
        // 好的做法:预先定义Lambda
        Consumer<String> printer = str -> System.out.println("名字: " + str);
        for (String name : names) {
            printer.accept(name);
        }
        
        // 更好的做法:使用forEach
        names.forEach(str -> System.out.println("名字: " + str));
    }
    
    // 2. 使用并行流提高性能
    public static void parallelStreamExample() {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        
        // 顺序流
        long startTime = System.currentTimeMillis();
        int sum = numbers.stream()
            .mapToInt(Integer::intValue)
            .sum();
        long endTime = System.currentTimeMillis();
        System.out.println("顺序流耗时: " + (endTime - startTime) + "ms");
        
        // 并行流
        startTime = System.currentTimeMillis();
        int sumParallel = numbers.parallelStream()
            .mapToInt(Integer::intValue)
            .sum();
        endTime = System.currentTimeMillis();
        System.out.println("并行流耗时: " + (endTime - startTime) + "ms");
    }
    
    // 3. 缓存Lambda表达式
    public static void cacheLambda() {
        // 缓存常用的Lambda表达式
        Function<String, String> upperCase = String::toUpperCase;
        Function<String, String> addExclamation = str -> str + "!";
        Predicate<String> isLong = str -> str.length() > 5;
        
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
        
        // 重用缓存的Lambda
        names.stream()
            .filter(isLong)
            .map(upperCase)
            .map(addExclamation)
            .forEach(System.out::println);
    }
    
    // 4. 避免不必要的装箱拆箱
    public static void avoidBoxing() {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
        
        // 不好的做法:有装箱拆箱
        int sum = numbers.stream()
            .mapToInt(Integer::intValue) // 避免装箱
            .sum();
        
        // 更好的做法:直接使用基本类型
        int[] primitiveNumbers = {1, 2, 3, 4, 5};
        int sum2 = Arrays.stream(primitiveNumbers)
            .sum();
    }
}

// 使用示例
public class LambdaPerformanceExample {
    public static void main(String[] args) {
        // 性能测试
        LambdaPerformance.avoidLambdaInLoop();
        LambdaPerformance.parallelStreamExample();
        LambdaPerformance.cacheLambda();
        LambdaPerformance.avoidBoxing();
    }
}

Lambda表达式的实用工具类:

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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import java.util.*;
import java.util.function.*;
import java.util.stream.Collectors;

public class LambdaUtils {
    
    // 1. 安全的函数执行
    public static <T, R> Optional<R> safeApply(Function<T, R> function, T input) {
        try {
            return Optional.of(function.apply(input));
        } catch (Exception e) {
            return Optional.empty();
        }
    }
    
    // 2. 重试机制
    public static <T> T retry(Supplier<T> supplier, int maxAttempts) {
        for (int i = 0; i < maxAttempts; i++) {
            try {
                return supplier.get();
            } catch (Exception e) {
                if (i == maxAttempts - 1) {
                    throw new RuntimeException("重试失败", e);
                }
            }
        }
        throw new RuntimeException("重试失败");
    }
    
    // 3. 条件执行
    public static <T> Optional<T> executeIf(Predicate<T> condition, Function<T, T> action, T input) {
        return condition.test(input) ? Optional.of(action.apply(input)) : Optional.of(input);
    }
    
    // 4. 管道处理
    @SafeVarargs
    public static <T> Function<T, T> pipeline(Function<T, T>... functions) {
        return Arrays.stream(functions)
            .reduce(Function.identity(), Function::andThen);
    }
    
    // 5. 批量处理
    public static <T, R> List<R> batchProcess(List<T> items, Function<T, R> processor, int batchSize) {
        return items.stream()
            .collect(Collectors.groupingBy(item -> items.indexOf(item) / batchSize))
            .values()
            .stream()
            .flatMap(batch -> batch.stream().map(processor))
            .collect(Collectors.toList());
    }
    
    // 6. 异步执行
    public static <T> CompletableFuture<T> asyncExecute(Supplier<T> supplier) {
        return CompletableFuture.supplyAsync(supplier);
    }
    
    // 7. 缓存函数结果
    public static <T, R> Function<T, R> memoize(Function<T, R> function) {
        Map<T, R> cache = new ConcurrentHashMap<>();
        return input -> cache.computeIfAbsent(input, function);
    }
    
    // 8. 组合多个谓词
    @SafeVarargs
    public static <T> Predicate<T> allOf(Predicate<T>... predicates) {
        return Arrays.stream(predicates)
            .reduce(Predicate::and)
            .orElse(x -> true);
    }
    
    @SafeVarargs
    public static <T> Predicate<T> anyOf(Predicate<T>... predicates) {
        return Arrays.stream(predicates)
            .reduce(Predicate::or)
            .orElse(x -> false);
    }
    
    // 9. 函数柯里化
    public static <T, U, R> Function<T, Function<U, R>> curry(BiFunction<T, U, R> function) {
        return t -> u -> function.apply(t, u);
    }
    
    // 10. 部分应用
    public static <T, U, R> Function<U, R> partial(BiFunction<T, U, R> function, T first) {
        return u -> function.apply(first, u);
    }
}

// 使用示例
public class LambdaUtilsExample {
    public static void main(String[] args) {
        // 安全执行
        Optional<String> result = LambdaUtils.safeApply(
            str -> str.toUpperCase(), "hello");
        System.out.println("安全执行结果: " + result); // 输出: 安全执行结果: Optional[HELLO]
        
        // 重试机制
        String retryResult = LambdaUtils.retry(
            () -> "成功", 3);
        System.out.println("重试结果: " + retryResult); // 输出: 重试结果: 成功
        
        // 条件执行
        Optional<String> conditionalResult = LambdaUtils.executeIf(
            str -> str.length() > 3,
            str -> str.toUpperCase(),
            "hello");
        System.out.println("条件执行结果: " + conditionalResult); // 输出: 条件执行结果: Optional[HELLO]
        
        // 管道处理
        Function<String, String> pipeline = LambdaUtils.pipeline(
            String::toUpperCase,
            str -> str + "!",
            str -> "处理结果: " + str
        );
        System.out.println("管道处理: " + pipeline.apply("hello")); // 输出: 管道处理: 处理结果: HELLO!
        
        // 批量处理
        List<String> items = Arrays.asList("a", "b", "c", "d", "e");
        List<String> processed = LambdaUtils.batchProcess(
            items, str -> str.toUpperCase(), 2);
        System.out.println("批量处理结果: " + processed); // 输出: 批量处理结果: [A, B, C, D, E]
        
        // 组合谓词
        Predicate<String> combined = LambdaUtils.allOf(
            str -> str.length() > 3,
            str -> str.startsWith("h")
        );
        System.out.println("组合谓词测试: " + combined.test("hello")); // 输出: 组合谓词测试: true
        
        // 柯里化
        BiFunction<Integer, Integer, Integer> add = (a, b) -> a + b;
        Function<Integer, Function<Integer, Integer>> curriedAdd = LambdaUtils.curry(add);
        Function<Integer, Integer> addFive = curriedAdd.apply(5);
        System.out.println("柯里化结果: " + addFive.apply(3)); // 输出: 柯里化结果: 8
    }
}

Lambda表达式的注意事项:

  1. 语法规则
    • 参数类型可以省略(类型推断)
    • 单个参数可以省略括号
    • 单行表达式可以省略return和大括号
    • 多行表达式需要大括号和return
  2. 变量捕获
    • 只能捕获final或effectively final的变量
    • 不能修改捕获的变量
    • 可以访问实例变量和静态变量
  3. 性能考虑
    • 避免在循环中重复创建Lambda
    • 使用并行流提高性能
    • 缓存常用的Lambda表达式
    • 避免不必要的装箱拆箱
  4. 常见陷阱
    • 变量捕获的限制
    • 异常处理
    • 递归Lambda的实现
    • 并发环境下的使用
  5. 最佳实践
    • 优先使用方法引用
    • 合理使用函数式接口
    • 注意代码可读性
    • 适当使用Stream API
  6. 应用场景
    • 集合操作和遍历
    • 事件处理
    • 异步编程
    • 函数式编程
    • 回调函数
7.11 Apache Commons IO

Commons IO简介:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Maven依赖
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.15.1</version>
</dependency>

// Gradle依赖
implementation 'commons-io:commons-io:2.15.1'

// 主要包结构
import org.apache.commons.io.*;
import org.apache.commons.io.file.*;
import org.apache.commons.io.input.*;
import org.apache.commons.io.output.*;
import org.apache.commons.io.monitor.*;

FileUtils工具类:

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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import org.apache.commons.io.FileUtils;
import java.io.*;
import java.nio.charset.StandardCharsets;

// 1. 文件读写操作
public class FileUtilsExample {
    
    public static void fileOperations() throws IOException {
        // 读取文件内容
        String content = FileUtils.readFileToString(new File("input.txt"), StandardCharsets.UTF_8);
        System.out.println("文件内容: " + content);
        
        // 写入文件内容
        FileUtils.writeStringToFile(new File("output.txt"), "Hello Commons IO", StandardCharsets.UTF_8);
        
        // 追加内容
        FileUtils.writeStringToFile(new File("output.txt"), "\n追加内容", StandardCharsets.UTF_8, true);
        
        // 读取文件为字节数组
        byte[] bytes = FileUtils.readFileToByteArray(new File("input.txt"));
        System.out.println("文件大小: " + bytes.length + " bytes");
        
        // 写入字节数组到文件
        FileUtils.writeByteArrayToFile(new File("output.bin"), bytes);
        
        // 按行读取文件
        List<String> lines = FileUtils.readLines(new File("input.txt"), StandardCharsets.UTF_8);
        lines.forEach(System.out::println);
        
        // 按行写入文件
        List<String> writeLines = Arrays.asList("第一行", "第二行", "第三行");
        FileUtils.writeLines(new File("lines.txt"), writeLines, StandardCharsets.UTF_8);
    }
    
    // 2. 文件操作
    public static void fileManipulation() throws IOException {
        File source = new File("source.txt");
        File dest = new File("dest.txt");
        
        // 复制文件
        FileUtils.copyFile(source, dest);
        System.out.println("文件复制完成");
        
        // 复制目录
        FileUtils.copyDirectory(new File("sourceDir"), new File("destDir"));
        System.out.println("目录复制完成");
        
        // 移动文件
        FileUtils.moveFile(source, new File("moved.txt"));
        System.out.println("文件移动完成");
        
        // 删除文件或目录
        FileUtils.deleteQuietly(new File("temp.txt")); // 静默删除,不抛异常
        FileUtils.forceDelete(new File("tempDir"));    // 强制删除,抛异常
        
        // 创建目录
        FileUtils.forceMkdir(new File("newDir"));
        System.out.println("目录创建完成");
        
        // 清理目录
        FileUtils.cleanDirectory(new File("tempDir")); // 删除目录内容,保留目录
        System.out.println("目录清理完成");
    }
    
    // 3. 文件信息
    public static void fileInfo() throws IOException {
        File file = new File("example.txt");
        
        // 获取文件大小
        long size = FileUtils.sizeOf(file);
        System.out.println("文件大小: " + size + " bytes");
        
        // 获取目录大小
        long dirSize = FileUtils.sizeOfDirectory(new File("exampleDir"));
        System.out.println("目录大小: " + dirSize + " bytes");
        
        // 获取文件大小(人类可读格式)
        String humanReadableSize = FileUtils.byteCountToDisplaySize(size);
        System.out.println("可读大小: " + humanReadableSize);
        
        // 检查文件是否为空
        boolean isEmpty = FileUtils.isEmptyDirectory(new File("emptyDir"));
        System.out.println("目录是否为空: " + isEmpty);
        
        // 获取文件修改时间
        Date lastModified = new Date(file.lastModified());
        System.out.println("最后修改时间: " + lastModified);
    }
    
    // 4. 文件比较
    public static void fileComparison() throws IOException {
        File file1 = new File("file1.txt");
        File file2 = new File("file2.txt");
        
        // 比较文件内容
        boolean isEqual = FileUtils.contentEquals(file1, file2);
        System.out.println("文件内容是否相同: " + isEqual);
        
        // 比较文件内容(忽略行结束符)
        boolean isEqualIgnoreEOL = FileUtils.contentEqualsIgnoreEOL(file1, file2, StandardCharsets.UTF_8);
        System.out.println("文件内容是否相同(忽略行结束符): " + isEqualIgnoreEOL);
    }
}

IOUtils工具类:

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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import org.apache.commons.io.IOUtils;
import java.io.*;
import java.net.URL;
import java.nio.charset.StandardCharsets;

public class IOUtilsExample {
    
    // 1. 流操作
    public static void streamOperations() throws IOException {
        // 复制流
        InputStream input = new FileInputStream("input.txt");
        OutputStream output = new FileOutputStream("output.txt");
        IOUtils.copy(input, output);
        IOUtils.closeQuietly(input, output);
        
        // 复制流(指定缓冲区大小)
        IOUtils.copy(input, output, 8192);
        
        // 复制流到字符串
        String content = IOUtils.toString(input, StandardCharsets.UTF_8);
        System.out.println("流内容: " + content);
        
        // 复制字符串到流
        IOUtils.write("Hello IOUtils", output, StandardCharsets.UTF_8);
        
        // 复制流到字节数组
        byte[] bytes = IOUtils.toByteArray(input);
        System.out.println("字节数组大小: " + bytes.length);
        
        // 复制字节数组到流
        IOUtils.write(bytes, output);
        
        // 按行读取
        List<String> lines = IOUtils.readLines(input, StandardCharsets.UTF_8);
        lines.forEach(System.out::println);
        
        // 按行写入
        IOUtils.writeLines(lines, "\n", output, StandardCharsets.UTF_8);
    }
    
    // 2. 网络操作
    public static void networkOperations() throws IOException {
        // 从URL读取内容
        URL url = new URL("https://www.example.com");
        String content = IOUtils.toString(url, StandardCharsets.UTF_8);
        System.out.println("网页内容长度: " + content.length());
        
        // 从URL读取字节数组
        byte[] bytes = IOUtils.toByteArray(url);
        System.out.println("网页字节大小: " + bytes.length);
        
        // 下载文件
        try (InputStream input = url.openStream();
             FileOutputStream output = new FileOutputStream("downloaded.html")) {
            IOUtils.copy(input, output);
        }
    }
    
    // 3. 流转换
    public static void streamConversion() throws IOException {
        // 字符串转输入流
        String text = "Hello World";
        InputStream inputStream = IOUtils.toInputStream(text, StandardCharsets.UTF_8);
        
        // 字节数组转输入流
        byte[] bytes = "Hello Bytes".getBytes(StandardCharsets.UTF_8);
        InputStream byteStream = IOUtils.toInputStream(bytes);
        
        // 读取所有内容
        String allContent = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
        System.out.println("转换后的内容: " + allContent);
    }
    
    // 4. 流监控
    public static void streamMonitoring() throws IOException {
        InputStream input = new FileInputStream("large.txt");
        
        // 创建带进度监控的流
        InputStream monitoredStream = new ProgressMonitorInputStream(
            null, "读取文件", input);
        
        // 读取内容
        String content = IOUtils.toString(monitoredStream, StandardCharsets.UTF_8);
        System.out.println("文件读取完成");
    }
}

FilenameUtils工具类:

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
import org.apache.commons.io.FilenameUtils;
import java.io.File;

public class FilenameUtilsExample {
    
    public static void filenameOperations() {
        String path = "/home/user/documents/file.txt";
        
        // 获取文件名(不含路径)
        String name = FilenameUtils.getName(path);
        System.out.println("文件名: " + name); // 输出: file.txt
        
        // 获取文件名(不含扩展名)
        String baseName = FilenameUtils.getBaseName(path);
        System.out.println("文件名(不含扩展名): " + baseName); // 输出: file
        
        // 获取扩展名
        String extension = FilenameUtils.getExtension(path);
        System.out.println("扩展名: " + extension); // 输出: txt
        
        // 获取完整路径(不含文件名)
        String fullPath = FilenameUtils.getFullPath(path);
        System.out.println("完整路径: " + fullPath); // 输出: /home/user/documents/
        
        // 获取路径(不含文件名)
        String pathOnly = FilenameUtils.getPath(path);
        System.out.println("路径: " + pathOnly); // 输出: home/user/documents/
        
        // 获取前缀
        String prefix = FilenameUtils.getPrefix(path);
        System.out.println("前缀: " + prefix); // 输出: /
        
        // 规范化路径
        String normalized = FilenameUtils.normalize(path);
        System.out.println("规范化路径: " + normalized);
        
        // 连接路径
        String joined = FilenameUtils.concat("/home/user", "documents/file.txt");
        System.out.println("连接路径: " + joined); // 输出: /home/user/documents/file.txt
        
        // 检查扩展名
        boolean isTxt = FilenameUtils.isExtension(path, "txt");
        System.out.println("是否为txt文件: " + isTxt); // 输出: true
        
        boolean isImage = FilenameUtils.isExtension(path, "jpg", "png", "gif");
        System.out.println("是否为图片文件: " + isImage); // 输出: false
        
        // 移除扩展名
        String withoutExt = FilenameUtils.removeExtension(path);
        System.out.println("移除扩展名: " + withoutExt); // 输出: /home/user/documents/file
        
        // 更改扩展名
        String newExt = FilenameUtils.getBaseName(path) + ".bak";
        System.out.println("新文件名: " + newExt); // 输出: file.bak
    }
}

FileSystemUtils工具类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import org.apache.commons.io.FileSystemUtils;
import java.io.IOException;

public class FileSystemUtilsExample {
    
    public static void fileSystemOperations() throws IOException {
        // 获取磁盘空间(字节)
        long freeSpace = FileSystemUtils.freeSpaceKb("/");
        System.out.println("可用空间: " + freeSpace + " KB");
        
        // 获取磁盘空间(MB)
        long freeSpaceMB = FileSystemUtils.freeSpaceKb("/") / 1024;
        System.out.println("可用空间: " + freeSpaceMB + " MB");
        
        // 获取磁盘空间(GB)
        long freeSpaceGB = FileSystemUtils.freeSpaceKb("/") / (1024 * 1024);
        System.out.println("可用空间: " + freeSpaceGB + " GB");
        
        // 检查磁盘空间是否足够
        long requiredSpace = 1024 * 1024; // 1GB in KB
        boolean hasEnoughSpace = FileSystemUtils.freeSpaceKb("/") > requiredSpace;
        System.out.println("是否有足够空间: " + hasEnoughSpace);
    }
}

LineIterator工具类:

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
import org.apache.commons.io.LineIterator;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;

public class LineIteratorExample {
    
    public static void lineIteratorOperations() throws IOException {
        File file = new File("large.txt");
        
        // 使用LineIterator逐行读取大文件
        try (LineIterator lineIterator = FileUtils.lineIterator(file, "UTF-8")) {
            while (lineIterator.hasNext()) {
                String line = lineIterator.nextLine();
                // 处理每一行
                System.out.println("处理行: " + line);
                
                // 可以在这里添加处理逻辑
                if (line.startsWith("ERROR")) {
                    System.out.println("发现错误行: " + line);
                }
            }
        }
        
        // 统计行数
        try (LineIterator lineIterator = FileUtils.lineIterator(file, "UTF-8")) {
            int lineCount = 0;
            while (lineIterator.hasNext()) {
                lineIterator.nextLine();
                lineCount++;
            }
            System.out.println("文件总行数: " + lineCount);
        }
        
        // 查找特定行
        try (LineIterator lineIterator = FileUtils.lineIterator(file, "UTF-8")) {
            int lineNumber = 0;
            while (lineIterator.hasNext()) {
                lineNumber++;
                String line = lineIterator.nextLine();
                if (line.contains("target")) {
                    System.out.println("在第" + lineNumber + "行找到目标: " + line);
                    break;
                }
            }
        }
    }
}

文件监控器:

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 org.apache.commons.io.monitor.FileAlterationListener;
import org.apache.commons.io.monitor.FileAlterationListenerAdaptor;
import org.apache.commons.io.monitor.FileAlterationMonitor;
import org.apache.commons.io.monitor.FileAlterationObserver;
import java.io.File;

public class FileMonitorExample {
    
    public static void fileMonitoring() throws Exception {
        // 创建文件监听器
        FileAlterationListener listener = new FileAlterationListenerAdaptor() {
            @Override
            public void onFileCreate(File file) {
                System.out.println("文件创建: " + file.getName());
            }
            
            @Override
            public void onFileDelete(File file) {
                System.out.println("文件删除: " + file.getName());
            }
            
            @Override
            public void onFileChange(File file) {
                System.out.println("文件修改: " + file.getName());
            }
            
            @Override
            public void onDirectoryCreate(File directory) {
                System.out.println("目录创建: " + directory.getName());
            }
            
            @Override
            public void onDirectoryDelete(File directory) {
                System.out.println("目录删除: " + directory.getName());
            }
            
            @Override
            public void onDirectoryChange(File directory) {
                System.out.println("目录修改: " + directory.getName());
            }
        };
        
        // 创建观察者
        FileAlterationObserver observer = new FileAlterationObserver(
            new File("monitored_dir"), null, null);
        observer.addListener(listener);
        
        // 创建监控器
        FileAlterationMonitor monitor = new FileAlterationMonitor(1000); // 1秒检查一次
        monitor.addObserver(observer);
        
        // 启动监控
        monitor.start();
        System.out.println("文件监控已启动,监控目录: monitored_dir");
        
        // 运行一段时间后停止
        Thread.sleep(30000); // 运行30秒
        monitor.stop();
        System.out.println("文件监控已停止");
    }
}

实用工具类组合使用:

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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
import org.apache.commons.io.*;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.List;

public class CommonsIOUtils {
    
    // 1. 文件备份工具
    public static void backupFile(String sourcePath, String backupPath) throws IOException {
        File source = new File(sourcePath);
        File backup = new File(backupPath);
        
        if (source.exists()) {
            // 创建备份目录
            FileUtils.forceMkdirParent(backup);
            
            // 复制文件
            FileUtils.copyFile(source, backup);
            System.out.println("文件备份完成: " + backupPath);
        } else {
            System.out.println("源文件不存在: " + sourcePath);
        }
    }
    
    // 2. 批量文件处理
    public static void batchProcessFiles(String directory, String extension) throws IOException {
        File dir = new File(directory);
        if (!dir.exists() || !dir.isDirectory()) {
            System.out.println("目录不存在: " + directory);
            return;
        }
        
        // 获取所有指定扩展名的文件
        String[] files = dir.list((dir1, name) -> name.endsWith(extension));
        
        if (files != null) {
            for (String fileName : files) {
                File file = new File(dir, fileName);
                processFile(file);
            }
        }
    }
    
    private static void processFile(File file) throws IOException {
        // 读取文件内容
        String content = FileUtils.readFileToString(file, StandardCharsets.UTF_8);
        
        // 处理内容(示例:转换为大写)
        String processedContent = content.toUpperCase();
        
        // 写入处理后的内容
        FileUtils.writeStringToFile(file, processedContent, StandardCharsets.UTF_8);
        
        System.out.println("文件处理完成: " + file.getName());
    }
    
    // 3. 日志文件分析
    public static void analyzeLogFile(String logPath) throws IOException {
        File logFile = new File(logPath);
        
        if (!logFile.exists()) {
            System.out.println("日志文件不存在: " + logPath);
            return;
        }
        
        // 统计行数
        List<String> lines = FileUtils.readLines(logFile, StandardCharsets.UTF_8);
        int totalLines = lines.size();
        
        // 统计错误行数
        long errorLines = lines.stream()
            .filter(line -> line.contains("ERROR"))
            .count();
        
        // 统计警告行数
        long warningLines = lines.stream()
            .filter(line -> line.contains("WARN"))
            .count();
        
        // 统计信息行数
        long infoLines = lines.stream()
            .filter(line -> line.contains("INFO"))
            .count();
        
        System.out.println("日志文件分析结果:");
        System.out.println("  总行数: " + totalLines);
        System.out.println("  错误行数: " + errorLines);
        System.out.println("  警告行数: " + warningLines);
        System.out.println("  信息行数: " + infoLines);
        System.out.println("  文件大小: " + FileUtils.byteCountToDisplaySize(logFile.length()));
    }
    
    // 4. 文件同步工具
    public static void syncDirectories(String sourceDir, String targetDir) throws IOException {
        File source = new File(sourceDir);
        File target = new File(targetDir);
        
        if (!source.exists() || !source.isDirectory()) {
            System.out.println("源目录不存在: " + sourceDir);
            return;
        }
        
        // 创建目标目录
        FileUtils.forceMkdir(target);
        
        // 复制目录
        FileUtils.copyDirectory(source, target);
        System.out.println("目录同步完成: " + targetDir);
    }
    
    // 5. 文件清理工具
    public static void cleanupOldFiles(String directory, long maxAge) {
        File dir = new File(directory);
        if (!dir.exists() || !dir.isDirectory()) {
            System.out.println("目录不存在: " + directory);
            return;
        }
        
        File[] files = dir.listFiles();
        if (files != null) {
            long currentTime = System.currentTimeMillis();
            int deletedCount = 0;
            
            for (File file : files) {
                if (file.isFile()) {
                    long fileAge = currentTime - file.lastModified();
                    if (fileAge > maxAge) {
                        if (FileUtils.deleteQuietly(file)) {
                            deletedCount++;
                            System.out.println("删除旧文件: " + file.getName());
                        }
                    }
                }
            }
            
            System.out.println("清理完成,共删除 " + deletedCount + " 个文件");
        }
    }
}

// 使用示例
public class CommonsIOExample {
    public static void main(String[] args) {
        try {
            // 文件备份
            CommonsIOUtils.backupFile("important.txt", "backup/important.txt.bak");
            
            // 批量处理
            CommonsIOUtils.batchProcessFiles("documents", ".txt");
            
            // 日志分析
            CommonsIOUtils.analyzeLogFile("application.log");
            
            // 目录同步
            CommonsIOUtils.syncDirectories("source", "backup");
            
            // 清理旧文件(7天前)
            CommonsIOUtils.cleanupOldFiles("temp", 7 * 24 * 60 * 60 * 1000L);
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Commons IO的注意事项:

  1. 性能考虑
    • 大文件操作时使用流式处理
    • 避免一次性加载大文件到内存
    • 使用LineIterator处理大文本文件
  2. 异常处理
    • 使用closeQuietly方法安全关闭流
    • 处理IO异常和文件不存在异常
    • 使用try-with-resources语句
  3. 字符编码
    • 明确指定字符编码,避免平台差异
    • 使用StandardCharsets常量
    • 处理编码异常
  4. 文件操作
    • 检查文件存在性
    • 创建必要的目录
    • 处理文件权限问题
  5. 最佳实践
    • 使用工具类简化代码
    • 合理使用文件监控
    • 注意跨平台兼容性
  6. 应用场景
    • 文件操作和IO处理
    • 日志文件分析
    • 文件备份和同步
    • 批量文件处理
    • 文件监控和事件处理
7.12 Hutool工具库

Hutool简介:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Maven依赖
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.8.25</version>
</dependency>

// Gradle依赖
implementation 'cn.hutool:hutool-all:5.8.25'

// 主要模块
import cn.hutool.core.util.*;
import cn.hutool.core.lang.*;
import cn.hutool.core.date.*;
import cn.hutool.core.io.*;
import cn.hutool.core.text.*;
import cn.hutool.core.collection.*;
import cn.hutool.core.map.*;
import cn.hutool.crypto.*;
import cn.hutool.http.*;
import cn.hutool.json.*;
import cn.hutool.db.*;
import cn.hutool.poi.*;

StrUtil字符串工具类:

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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.text.CharSequenceUtil;

public class StrUtilExample {
    
    public static void stringOperations() {
        // 1. 字符串判空
        String str1 = "";
        String str2 = null;
        String str3 = "  ";
        String str4 = "hello";
        
        System.out.println("isEmpty: " + StrUtil.isEmpty(str1));      // true
        System.out.println("isEmpty: " + StrUtil.isEmpty(str2));      // true
        System.out.println("isBlank: " + StrUtil.isBlank(str3));      // true
        System.out.println("isNotBlank: " + StrUtil.isNotBlank(str4)); // true
        
        // 2. 字符串格式化
        String template = "Hello {}, welcome to {}!";
        String result = StrUtil.format(template, "World", "Java");
        System.out.println("格式化结果: " + result); // Hello World, welcome to Java!
        
        // 3. 字符串截取
        String text = "Hello World Java";
        String sub1 = StrUtil.sub(text, 0, 5);           // Hello
        String sub2 = StrUtil.subAfter(text, " ", false); // World Java
        String sub3 = StrUtil.subBefore(text, " ", false); // Hello
        
        System.out.println("截取1: " + sub1);
        System.out.println("截取2: " + sub2);
        System.out.println("截取3: " + sub3);
        
        // 4. 字符串替换
        String original = "Hello World World";
        String replaced = StrUtil.replace(original, "World", "Java");
        System.out.println("替换结果: " + replaced); // Hello Java Java
        
        // 5. 字符串分割
        String csv = "apple,banana,orange,grape";
        String[] fruits = StrUtil.split(csv, ',');
        System.out.println("分割结果: " + Arrays.toString(fruits));
        
        // 6. 字符串连接
        String[] words = {"Hello", "World", "Java"};
        String joined = StrUtil.join(", ", words);
        System.out.println("连接结果: " + joined); // Hello, World, Java
        
        // 7. 字符串填充
        String padded = StrUtil.padPre("123", 5, '0');
        System.out.println("左填充: " + padded); // 00123
        
        String padded2 = StrUtil.padAfter("123", 5, '0');
        System.out.println("右填充: " + padded2); // 12300
        
        // 8. 字符串反转
        String reversed = StrUtil.reverse("Hello");
        System.out.println("反转结果: " + reversed); // olleH
        
        // 9. 驼峰转换
        String camelCase = StrUtil.toCamelCase("hello_world");
        System.out.println("驼峰转换: " + camelCase); // helloWorld
        
        String underLine = StrUtil.toUnderlineCase("helloWorld");
        System.out.println("下划线转换: " + underLine); // hello_world
        
        // 10. 字符串模板
        String template2 = "姓名:{name},年龄:{age},城市:{city}";
        Map<String, Object> params = new HashMap<>();
        params.put("name", "张三");
        params.put("age", 25);
        params.put("city", "北京");
        
        String result2 = StrUtil.format(template2, params);
        System.out.println("模板结果: " + result2); // 姓名:张三,年龄:25,城市:北京
    }
}

DateUtil日期工具类:

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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DatePattern;
import java.util.Date;

public class DateUtilExample {
    
    public static void dateOperations() {
        // 1. 日期解析
        String dateStr = "2025-05-15 14:30:45";
        DateTime date = DateUtil.parse(dateStr);
        System.out.println("解析日期: " + date);
        
        // 2. 日期格式化
        String formatted = DateUtil.format(date, DatePattern.NORM_DATETIME_PATTERN);
        System.out.println("格式化日期: " + formatted);
        
        // 3. 获取当前时间
        DateTime now = DateUtil.date();
        System.out.println("当前时间: " + now);
        
        // 4. 日期计算
        DateTime tomorrow = DateUtil.tomorrow();
        DateTime yesterday = DateUtil.yesterday();
        DateTime nextWeek = DateUtil.nextWeek();
        DateTime nextMonth = DateUtil.nextMonth();
        
        System.out.println("明天: " + tomorrow);
        System.out.println("昨天: " + yesterday);
        System.out.println("下周: " + nextWeek);
        System.out.println("下月: " + nextMonth);
        
        // 5. 日期偏移
        DateTime offset1 = DateUtil.offsetDay(now, 7);    // 7天后
        DateTime offset2 = DateUtil.offsetMonth(now, 1);  // 1个月后
        DateTime offset3 = DateUtil.offsetYear(now, 1);   // 1年后
        
        System.out.println("7天后: " + offset1);
        System.out.println("1个月后: " + offset2);
        System.out.println("1年后: " + offset3);
        
        // 6. 日期比较
        DateTime date1 = DateUtil.parse("2025-05-15");
        DateTime date2 = DateUtil.parse("2025-05-20");
        
        boolean isAfter = DateUtil.isAfter(date2, date1);
        boolean isBefore = DateUtil.isBefore(date1, date2);
        boolean isSame = DateUtil.isSameDay(date1, date2);
        
        System.out.println("date2在date1之后: " + isAfter);
        System.out.println("date1在date2之前: " + isBefore);
        System.out.println("同一天: " + isSame);
        
        // 7. 获取时间戳
        long timestamp = DateUtil.current();
        System.out.println("当前时间戳: " + timestamp);
        
        // 8. 时间差计算
        long betweenDays = DateUtil.betweenDay(date1, date2, false);
        long betweenHours = DateUtil.betweenHour(date1, date2, false);
        long betweenMinutes = DateUtil.betweenMinute(date1, date2, false);
        
        System.out.println("相差天数: " + betweenDays);
        System.out.println("相差小时: " + betweenHours);
        System.out.println("相差分钟: " + betweenMinutes);
        
        // 9. 获取日期部分
        int year = DateUtil.year(date);
        int month = DateUtil.month(date) + 1; // 月份从0开始
        int day = DateUtil.dayOfMonth(date);
        int hour = DateUtil.hour(date, true);
        int minute = DateUtil.minute(date);
        int second = DateUtil.second(date);
        
        System.out.println("年: " + year + ", 月: " + month + ", 日: " + day);
        System.out.println("时: " + hour + ", 分: " + minute + ", 秒: " + second);
        
        // 10. 日期范围
        DateTime start = DateUtil.beginOfDay(date);
        DateTime end = DateUtil.endOfDay(date);
        
        System.out.println("当天开始: " + start);
        System.out.println("当天结束: " + end);
        
        // 11. 星期相关
        int week = DateUtil.dayOfWeek(date);
        String weekName = DateUtil.dayOfWeekEnum(date).toChinese();
        
        System.out.println("星期几(数字): " + week);
        System.out.println("星期几(中文): " + weekName);
    }
}

CollUtil集合工具类:

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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import java.util.*;

public class CollUtilExample {
    
    public static void collectionOperations() {
        // 1. 创建集合
        List<String> list1 = CollUtil.newArrayList("a", "b", "c");
        Set<String> set1 = CollUtil.newHashSet("x", "y", "z");
        Map<String, String> map1 = CollUtil.newHashMap("key1", "value1", "key2", "value2");
        
        System.out.println("列表: " + list1);
        System.out.println("集合: " + set1);
        System.out.println("映射: " + map1);
        
        // 2. 集合判空
        List<String> emptyList = new ArrayList<>();
        List<String> nullList = null;
        
        System.out.println("isEmpty: " + CollUtil.isEmpty(emptyList));    // true
        System.out.println("isEmpty: " + CollUtil.isEmpty(nullList));     // true
        System.out.println("isNotEmpty: " + CollUtil.isNotEmpty(list1)); // true
        
        // 3. 集合操作
        List<String> list2 = Arrays.asList("d", "e", "f");
        
        // 并集
        List<String> union = CollUtil.union(list1, list2);
        System.out.println("并集: " + union);
        
        // 交集
        List<String> intersection = CollUtil.intersection(list1, list2);
        System.out.println("交集: " + intersection);
        
        // 差集
        List<String> difference = CollUtil.disjunction(list1, list2);
        System.out.println("差集: " + difference);
        
        // 4. 集合转换
        // 列表转数组
        String[] array = CollUtil.toArray(list1, String.class);
        System.out.println("转数组: " + Arrays.toString(array));
        
        // 数组转列表
        List<String> listFromArray = CollUtil.toList(array);
        System.out.println("转列表: " + listFromArray);
        
        // 5. 集合分组
        List<Person> persons = Arrays.asList(
            new Person("张三", 25, "北京"),
            new Person("李四", 30, "上海"),
            new Person("王五", 25, "北京"),
            new Person("赵六", 35, "广州")
        );
        
        Map<Integer, List<Person>> ageGroup = CollUtil.groupByField(persons, "age");
        System.out.println("按年龄分组: " + ageGroup);
        
        Map<String, List<Person>> cityGroup = CollUtil.groupByField(persons, "city");
        System.out.println("按城市分组: " + cityGroup);
        
        // 6. 集合排序
        List<Integer> numbers = Arrays.asList(3, 1, 4, 1, 5, 9, 2, 6);
        CollUtil.sort(numbers);
        System.out.println("排序后: " + numbers);
        
        // 自定义排序
        CollUtil.sort(persons, (p1, p2) -> Integer.compare(p1.getAge(), p2.getAge()));
        System.out.println("按年龄排序: " + persons);
        
        // 7. 集合分页
        List<String> longList = Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h", "i", "j");
        List<String> page1 = CollUtil.page(0, 3, longList);
        List<String> page2 = CollUtil.page(1, 3, longList);
        
        System.out.println("第1页: " + page1); // [a, b, c]
        System.out.println("第2页: " + page2); // [d, e, f]
        
        // 8. 集合去重
        List<String> duplicateList = Arrays.asList("a", "b", "a", "c", "b", "d");
        List<String> uniqueList = CollUtil.distinct(duplicateList);
        System.out.println("去重后: " + uniqueList);
        
        // 9. 集合过滤
        List<String> filtered = CollUtil.filter(list1, str -> str.startsWith("a"));
        System.out.println("过滤后: " + filtered);
        
        // 10. 集合映射
        List<String> mapped = CollUtil.map(list1, String::toUpperCase);
        System.out.println("映射后: " + mapped);
    }
    
    static class Person {
        private String name;
        private int age;
        private String city;
        
        public Person(String name, int age, String city) {
            this.name = name;
            this.age = age;
            this.city = city;
        }
        
        public String getName() { return name; }
        public int getAge() { return age; }
        public String getCity() { return city; }
        
        @Override
        public String toString() {
            return name + "(" + age + "," + city + ")";
        }
    }
}

HttpUtil网络工具类:

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
import cn.hutool.http.HttpUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import java.util.HashMap;
import java.util.Map;

public class HttpUtilExample {
    
    public static void httpOperations() {
        // 1. GET请求
        String getResult = HttpUtil.get("https://httpbin.org/get");
        System.out.println("GET响应: " + getResult);
        
        // 带参数的GET请求
        Map<String, Object> params = new HashMap<>();
        params.put("name", "张三");
        params.put("age", 25);
        
        String getWithParams = HttpUtil.get("https://httpbin.org/get", params);
        System.out.println("带参数GET响应: " + getWithParams);
        
        // 2. POST请求
        String postResult = HttpUtil.post("https://httpbin.org/post", "Hello World");
        System.out.println("POST响应: " + postResult);
        
        // POST表单数据
        Map<String, Object> formData = new HashMap<>();
        formData.put("username", "admin");
        formData.put("password", "123456");
        
        String postForm = HttpUtil.post("https://httpbin.org/post", formData);
        System.out.println("POST表单响应: " + postForm);
        
        // 3. 设置请求头
        HttpResponse response = HttpRequest.get("https://httpbin.org/headers")
            .header("User-Agent", "Hutool/1.0")
            .header("Authorization", "Bearer token123")
            .execute();
        
        System.out.println("带请求头响应: " + response.body());
        
        // 4. 设置超时
        HttpResponse timeoutResponse = HttpRequest.get("https://httpbin.org/delay/5")
            .timeout(3000) // 3秒超时
            .execute();
        
        System.out.println("超时响应状态: " + timeoutResponse.getStatus());
        
        // 5. 异步请求
        HttpRequest.get("https://httpbin.org/get")
            .async()
            .thenAccept(resp -> {
                System.out.println("异步响应: " + resp.body());
            });
    }
}

JSONUtil JSON工具类:

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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
import cn.hutool.json.JSONUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONArray;
import java.util.*;

public class JSONUtilExample {
    
    public static void jsonOperations() {
        // 1. 对象转JSON
        Person person = new Person("张三", 25, "北京");
        String jsonStr = JSONUtil.toJsonStr(person);
        System.out.println("对象转JSON: " + jsonStr);
        
        // 2. JSON转对象
        Person parsedPerson = JSONUtil.toBean(jsonStr, Person.class);
        System.out.println("JSON转对象: " + parsedPerson);
        
        // 3. 创建JSONObject
        JSONObject jsonObject = JSONUtil.createObj()
            .put("name", "李四")
            .put("age", 30)
            .put("city", "上海")
            .put("hobbies", Arrays.asList("读书", "游泳", "编程"));
        
        System.out.println("JSONObject: " + jsonObject);
        
        // 4. 获取JSON值
        String name = jsonObject.getStr("name");
        int age = jsonObject.getInt("age");
        List<String> hobbies = jsonObject.getBeanList("hobbies", String.class);
        
        System.out.println("姓名: " + name);
        System.out.println("年龄: " + age);
        System.out.println("爱好: " + hobbies);
        
        // 5. 创建JSONArray
        JSONArray jsonArray = JSONUtil.createArray()
            .add(person)
            .add(new Person("王五", 35, "广州"))
            .add(new Person("赵六", 28, "深圳"));
        
        System.out.println("JSONArray: " + jsonArray);
        
        // 6. 遍历JSONArray
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject obj = jsonArray.getJSONObject(i);
            System.out.println("第" + (i+1) + "个人: " + obj.getStr("name"));
        }
        
        // 7. JSONArray转List
        List<Person> personList = jsonArray.toList(Person.class);
        System.out.println("转List: " + personList);
        
        // 8. 复杂JSON操作
        String complexJson = """
            {
                "company": {
                    "name": "科技有限公司",
                    "employees": [
                        {"name": "张三", "age": 25, "department": "技术部"},
                        {"name": "李四", "age": 30, "department": "产品部"},
                        {"name": "王五", "age": 35, "department": "技术部"}
                    ]
                }
            }
            """;
        
        JSONObject companyJson = JSONUtil.parseObj(complexJson);
        String companyName = companyJson.getByPath("company.name", String.class);
        JSONArray employees = companyJson.getByPath("company.employees", JSONArray.class);
        
        System.out.println("公司名称: " + companyName);
        System.out.println("员工数量: " + employees.size());
        
        // 9. JSON格式化
        String formattedJson = JSONUtil.formatJsonStr(complexJson);
        System.out.println("格式化JSON:\n" + formattedJson);
        
        // 10. JSON验证
        boolean isValid = JSONUtil.isTypeJSON(complexJson);
        System.out.println("是否为有效JSON: " + isValid);
        
        // 11. JSON合并
        JSONObject obj1 = JSONUtil.createObj().put("a", 1).put("b", 2);
        JSONObject obj2 = JSONUtil.createObj().put("c", 3).put("d", 4);
        JSONObject merged = JSONUtil.merge(obj1, obj2);
        System.out.println("合并结果: " + merged);
    }
    
    static class Person {
        private String name;
        private int age;
        private String city;
        
        public Person(String name, int age, String city) {
            this.name = name;
            this.age = age;
            this.city = city;
        }
        
        public String getName() { return name; }
        public int getAge() { return age; }
        public String getCity() { return city; }
        
        @Override
        public String toString() {
            return name + "(" + age + "," + city + ")";
        }
    }
}

Hutool实用工具类组合使用:

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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
import cn.hutool.core.util.*;
import cn.hutool.core.date.*;
import cn.hutool.core.collection.*;
import cn.hutool.http.*;
import cn.hutool.json.*;
import java.util.*;

public class HutoolUtils {
    
    // 1. 配置文件读取工具
    public static void readConfig() {
        // 假设有一个配置文件 config.json
        String configJson = """
            {
                "database": {
                    "url": "jdbc:mysql://localhost:3306/test",
                    "username": "root",
                    "password": "123456"
                },
                "redis": {
                    "host": "localhost",
                    "port": 6379
                }
            }
            """;
        
        JSONObject config = JSONUtil.parseObj(configJson);
        String dbUrl = config.getByPath("database.url", String.class);
        String redisHost = config.getByPath("redis.host", String.class);
        
        System.out.println("数据库URL: " + dbUrl);
        System.out.println("Redis主机: " + redisHost);
    }
    
    // 2. 日志分析工具
    public static void analyzeLog(String logContent) {
        List<String> lines = StrUtil.split(logContent, '\n');
        
        // 统计不同级别的日志
        Map<String, Integer> levelCount = new HashMap<>();
        List<String> errorLines = new ArrayList<>();
        
        for (String line : lines) {
            if (StrUtil.contains(line, "ERROR")) {
                levelCount.merge("ERROR", 1, Integer::sum);
                errorLines.add(line);
            } else if (StrUtil.contains(line, "WARN")) {
                levelCount.merge("WARN", 1, Integer::sum);
            } else if (StrUtil.contains(line, "INFO")) {
                levelCount.merge("INFO", 1, Integer::sum);
            }
        }
        
        System.out.println("日志级别统计: " + levelCount);
        System.out.println("错误日志数量: " + errorLines.size());
    }
    
    // 3. 数据验证工具
    public static boolean validateData(Map<String, Object> data) {
        // 验证必填字段
        String[] requiredFields = {"name", "age", "email"};
        
        for (String field : requiredFields) {
            if (StrUtil.isBlank(StrUtil.toString(data.get(field)))) {
                System.out.println("缺少必填字段: " + field);
                return false;
            }
        }
        
        // 验证年龄
        int age = Convert.toInt(data.get("age"));
        if (age < 0 || age > 150) {
            System.out.println("年龄无效: " + age);
            return false;
        }
        
        // 验证邮箱格式
        String email = StrUtil.toString(data.get("email"));
        if (!ReUtil.isMatch("^[\\w-\\.]+@([\\w-]+\\.)+[\\w-]{2,4}$", email)) {
            System.out.println("邮箱格式无效: " + email);
            return false;
        }
        
        return true;
    }
    
    // 4. 缓存工具
    public static class SimpleCache<K, V> {
        private final Map<K, CacheEntry<V>> cache = new HashMap<>();
        private final long expireTime;
        
        public SimpleCache(long expireTime) {
            this.expireTime = expireTime;
        }
        
        public void put(K key, V value) {
            cache.put(key, new CacheEntry<>(value, System.currentTimeMillis()));
        }
        
        public V get(K key) {
            CacheEntry<V> entry = cache.get(key);
            if (entry != null && !entry.isExpired(expireTime)) {
                return entry.getValue();
            }
            cache.remove(key);
            return null;
        }
        
        public void clear() {
            cache.clear();
        }
        
        private static class CacheEntry<V> {
            private final V value;
            private final long timestamp;
            
            public CacheEntry(V value, long timestamp) {
                this.value = value;
                this.timestamp = timestamp;
            }
            
            public V getValue() { return value; }
            
            public boolean isExpired(long expireTime) {
                return System.currentTimeMillis() - timestamp > expireTime;
            }
        }
    }
    
    // 5. 数据转换工具
    public static <T> T convertValue(Object value, Class<T> targetType) {
        if (value == null) {
            return null;
        }
        
        if (targetType.isAssignableFrom(value.getClass())) {
            return targetType.cast(value);
        }
        
        if (targetType == String.class) {
            return targetType.cast(StrUtil.toString(value));
        }
        
        if (targetType == Integer.class || targetType == int.class) {
            return targetType.cast(Convert.toInt(value));
        }
        
        if (targetType == Long.class || targetType == long.class) {
            return targetType.cast(Convert.toLong(value));
        }
        
        if (targetType == Double.class || targetType == double.class) {
            return targetType.cast(Convert.toDouble(value));
        }
        
        if (targetType == Boolean.class || targetType == boolean.class) {
            return targetType.cast(Convert.toBool(value));
        }
        
        throw new IllegalArgumentException("不支持的类型转换: " + value.getClass() + " -> " + targetType);
    }
}

// 使用示例
public class HutoolExample {
    public static void main(String[] args) {
        // 配置读取
        HutoolUtils.readConfig();
        
        // 日志分析
        String logContent = """
            [INFO] 应用启动成功
            [ERROR] 数据库连接失败
            [WARN] 内存使用率过高
            [ERROR] 文件读取失败
            [INFO] 用户登录成功
            """;
        HutoolUtils.analyzeLog(logContent);
        
        // 数据验证
        Map<String, Object> userData = new HashMap<>();
        userData.put("name", "张三");
        userData.put("age", 25);
        userData.put("email", "zhangsan@example.com");
        
        boolean isValid = HutoolUtils.validateData(userData);
        System.out.println("数据验证结果: " + isValid);
        
        // 缓存使用
        HutoolUtils.SimpleCache<String, String> cache = new HutoolUtils.SimpleCache<>(5000); // 5秒过期
        cache.put("key1", "value1");
        System.out.println("缓存值: " + cache.get("key1"));
        
        // 数据转换
        String numberStr = "123";
        Integer number = HutoolUtils.convertValue(numberStr, Integer.class);
        System.out.println("转换结果: " + number);
    }
}

Hutool的注意事项:

  1. 性能考虑
    • 合理使用缓存机制
    • 避免频繁创建工具类实例
    • 使用连接池管理HTTP连接
  2. 异常处理
    • 处理网络请求异常
    • 处理JSON解析异常
    • 处理加密解密异常
  3. 安全性
    • 使用安全的加密算法
    • 保护敏感信息
    • 验证输入数据
  4. 最佳实践
    • 合理使用工具类
    • 注意版本兼容性
    • 遵循编码规范
  5. 应用场景
    • 快速开发原型
    • 数据处理和转换
    • 网络请求和API调用
    • 文件操作和IO处理
    • 加密和安全处理
7.13 对象克隆

浅克隆(Shallow Clone):

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
62
63
64
65
66
67
68
// 实现Cloneable接口
public class Student implements Cloneable {
    private String name;
    private int age;
    private Address address;  // 引用类型
    
    // 构造方法
    public Student(String name, int age, Address address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }
    
    // 浅克隆方法
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();  // 调用Object的clone方法
    }
    
    // getter和setter方法
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
    public Address getAddress() { return address; }
    public void setAddress(Address address) { this.address = address; }
}

// 地址类
public class Address {
    private String city;
    private String street;
    
    public Address(String city, String street) {
        this.city = city;
        this.street = street;
    }
    
    public String getCity() { return city; }
    public void setCity(String city) { this.city = city; }
    public String getStreet() { return street; }
    public void setStreet(String street) { this.street = street; }
}

// 浅克隆测试
public class CloneTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        Address address = new Address("北京", "长安街");
        Student original = new Student("张三", 20, address);
        
        // 浅克隆
        Student cloned = (Student) original.clone();
        
        System.out.println("原始对象: " + original.getName() + ", " + original.getAddress().getCity());
        // 输出: 原始对象: 张三, 北京
        System.out.println("克隆对象: " + cloned.getName() + ", " + cloned.getAddress().getCity());
        // 输出: 克隆对象: 张三, 北京
        
        // 修改原始对象的引用类型属性
        original.getAddress().setCity("上海");
        
        System.out.println("修改后原始对象: " + original.getName() + ", " + original.getAddress().getCity());
        // 输出: 修改后原始对象: 张三, 上海
        System.out.println("修改后克隆对象: " + cloned.getName() + ", " + cloned.getAddress().getCity());
        // 输出: 修改后克隆对象: 张三, 上海
        // 克隆对象的地址也被修改了!这就是浅克隆的问题
    }
}

深克隆(Deep Clone):

方法一:重写clone方法

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
public class Student implements Cloneable {
    private String name;
    private int age;
    private Address address;
    private List<String> hobbies;  // 集合类型
    
    public Student(String name, int age, Address address, List<String> hobbies) {
        this.name = name;
        this.age = age;
        this.address = address;
        this.hobbies = hobbies;
    }
    
    // 深克隆方法
    @Override
    public Object clone() throws CloneNotSupportedException {
        Student cloned = (Student) super.clone();  // 先进行浅克隆
        
        // 对引用类型进行深克隆
        if (this.address != null) {
            cloned.address = (Address) this.address.clone();
        }
        
        // 对集合类型进行深克隆
        if (this.hobbies != null) {
            cloned.hobbies = new ArrayList<>(this.hobbies);
        }
        
        return cloned;
    }
}

// Address类也需要实现Cloneable
public class Address implements Cloneable {
    private String city;
    private String street;
    
    public Address(String city, String street) {
        this.city = city;
        this.street = street;
    }
    
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
    
    // getter和setter方法
    public String getCity() { return city; }
    public void setCity(String city) { this.city = city; }
    public String getStreet() { return street; }
    public void setStreet(String street) { this.street = street; }
}

方法二:使用序列化实现深克隆

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

public class DeepCloneUtil {
    
    // 通过序列化实现深克隆
    public static <T> T deepClone(T obj) throws Exception {
        if (obj == null) return null;
        
        // 检查对象是否实现了Serializable接口
        if (!(obj instanceof Serializable)) {
            throw new IllegalArgumentException("对象必须实现Serializable接口");
        }
        
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(obj);
        oos.close();
        
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        T cloned = (T) ois.readObject();
        ois.close();
        
        return cloned;
    }
}

// 需要实现Serializable接口
public class Student implements Serializable {
    private static final long serialVersionUID = 1L;
    private String name;
    private int age;
    private Address address;
    private List<String> hobbies;
    
    // 构造方法和getter/setter方法...
    
    // 使用序列化进行深克隆
    public Student deepClone() throws Exception {
        return DeepCloneUtil.deepClone(this);
    }
}

public class Address implements Serializable {
    private static final long serialVersionUID = 1L;
    private String city;
    private String street;
    
    // 构造方法和getter/setter方法...
}

方法三:使用JSON实现深克隆

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
import com.fasterxml.jackson.databind.ObjectMapper;

public class JsonCloneUtil {
    private static final ObjectMapper mapper = new ObjectMapper();
    
    // 通过JSON实现深克隆
    public static <T> T deepClone(T obj, Class<T> clazz) throws Exception {
        if (obj == null) return null;
        
        String json = mapper.writeValueAsString(obj);
        return mapper.readValue(json, clazz);
    }
}

// 使用示例
public class CloneExample {
    public static void main(String[] args) throws Exception {
        Address address = new Address("北京", "长安街");
        List<String> hobbies = Arrays.asList("读书", "游泳");
        Student original = new Student("张三", 20, address, hobbies);
        
        // 使用JSON进行深克隆
        Student cloned = JsonCloneUtil.deepClone(original, Student.class);
        
        // 修改原始对象
        original.getAddress().setCity("上海");
        original.getHobbies().add("编程");
        
        // 克隆对象不受影响
        System.out.println("原始对象地址: " + original.getAddress().getCity());
        // 输出: 原始对象地址: 上海
        System.out.println("克隆对象地址: " + cloned.getAddress().getCity());
        // 输出: 克隆对象地址: 北京
        System.out.println("原始对象爱好数量: " + original.getHobbies().size());
        // 输出: 原始对象爱好数量: 3
        System.out.println("克隆对象爱好数量: " + cloned.getHobbies().size());
        // 输出: 克隆对象爱好数量: 2
    }
}

克隆工具类:

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
public class CloneUtils {
    
    // 通用深克隆方法
    public static <T> T deepClone(T obj) {
        if (obj == null) return null;
        
        try {
            // 优先使用序列化方法
            if (obj instanceof Serializable) {
                return deepCloneBySerialization(obj);
            } else {
                // 使用反射方法
                return deepCloneByReflection(obj);
            }
        } catch (Exception e) {
            throw new RuntimeException("深克隆失败", e);
        }
    }
    
    // 序列化深克隆
    private static <T> T deepCloneBySerialization(T obj) throws Exception {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(obj);
        oos.close();
        
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        T cloned = (T) ois.readObject();
        ois.close();
        
        return cloned;
    }
    
    // 反射深克隆(简化版)
    private static <T> T deepCloneByReflection(T obj) throws Exception {
        Class<?> clazz = obj.getClass();
        T cloned = (T) clazz.newInstance();
        
        // 这里需要根据具体类的结构来实现
        // 实际应用中可能需要更复杂的反射逻辑
        
        return cloned;
    }
}

克隆的注意事项:

  • 浅克隆:只复制基本数据类型和引用地址,引用类型对象共享
  • 深克隆:复制所有数据,包括引用类型对象的完整副本
  • Cloneable接口:标记接口,不实现会抛出CloneNotSupportedException
  • 序列化方法:要求所有相关类都实现Serializable接口
  • JSON方法:简单易用,但性能相对较低
  • 性能考虑:深克隆比浅克隆消耗更多资源
  • 循环引用:深克隆时需要注意处理循环引用问题

使用场景:

  • 浅克隆:对象结构简单,引用类型不需要独立副本
  • 深克隆:对象结构复杂,需要完全独立的副本
  • 原型模式:创建对象的副本作为原型
  • 缓存机制:避免修改原始数据影响缓存

8. 网络编程API

8.1 Socket编程

服务器端:

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
import java.net.*;
import java.io.*;

public class Server {
    public static void main(String[] args) {
        try (ServerSocket serverSocket = new ServerSocket(8080)) {
            System.out.println("Server started on port 8080");
            
            while (true) {
                Socket clientSocket = serverSocket.accept();
                System.out.println("Client connected: " + clientSocket.getInetAddress());
                
                // 处理客户端连接
                new Thread(() -> handleClient(clientSocket)).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    private static void handleClient(Socket clientSocket) {
        try (BufferedReader in = new BufferedReader(
                new InputStreamReader(clientSocket.getInputStream()));
             PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true)) {
            
            String inputLine;
            while ((inputLine = in.readLine()) != null) {
                System.out.println("Received: " + inputLine);
                out.println("Echo: " + inputLine);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

客户端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.net.*;
import java.io.*;

public class Client {
    public static void main(String[] args) {
        try (Socket socket = new Socket("localhost", 8080);
             PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
             BufferedReader in = new BufferedReader(
                 new InputStreamReader(socket.getInputStream()));
             BufferedReader stdIn = new BufferedReader(
                 new InputStreamReader(System.in))) {
            
            String userInput;
            while ((userInput = stdIn.readLine()) != null) {
                out.println(userInput);
                String response = in.readLine();
                System.out.println("Server response: " + response);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
8.2 URL处理

URL操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.net.*;
import java.io.*;

try {
    URL url = new URL("https://www.example.com");
    
    // 获取URL信息
    System.out.println("Protocol: " + url.getProtocol());
    System.out.println("Host: " + url.getHost());
    System.out.println("Port: " + url.getPort());
    System.out.println("Path: " + url.getPath());
    
    // 读取URL内容
    try (BufferedReader reader = new BufferedReader(
            new InputStreamReader(url.openStream()))) {
        String line;
        while ((line = reader.readLine()) != null) {
            System.out.println(line);
        }
    }
} catch (IOException e) {
    e.printStackTrace();
}

学习总结

通过本阶段的学习,掌握了Java常用API的核心功能和使用方法:

  1. 字符串处理:熟练使用String、StringBuilder、StringBuffer等类进行字符串操作
  2. 集合框架:理解List、Set、Map的特点和适用场景,能够选择合适的集合类型
  3. IO流:掌握字节流、字符流、缓冲流的使用,能够进行文件读写操作
  4. 多线程:理解线程创建、控制、同步机制,能够编写多线程程序
  5. 反射注解:掌握反射机制和注解的使用,能够动态操作类和对象
  6. 日期时间:熟练使用新日期时间API,能够进行日期时间计算和格式化
  7. 工具类:掌握Arrays、Collections、Objects、Optional等工具类的使用
  8. 大数运算:掌握BigInteger和BigDecimal的使用,能够进行高精度数学计算和金融计算
  9. 正则表达式:掌握Pattern、Matcher类的使用,能够进行文本匹配、验证和替换
  10. 包装类:掌握基本类型与包装类的转换,理解装箱拆箱机制和性能优化
  11. Lambda表达式:掌握函数式编程,理解Lambda语法、函数式接口和Stream API
  12. 网络编程:理解Socket编程和URL处理的基本原理

这些API是Java开发的基础,为后续学习Spring框架、数据库操作、Web开发等高级主题奠定了坚实基础。

今日学习心得

今天重点学习了BigInteger和BigDecimal这两个重要的数值类型:

BigInteger学习要点:

  • 可以表示任意大的整数,解决了基本整数类型的范围限制
  • 支持所有基本数学运算:加减乘除、幂运算、位运算等
  • 提供了素数测试、最大公约数、最小公倍数等高级功能
  • 适用于密码学、大数统计、科学计算等场景

BigDecimal学习要点:

  • 解决了浮点数精度问题,特别适用于金融计算
  • 支持精确的十进制运算,避免浮点数舍入误差
  • 提供了多种舍入模式,满足不同业务需求
  • 可以控制精度和舍入方式,确保计算结果的准确性

实际应用场景:

  • 金融系统:货币计算、利率计算、百分比计算
  • 科学计算:高精度数学运算、统计分析
  • 密码学:大数运算、素数生成
  • 避免浮点数精度问题:确保计算结果的准确性

注意事项:

  • 性能考虑:BigInteger和BigDecimal运算比基本类型慢,只在需要时使用
  • 构造方式:优先使用字符串构造BigDecimal,避免double精度问题
  • 比较操作:使用compareTo()而不是equals()进行比较
  • 舍入模式:根据业务需求选择合适的舍入模式

通过今天的学习,对Java的数值处理能力有了更深入的理解,特别是在处理大数和精确计算方面的优势。这些知识为后续开发金融应用、科学计算程序等提供了重要基础。

正则表达式学习要点:

  • 掌握了Pattern和Matcher类的核心用法,能够进行复杂的文本匹配和验证
  • 熟练使用String类的正则方法(matches、split、replaceAll、replaceFirst)
  • 掌握了常用正则表达式模式,包括邮箱、手机号、身份证、URL等验证
  • 理解了正则表达式的语法要点,包括字符类、量词、边界、分组等
  • 学会了性能优化技巧,如预编译正则表达式、避免回溯等
  • 能够编写实用的正则表达式工具类,提高代码复用性

正则表达式应用场景:

  • 数据验证:表单验证、数据格式检查
  • 文本处理:提取关键信息、格式化文本
  • 日志分析:解析日志文件、提取错误信息
  • 数据清洗:标准化数据格式、去除无用信息

正则表达式注意事项:

  • 性能考虑:预编译正则表达式,避免在循环中重复编译
  • 语法陷阱:注意转义字符、边界匹配、贪婪与非贪婪匹配
  • 可读性:复杂正则表达式要添加注释,提高代码可维护性
  • 测试验证:编写充分的测试用例,确保正则表达式的正确性

通过正则表达式的学习,对文本处理和模式匹配有了更深入的理解,这将为后续开发数据处理、日志分析、表单验证等功能提供重要支持。

包装类学习要点:

  • 掌握了基本数据类型与包装类的对应关系,理解装箱拆箱机制
  • 熟练使用包装类的常用方法,包括类型转换、字符串解析、比较操作等
  • 理解了包装类的缓存机制,特别是Integer的-128到127缓存范围
  • 掌握了Character类的特殊方法,能够进行字符类型判断和转换
  • 学会了包装类的性能优化技巧,避免不必要的装箱拆箱操作
  • 能够编写实用的包装类工具方法,提高代码的安全性和可读性

包装类应用场景:

  • 集合框架:在List、Set、Map中存储数值类型
  • 泛型编程:在泛型中使用包装类类型参数
  • 数据库操作:处理可能为null的数值字段
  • 反射机制:在反射中使用包装类类型
  • 序列化:包装类支持序列化操作

包装类注意事项:

  • 性能考虑:基本类型比包装类性能更好,避免在循环中频繁装箱拆箱
  • null值处理:包装类可以为null,拆箱前要检查null值
  • 比较操作:使用equals()比较内容,使用compareTo()进行排序
  • 缓存机制:利用valueOf()方法使用缓存,提高性能
  • 不可变性:所有包装类都是不可变的,修改会创建新对象

通过包装类的学习,对Java的类型系统有了更深入的理解,特别是在处理基本类型与对象类型转换、集合框架使用、数据库操作等方面的重要作用。这些知识为后续开发企业级应用、数据库操作、框架使用等提供了重要基础。

Lambda表达式学习要点:

  • 掌握了Lambda表达式的基本语法,包括参数列表、箭头操作符和表达式体
  • 理解了函数式接口的概念,能够自定义和使用函数式接口
  • 熟练使用Java内置函数式接口:Predicate、Function、Consumer、Supplier、BiFunction等
  • 掌握了Lambda表达式在集合中的应用,包括forEach、removeIf、replaceAll、sort等
  • 学会了Stream API的使用,能够进行过滤、映射、归约、分组等操作
  • 理解了方法引用、闭包、变量捕获等高级概念
  • 学会了Lambda表达式的性能优化技巧,避免常见陷阱

Lambda表达式应用场景:

  • 集合操作:简化遍历、过滤、映射、排序等操作
  • 事件处理:GUI事件、异步回调等
  • 函数式编程:函数组合、管道处理、柯里化等
  • Stream API:数据流处理、并行计算
  • 回调函数:异步编程、事件驱动编程

Lambda表达式注意事项:

  • 语法规则:参数类型推断、括号省略、return省略等
  • 变量捕获:只能捕获final或effectively final的变量
  • 性能考虑:避免在循环中重复创建Lambda,使用并行流
  • 常见陷阱:变量捕获限制、异常处理、递归实现
  • 最佳实践:优先使用方法引用,合理使用函数式接口

通过Lambda表达式的学习,对Java的函数式编程能力有了显著提升,特别是在集合处理、异步编程、事件处理等方面的应用。这些知识为后续学习现代Java框架、响应式编程、微服务开发等提供了重要基础。

Hutool工具库学习要点:

  • 掌握了Hutool的核心工具类:StrUtil、DateUtil、CollUtil、MapUtil、HttpUtil、JSONUtil等
  • 理解了Hutool的设计理念:简化Java开发,提高开发效率
  • 熟练使用字符串处理工具,包括判空、格式化、截取、替换、分割、连接等操作
  • 掌握了日期时间处理工具,包括解析、格式化、计算、比较、偏移等操作
  • 学会了集合操作工具,包括创建、判空、并集交集差集、分组、排序、分页等
  • 理解了HTTP请求工具,包括GET、POST、文件上传、异步请求、请求拦截等
  • 掌握了JSON处理工具,包括对象转换、JSONObject、JSONArray、复杂JSON操作等
  • 学会了实用工具类的组合使用,提高代码复用性和开发效率

Hutool工具库应用场景:

  • 快速开发:原型开发、工具脚本、测试代码
  • 数据处理:字符串处理、日期处理、集合操作
  • 网络编程:HTTP客户端、API调用、文件下载
  • 配置管理:JSON配置、配置文件读取、数据验证
  • 日志分析:日志解析、统计分析、错误监控
  • 缓存管理:简单缓存、数据缓存、性能优化

Hutool工具库注意事项:

  • 性能考虑:合理使用缓存机制,避免频繁创建工具类实例
  • 异常处理:处理网络请求异常、JSON解析异常、加密解密异常
  • 安全性:使用安全的加密算法,保护敏感信息,验证输入数据
  • 版本兼容:注意版本兼容性,遵循编码规范
  • 最佳实践:合理使用工具类,避免过度依赖,保持代码简洁

通过Hutool工具库的学习,对Java开发效率有了显著提升,特别是在快速开发、数据处理、网络编程等方面的应用。这些知识为后续开发企业级应用、微服务、工具脚本等提供了重要支持。


后续将继续深入学习更多高级API和框架,不断提升Java编程技能。