一、常见算法(排序与查找)

(一) 冒泡排序

  • 核心逻辑:每轮相邻元素比较,将当前未排序区间的最大值“冒泡”到末尾,重复直至全排序。
  • 关键规则:共数组长度-1轮,第 i 轮比较数组长度 - i - 1次,arr[ j ] > arr[ j+1] 时交换;

(二) 选择排序

  • 核心逻辑:每轮从当前位置开始,找到未排序区间的最小值,与当前位置元素交换,重复直至全排序。
  • 关键规则:共数组长度-1轮,第 i 轮初始将 minIndex 设为 i,从 j = i+1 开始遍历,更新最小值索引; minIndex != i 时交换 arr[ i] 与 arr[ minIndex ]

(三) 二分查找

  • 前提:数组必须有序;
  • 核心逻辑:折半缩小范围,每次排除一半数据;
  • 步骤:
    • 定义 left=0、right=数组长度-1,
    • 循环( left<=right )计算mid=(left+right)/2
    • 若 目标值 > arr[mid]:目标在右半区,left = mid + 1;
    • 若 目标值 < arr[mid]:目标在左半区,right = mid - 1;
    • 若 目标值 == arr[mid]:找到目标,返回 mid,未找到返回-1。

(四) 正则表达式(规则表达式)

  • 校验数据格式:验证手机号、邮箱、日期等格式是否合法;
  • 查找文本内容:从一段文本中提取满足规则的信息(如手机号、邮箱);
  • 替换与分割:按规则替换文本内容(如脱敏)、分割字符串(如按任意空白符分割)。

1. 字符类(匹配单个字符)

符号 含义 示例
[abc] 匹配 a、b、c 中的任意一个 [abc] 匹配 “a”、“b”
[^abc] 匹配除 a、b、c 外的任意字符 [^abc] 匹配 “d”、“1”
[a-z] 匹配小写字母(a-z) [a-z] 匹配 “x”、“y”
[a-zA-Z0-9] 匹配字母或数字 [a-zA-Z0-9] 匹配 “A”、“5”
[a-z&&[m-p]] 交集,匹配 a-z 且 m-p 的字符(m-p) [a-z&&[m-p]] 匹配 “n”

2. 预定义字符(匹配单个字符)

符号 含义 示例
. 匹配任意字符(不包括回车) a.b 匹配 “aab”、“acb”
\d 匹配数字(0-9),等价于 [0-9] \d{11} 匹配11位数字
\D 匹配非数字,等价于 [^0-9] \D 匹配 “a”、“!”
\s 匹配空白符(空格、制表符等) a\sb 匹配 “a b”
\S 匹配非空白符 \S 匹配 “x”、“1”
\w 匹配单词字符(字母、数字、下划线) \w 匹配 “A”、“5”、“_”
\W 匹配非单词字符 \W 匹配 “!”、“@”

3. 数量词(控制字符出现次数)

符号 含义 示例
X? X 出现 0 次或 1 次 ab? 匹配 “a”、“ab”
X* X 出现 0 次或多次 ab* 匹配 “a”、“ab”、“abb”
X+ X 出现 1 次或多次 ab+ 匹配 “ab”、“abb”
X{n} X 恰好出现 n 次 \d{11} 匹配11位手机号
X{n,} X 至少出现 n 次 \d{6,} 匹配6位及以上数字
X{n,m} X 出现 n 到 m 次(含边界) \d{6,18} 匹配6-18位密码

4. 分组与逻辑

含义 示例
分组,将 X 视为一个整体 (ab)+ 匹配 “ab”、“abab”
X|Y 逻辑或,匹配 X 或 Y

5. 常用方法与案例

(一) 校验格式
  • 语法:String str.matches(String regex) → 返回 boolean(匹配返回 true)。
String phone = "13811112222";
String regex = "1[3-9]\\d{9}"; // 注意转义:\d 需写为 \\d
System.out.println(phone.matches(regex)); // true
(二) 查找内容
  • 步骤:

    1. 用 Pattern.compile(regex) 封装正则规则;
    2. 用 pattern.matcher(data) 获取匹配器;
    3. 用 matcher.find() 循环查找,matcher.group() 提取结果(group(1) 提取第一组)。
  • 案例:提取文本中的邮箱:

String data = "邮箱:bozai@itcast.cn,邮箱2:dlei0009@163.com";
String regex = "([a-zA-Z0-9_]+)@([a-zA-Z0-9.]+)"; // 分组:用户名 + 域名
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(data);
while (matcher.find()) {
    System.out.println("用户名:" + matcher.group(1)); // 第一组(用户名)
    System.out.println("完整邮箱:" + matcher.group()); // 完整匹配
}
// 输出:
// 完整邮箱:bozai@itcast.cn,用户名:bozai
// 完整邮箱:dlei0009@163.com,用户名:dlei0009
(三) 替换与分割
方法 作用 示例
replaceAll(regex, newStr) 数字脱敏,按正则替换所有匹配内容 str.replaceAll(“\d”, "") → 数字替换为
split(regex) 按正则分割字符串,返回数组 str.split(“\s+”) → 按任意空白符分割

二、IO流

(一) 字符编码(IO流基础)

  • 核心规则:编码/解码需同一字符集,否则乱码。
  • Java实现:
    • 编码(String → byte[ ]):String.getBytes(字符集)(如str.getBytes(“UTF8”));
    • 解码(byte[ ] → String):new String(字节数组, 字符集)(如new String(bytes, “UTF-8”))
字符集 特点 适用场景
ASCII 1字节存储,仅含英文、数字、符号 英文文档
GBK 中文2字节,兼容ASCII 中文文档(Windows默认)
UTF-8 中文3字节,英文1字节,兼容ASCII 推荐(跨平台、互联网通用)

(二) IO流体系(核心)

IO流用于读写数据(文件、网络等),按“方向”和“数据单位”分类,核心是四大抽象类及实现类。
在这里插入图片描述

分类维度 类型 核心特点 适用场景
按方向 输入流(Input) 从外部(磁盘/网络)读入内存 读取文件内容
输出流(Output) 从内存写出到外部(磁盘/网络) 写入文件内容
按数据单位 字节流(byte) 以字节为单位,可处理所有类型文件(音视频、图片等) 文件复制、非文本文件读写
字符流(char) 以字符为单位,仅处理纯文本文件(.txt、.java等) 文本文件读写(避免乱码)
流类型 抽象类 常用实现类 核心作用
字节输入流 InputStream FileInputStream(文件字节输入流) 从文件读字节到内存
BufferedInputStream(字节缓冲输入流) 包装低级流,提升读性能(8KB缓冲区)
字节输出流 OutputStream FileOutputStream(文件字节输出流) 从内存写字节到文件
BufferedOutputStream(字节缓冲输出流) 包装低级流,提升写性能(8KB缓冲区)
字符输入流 Reader FileReader(文件字符输入流) 从文件读字符到内存(纯文本)
BufferedReader(字符缓冲输入流) 包装低级流,提升性能,支持按行读
InputStreamReader(字符输入转换流) 指定编码读文本,解决乱码
字符输出流 Writer FileWriter(文件字符输出流) 从内存写字符到文件(纯文本)
BufferedWriter(字符缓冲输出流) 包装低级流,提升性能,支持换行
OutputStreamWriter(字符输出转换流) 指定编码写文本,控制输出编码

1. 字节流(FileInputStream/FileOutputStream)

核心作用:处理所有类型文件(如图片、视频),以字节为单位读写。

流类型 构造器 核心方法
FileInputStream FileInputStream(File/路径) read() (读1字节)、read(byte[]) (读字节数组)、close() (关闭流)
FileOutputStream FileOutputStream(File/路径, boolean append) write(int) (写1字节)、write(byte[]) (写字节数组)、close()

案例:文件复制(字节流核心场景)

try (// try-with-resource:自动关闭流(JDK7+)
     InputStream is = new FileInputStream("D:/src.png");
     OutputStream os = new FileOutputStream("C:/dest.png")
) {
    byte[] buffer = new byte[1024]; // 1KB缓冲数组(提升性能)
    int len; // 记录每次读取的字节数
    while ((len = is.read(buffer)) != -1) {
        os.write(buffer, 0, len); // 写读取到的字节(避免写空)
    }
} catch (IOException e) {
    e.printStackTrace();
}

2. 字符流(FileReader/FileWriter)

核心作用:处理纯文本文件,避免字节流读中文乱码(需编码一致)。

流类型 构造器 核心方法 注意事项
FileReader FileReader(File/路径) read()(读1字符)、read(char[]) (读字符数组) 依赖默认编码,编码不一致会乱码
FileWriter FileWriter(File/路径, boolean append) write(int/char[]/String) (写字符)、flush() (刷新缓冲) 需调用flush()或close(),否则数据可能残留缓冲

3. 缓冲流(BufferedXXX)

核心作用:包装低级流(如FileInputStream),自带8KB缓冲区,大幅提升读写性能。

缓冲流类型 构造器 新增核心方法
BufferedInputStream BufferedInputStream(InputStream) 无新增,性能提升
BufferedOutputStream BufferedOutputStream(OutputStream) 无新增,性能提升
BufferedReader BufferedReader(Reader) readLine() (按行读文本,返回 null 表示结束)
BufferedWriter BufferedWriter(Writer) newLine() (跨平台换行,替代 \r\n )

4. 转换流(InputStreamReader/OutputStreamWriter)

核心作用:解决编码乱码,指定编码读写。

转换流类型 构造器 核心作用
InputStreamReader InputStreamReader(InputStream, String charset) 按指定编码将字节流转为字符流(读文本)
OutputStreamWriter OutputStreamWriter(OutputStream, String charset) 按指定编码将字符流转为字节流(写文本)

案例:指定UTF-8读文本

try (
    // 字节流 → 转换流(指定UTF-8)→ 缓冲流(提升性能)
    Reader isr = new InputStreamReader(new FileInputStream("D:/test.txt"), "UTF-8");
    BufferedReader br = new BufferedReader(isr)
) {
    String line;
    while ((line = br.readLine()) != null) {
        System.out.println(line);
    }
} catch (IOException e) {
    e.printStackTrace();
}

5. 打印流(PrintStream/PrintWriter)

核心作用:方便打印任意类型数据(如int、String),性能高效,支持自动刷新。

打印流类型 特点 核心方法
PrintStream 继承字节输出流,支持写字节 println( 任意类型 )、printf( 格式 , 参数 )
PrintWriter 继承字符输出流,支持写字符,可指定编码 println( 任意类型 )、flush()

应用:输出重定向(将System.out输出到文件)

try (PrintStream ps = new PrintStream("D:/log.txt", "UTF-8")) {
    System.setOut(ps); // 重定向System.out到文件
    System.out.println("日志内容:程序启动成功"); // 输出到文件
} catch (IOException e) {
    e.printStackTrace();
}

6. 数据流(DataInputStream/DataOutputStream)

核心作用:读写数据时保留数据类型(如int、double),需按写入顺序读取。

数据流类型 构造器 核心方法
DataInputStream DataInputStream(InputStream) readInt()、readDouble()、readUTF()
DataOutputStream DataOutputStream(OutputStream) writeInt()、writeDouble()、writeUTF()

7. 序列化流(ObjectInputStream/ObjectOutputStream)

核心作用:实现“对象序列化”(将Java对象写入文件)和“反序列化”(从文件读入对象)。

序列化流类型 核心方法 注意事项
ObjectOutputStream writeObject(Object obj) 对象必须实现 Serializable 接口(标记接口,无方法)
ObjectInputStream readObject() 读取顺序需与写入顺序一致,反序列化类需存在

批量序列化:用ArrayList存储多个对象(ArrayList已实现Serializable):

// 序列化:写入多个学生对象
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:/students.txt"))) {
    List<Student> list = new ArrayList<>();
    list.add(new Student("张三", 20));
    list.add(new Student("李四", 22));
    oos.writeObject(list); // 序列化ArrayList
} catch (IOException e) {
    e.printStackTrace();
}

// 反序列化:读取多个学生对象
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:/students.txt"))) {
    List<Student> list = (List<Student>) ois.readObject(); // 反序列化
    System.out.println(list);
} catch (IOException | ClassNotFoundException e) {
    e.printStackTrace();
}

(三) IO框架(Commons-IO)

封装原生IO,简化操作,提升效率(Apache开源)。

工具类 核心方法 说明
FileUtils copyFile(File src, File dest) 复制文件
copyDirectory(File srcDir, File destDir) 复制文件夹(含子文件夹)
deleteDirectory(File dir) 删除非空文件夹
readFileToString(File file, String charset) 按指定编码读文件为字符串
IOUtils copy(InputStream in, OutputStream out) 复制输入流到输出流(支持字节/字符流)
write(String data, OutputStream out, String charset) 按指定编码写字符串到输出流

三、集合

集合是可变容量的容器,解决数组容量固定问题,核心差异是元素存储形式(单值/键值对)。

集合类型 元素形式 顶层接口 核心实现类
单列集合 单个值(如"张三") Collection List(ArrayList、LinkedList)、Set(HashSet、LinkedHashSet、TreeSet)
双列集合 键值对(如"张三"=20) Map HashMap、LinkedHashMap、TreeMap

(一) 单列集合(Collection)

方法名 说明
add(E e) 添加元素,成功返回 true
clear() 清空集合所有元素
remove(E e) 删除指定元素,成功返回 true
contains(Object obj) 判断是否包含指定元素
isEmpty() 判断集合是否为空
size() 返回元素个数
toArray() 转为Object数组
遍历方式 适用场景 核心代码
迭代器 (Iterator) 所有单列集合(最底层方式) Iterator it = c.iterator(); while(it.hasNext()) { E e = it.next(); }
增强for循环 简化迭代器,无需手动控制索引 for (E e : 集合 ) { … }
Lambda表达式 JDK8+,代码最简洁 集合 .forEach(e -> System.out.println(e));

1. List集合(有序、可重复、有索引)

实现类 底层原理 核心优势 适用场景
ArrayList 动态数组(初始10,扩容1.5倍) 查询快(索引定位) 频繁查询、少量增删
LinkedList 双链表 首尾增删快,支持首尾操作特有方法 频繁操作首尾(如栈/队列)

List特有方法(索引相关)

方法名 说明
add(int index, E e) 在指定索引插入元素
remove(int index) 删除指定索引元素,返回被删元素
set(int index, E e) 修改指定索引元素,返回旧值
get(int index) 返回指定索引元素

LinkedList特有方法(首尾操作)

方法名 说明
addFirst(E e) / addLast(E e) 首尾添加元素
getFirst() / getLast() 获取首尾元素
removeFirst() / removeLast() 删除首尾元素,返回被删元素

2. Set集合(无序/有序、不重复、无索引)

实现类 底层原理 核心特点 去重/排序机制
HashSet 哈希表 (数组+链表+红黑树) 无序 依赖 hashCode() + equals()
LinkedHashSet 哈希表+双链表 有序(记插入顺序) 同HashSet,双链表保顺序
TreeSet 红黑树 可排序(默认升序) 实现 Comparable 或传 Comparator

注意:

  1. HashSet去重:自定义对象需重写hashCode()equals() ,确保“内容相同则哈希值相同、equals返回true”;
  2. TreeSet排序
    • 方式1:自定义类实现Comparable 接口,重写compareTo() (如return this.age - o.age );
    • 方式2:创建TreeSet 时传入Comparator (如new TreeSet<>((a,b)
      -> b.age - a.age) ,降序);
  3. 哈希表优化:JDK8后,链表长度>8且数组长度≥64时,链表自动转红黑树,提升查询性能。

(二) 双列集合(Map)

元素是键值对(key=value),key不重复、value可重复,特点由key决定;

实现类 底层原理 核心特点 适用场景
HashMap 哈希表(同 HashSet) 无序、key不重复、无索引 通用场景,增删改查性能好
LinkedHashMap 哈希表+双链表 有序(记住key添加顺序)、key不重复 需要保留插入顺序的场景
TreeMap 红黑树(同 TreeSet) key可排序、不重复、无索引 需要对key排序的场景 (如按年龄排序)
方法名 说明
put(K key, V value) 添加键值对(key重复则覆盖value)
get(Object key) 根据key获取value(无则返回null)
remove(Object key) 根据key删除键值对,返回value
containsKey(Object key) 判断是否包含指定key
containsValue(Object v) 判断是否包含指定value
keySet() 获取所有key的Set集合
values() 获取所有value的Collection集合
entrySet() 获取所有键值对(Map.Entry)的Set集合
遍历方式 核心逻辑 代码示例
键找值 先遍历key,再通过key找value Set keys = map.keySet(); for (K k : keys) { V v = map.get(k); }
键值对 直接遍历键值对对象 Set<Map.Entry<K,V>> entries = map.entrySet(); for (Map.Entry<K,V> e : entries) { K k = e.getKey(); V v = e.getValue(); }
Lambda表达式 JDK8+,简化遍历 map.forEach( (k, v) -> System.out.println(k + “=” + v) );

(三) Stream流(JDK8+)

Stream流是简化集合/数组操作的API,结合Lambda表达式,代码更简洁,支持“链式编程”。

关键步骤:

  1. 获取Stream流:从集合/数组创建流;
  2. 中间操作:过滤、排序、转换等(返回新流,支持链式);
  3. 终结操作:遍历、统计、收集结果(无返回值或返回非流结果)。
数据源 获取方式 示例
集合 Collection.stream() List list = new ArrayList<>(); Stream s = list.stream();
数组 Arrays.stream( 数组 ) int[] arr = {1,2,3}; Stream<int[]> s = Arrays.stream(arr);
零散数据 Stream.of( 数据1, 数据2… ) Stream s = Stream.of(“a”, “b”, “c”);

中间方法(返回新Stream):

方法名 说明 示例
filter(Predicate p) 过滤元素(满足条件保留) s.filter(e -> e.startsWith(“张”))
sorted() / sorted(Comparator c) 升序排序/自定义排序 s.sorted((a,b) -> b.length() - a.length()) (按长度降序)
limit(long n) 保留前n个元素 s.limit(3) (保留前3个)
skip(long n) 跳过前n个元素 s.skip(2) (跳过前2个)
distinct() 去重(依赖 equals() ) s.distinct()
map(Function f) 元素转换(如 String→Integer) s.map(Integer::parseInt) (字符串转整数)
concat(Stream a, Stream b) 合并两个流 Stream.concat(s1, s2)

终结方法(无返回Stream):

方法名 说明 示例
forEach(Consumer c) 遍历元素 s.forEach(System.out::println)
count() 统计元素个数(返回 long) long size = s.count();
max(Comparator c) / min(Comparator c) 获取最大/最小值(返回 Optional) Optional max = s.max((a,b) -> a.compareTo(b));
collect(Collector c) 收集到集合/数组 List list = s.collect(Collectors.toList());

通过Collectors工具类将流结果转为集合/数组:

收集方式 说明
Collectors.toList() 收集到List集合
Collectors.toSet() 收集到Set集合(去重)
Collectors.toMap(kf, vf) 收集到Map集合(kf为key映射,vf为value映射)
toArray() 收集到Object数组

(四) 工具类与补充知识

1. Collections工具类(操作集合的静态工具)

方法名 说明
addAll(Collection c, T… elements) 批量添加元素
shuffle(List<?> list) 打乱List元素顺序
sort(List list) / sort(List list, Comparator c) List升序/自定义排序

2. 可变参数(灵活接收数据)

  • 格式:数据类型... 参数名(如int… nums);
  • 特点:
    • 方法内部视为数组;
    • 一个方法仅能有一个可变参数,且需在形参列表末尾;

示例:

public static int sum(int... nums) { 
    int s = 0; 
    for (int n : nums) 
        s += n; 
    return s; 
}

3. 并发修改异常(遍历中修改集合)

  • 场景:迭代器/增强for遍历集合时,用集合remove() 删除元素;
  • 解决
    • 迭代器遍历:用iterator.remove()删除;
    • for循环遍历:倒序遍历或删除后 i - - 。

(五) 集合选型建议

需求场景 推荐集合
频繁查询、有序可重复 ArrayList
频繁增删首尾元素 LinkedList
无序不重复、增删改查快 HashSet
有序不重复、需保留插入顺序 LinkedHashSet
需排序不重复 TreeSet
键值对存储、无序 HashMap
键值对存储、需保留插入顺序 LinkedHashMap
键值对存储、需对key排序 TreeMap
简化集合/数组操作(过滤、排序等) Stream流

四、日志

记录程序运行信息(如错误、操作),可存控制台/文件/数据库,无需改代码即可控制启停,优于System.out(仅控制台、需改代码)。

(一) Logback日志框架(重点)

基于SLF4J接口,需导3个模块:

  • slf4j-api.jar:SLF4J接口;
  • logback-core.jar:基础模块;
  • logback-classic.jar:SLF4J接口实现(核心功能)。
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!-- 1. 控制台输出 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <!-- 日志格式:时间 级别 类名 - 内容 -->
            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%level] %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <!-- 2. 文件输出(滚动日志,避免单个文件过大) -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>logs/app.log</file> <!-- 日志文件路径 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>logs/app-%d{yyyy-MM-dd}.log</fileNamePattern> <!-- 按日期分割 -->
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%level] %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <!-- 3. 全局日志级别(仅输出≥该级别的日志) -->
    <root level="INFO">
        <appender-ref ref="CONSOLE"/> <!-- 关联控制台输出 -->
        <appender-ref ref="FILE"/> <!-- 关联文件输出 -->
    </root>
</configuration>

代码中使用:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LogbackTest {
    // 1. 获取Logger对象(参数为当前类名,便于定位日志来源)
    private static final Logger LOGGER = LoggerFactory.getLogger(LogbackTest.class);

    public static void main(String[] args) {
        // 2. 输出不同级别日志
        LOGGER.trace("追踪信息(程序轨迹)");
        LOGGER.debug("调试信息(开发调试)");
        LOGGER.info("普通信息(如启动成功)");
        LOGGER.warn("警告信息(如参数异常)");
        LOGGER.error("错误信息(如异常堆栈)");
    }
}

(二) 日志级别(核心控制)

级别 说明 适用场景
TRACE 程序运行轨迹(最详细,极少用) 深度调试
DEBUG 调试信息 开发阶段验证逻辑
INFO 普通运行信息(默认核心级别) 系统启动、关键操作记录(如登录)
WARN 警告信息(非致命问题) 参数不合法、资源不足
ERROR 错误信息(致命问题) 异常、功能失败
ALL 输出所有级别日志 全量调试
OFF 关闭所有日志 生产环境临时关闭

级别作用:

  • 配置文件中设置root level=“级别” 后,仅输出 ≥该级别的日志 (如设置INFO ,则INFO / WARN / ERROR 会输出,TRACE / DEBUG 被过滤)。
  • 用途:开发阶段用DEBUG ,生产阶段用INFO / WARN,减少日志冗余。
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐