核心类库_常用类

java.lang包

java.lang 包是 Java 语言的基石,封装了最核心的类和功能,涵盖了对象模型、字符串处理、数值运算、异常处理、多线程等基础能力。

Object类

Object 类是 Java 中所有类的根类(超类),任何类都直接或间接继承自 Object 类。即使在类定义时没有显式声明父类,编译器也会默认让它继承 Object 类。Object 类定义了所有 Java 对象都具备的基本行为,其方法在 Java 编程中具有重要意义。

Object 类的核心方法

Object 类包含 11 个方法,其中以下几个是最常用且需要重点理解的:

equals(Object obj)
  • 作用:判断当前对象与参数对象是否 "相等"。
  • 默认实现:return (this == obj);,即比较两个对象的内存地址(是否为同一个对象)。
  • 重写场景:当需要判断两个对象的 "内容" 是否相等时(而非地址),需重写此方法。
  • 重写原则:
    • 自反性:x.equals(x) 必须返回 true
    • 对称性:若 x.equals(y) true,则 y.equals(x) 也必须为 true
    • 传递性:若 x.equals(y) y.equals(z) true,则 x.equals(z) 也为 true
    • 一致性:多次调用结果应一致(对象未被修改时)。
    • 非空性:x.equals(null) 必须返回 false
java 复制代码
// 示例:重写 equals 比较对象内容
class Student {
    String id;
    String name;

    @Override
    public boolean equals(Object obj) {
        // 同一对象直接返回 true
        if (this == obj) return true;
        // 类型不同返回 false
        if (obj == null || getClass() != obj.getClass()) return false; 
        Student student = (Student) obj;
        // 比较关键属性是否相等
        return id.equals(student.id) && name.equals(student.name);
    }
}
hashCode()
  • 作用:返回对象的哈希码(一个整数),主要用于哈希表(如 HashMapHashSet)中快速定位对象。
  • 默认实现:返回对象的内存地址转换的整数(不同对象哈希码通常不同)。
  • 重写原则(与 equals 强关联):
    • x.equals(y)true,则x.hashCode()必须等于 y.hashCode()
    • x.equals(y)falsex.hashCode() y.hashCode() 可以相等(但可能影响哈希表性能)。
  • 常见实现:结合对象中参与 equals 比较的属性计算哈希码,例如:
java 复制代码
@Override
public int hashCode() {
    int result = id.hashCode();
    result = 31 * result + name.hashCode(); // 31 是质数,减少哈希冲突
    return result;
}
toString()
  • 作用:返回对象的字符串表示,便于打印和调试。
  • 默认实现:getClass().getName() + "@" + Integer.toHexString(hashCode()),例如 com.example.Student@1b6d3586
  • 重写建议:返回包含对象关键信息的字符串,提高可读性。
java 复制代码
@Override
public String toString() {
    return "Student{id='" + id + "', name='" + name + "'}";
}
getClass()
  • 作用:返回对象的运行时类(Class 对象)。
  • 特点:
    • 方法声明为 final,不能被重写。
    • 常用于反射(动态获取类信息、调用方法等)。
java 复制代码
Student s = new Student();
Class<? extends Student> clazz = s.getClass();
System.out.println(clazz.getName()); // 输出类的全限定名,如 com.example.Student
clone()
  • 作用:创建并返回当前对象的副本(克隆)。
  • 注意事项:
    • 方法声明为 protected,若要在类外调用,需重写并改为 public
    • 类需实现 Cloneable 接口(标记接口,无实际方法),否则调用时会抛出 CloneNotSupportedException
    • 默认是浅克隆:基本类型字段复制值,引用类型字段复制地址(与原对象共享引用对象)。
java 复制代码
class Person implements Cloneable {
    String name;
    int age;

    @Override
    public Person clone() throws CloneNotSupportedException {
        return (Person) super.clone(); // 调用父类的 clone 实现
    }
}

// 使用
Person p1 = new Person();
p1.name = "Alice";
p1.age = 20;
try {
    Person p2 = p1.clone(); // 克隆对象
    System.out.println(p2.name); // Alice(复制成功)
} catch (CloneNotSupportedException e) {
    e.printStackTrace();
}
线程相关方法
  • wait():使当前线程进入等待状态,直到被 notify() notifyAll() 唤醒。
  • notify():唤醒在此对象监视器上等待的单个线程。
  • notifyAll():唤醒在此对象监视器上等待的所有线程。
  • 特点 :均为 final 方法,需在同步代码块(synchronized)中使用,用于线程间通信。
finalize()
  • 作用:垃圾回收器回收对象前调用,用于释放资源(如关闭文件、网络连接)。
  • 注意:
    • 不推荐使用,Java 9 后已标记为过时(@Deprecated)。
    • 执行时机不确定,无法保证一定会被调用。
    • 替代方案:使用 try-with-resources 自动释放资源。

Object 类的重要性

  1. 统一接口 :为所有 Java 对象提供了统一的方法规范,例如任何对象都可以调用 toString() 打印信息。
  2. 支持核心机制equals()hashCode() 是哈希容器(HashMap 等)正常工作的基础;wait()/notify() 是线程同步的核心工具。
  3. 反射基础getClass() 方法为反射提供了入口,使动态操作类和对象成为可能。

字符串相关类

Java 中字符串相关的核心类主要有 StringStringBuilderStringBuffer,它们用于处理字符串数据,但在特性和使用场景上有显著区别。下面详细介绍这三个类的特点、常用方法及最佳实践。

String(不可变字符串)

String 是 Java 中最常用的字符串类,其核心特性是不可变性:一旦创建,字符串的内容无法被修改,任何修改操作都会返回一个新的 String 对象。

不可变性原理

String 类内部使用 private final char[] 数组存储字符(JDK 9+ 改为 byte[] 节省空间),final 修饰确保数组引用不可变,且没有提供修改数组元素的方法,因此字符串内容无法改变。

java 复制代码
String s = "hello";
s += " world"; // 实际创建了新的String对象,原"hello"未被修改
常用构造方法
java 复制代码
// 1. 直接赋值(推荐,会使用字符串常量池)
String s1 = "hello";

// 2. 构造方法(new关键字会创建新对象,不推荐)
String s2 = new String("hello"); 
String s3 = new String(new char[]{'h', 'i'}); // 从字符数组创建
核心方法
方法 功能 示例
length() 返回字符串长度 "abc".length() → 3
charAt(int index) 获取指定索引的字符 "abc".charAt(1) → 'b'
substring(int begin, int end) 截取子串(左闭右开) "hello".substring(1,3) → "el"
equals(Object obj) 比较内容是否相等 "a".equals("a") → true
equalsIgnoreCase(String s) 忽略大小写比较 "A".equalsIgnoreCase("a") → true
startsWith(String prefix) 判断是否以指定前缀开头 "hello".startsWith("he") → true
endsWith(String suffix) 判断是否以指定后缀结尾 "hello".endsWith("lo") → true
indexOf(String str) 查找子串首次出现的索引 "hello".indexOf("l") → 2
lastIndexOf(String str) 查找子串最后出现的索引 "hello".lastIndexOf("l") → 3
replace(char old, char new) 替换字符 "hello".replace('l','x') → "hexxo"
replaceAll(String regex, String replacement) 正则替换 "a1b2c".replaceAll("\\d", "") → "abc"
split(String regex) 按正则拆分字符串 "a,b,c".split(",") → ["a","b","c"]
trim() 去除首尾空白字符 " hi ".trim() → "hi"
toUpperCase()/toLowerCase() 转大小写 "Hello".toUpperCase() → "HELLO"
valueOf(xxx) 静态方法,将其他类型转为字符串 String.valueOf(123) → "123"
字符串常量池

为节省内存,Java 维护了一个字符串常量池(方法区中):

  • 直接赋值的字符串(如 String s = "abc")会优先从常量池查找,若存在则复用,否则创建并放入常量池。
  • new 关键字创建的字符串(如 new String("abc"))会在堆中创建新对象,且不会自动放入常量池(需调用 intern() 方法手动入池)。
java 复制代码
String s1 = "abc";
String s2 = "abc";
String s3 = new String("abc");

System.out.println(s1 == s2); // true(常量池复用,地址相同)
System.out.println(s1 == s3); // false(s3在堆中,地址不同)
System.out.println(s1 == s3.intern()); // true(s3.intern()返回常量池中的对象)

StringBuilder 类(可变字符串,非线程安全)

StringBuilder 是 JDK 5 引入的可变字符串类,其内容可以被修改,所有操作都在原对象上进行,不会创建新对象,效率高于 String。但它非线程安全(方法没有 synchronized 修饰),适合单线程场景。

常用构造方法
java 复制代码
StringBuilder sb1 = new StringBuilder(); // 初始容量16
StringBuilder sb2 = new StringBuilder(32); // 指定初始容量(减少扩容次数)
StringBuilder sb3 = new StringBuilder("hello"); // 从字符串初始化
核心方法(支持链式调用)
方法 功能 示例
append(xxx) 追加内容(任意类型) sb.append("a").append(123) → "a123"
insert(int index, xxx) 在指定位置插入内容 sb.insert(2, "xyz")
delete(int start, int end) 删除指定范围字符 sb.delete(1,3)
deleteCharAt(int index) 删除指定索引的字符 sb.deleteCharAt(2)
reverse() 反转字符串 new StringBuilder("abc").reverse() → "cba"
replace(int start, int end, String str) 替换指定范围内容 sb.replace(1,3,"xx")
setCharAt(int index, char c) 修改指定索引的字符 sb.setCharAt(1, 'x')
toString() 转换为 String 对象 sb.toString()
length() 返回长度 sb.length()

StringBuffer 类(可变字符串,线程安全)

StringBuffer 是 JDK 1.0 引入的可变字符串类,功能与 StringBuilder 几乎完全一致 ,但它线程安全(所有方法都被 synchronized 修饰),因此效率略低,适合多线程场景。

java 复制代码
StringBuffer sbf = new StringBuffer("java");
sbf.append(8).append(" is great");
System.out.println(sbf.toString()); // "java8 is great"

三者对比与选择

特性 **String** **StringBuilder** **StringBuffer**
可变性 不可变 可变 可变
线程安全 安全(不可变天然安全) 不安全 安全(方法加锁)
效率 低(频繁修改产生大量对象) 中(锁开销)
适用场景 字符串不常修改 单线程,频繁修改 多线程,频繁修改

最佳实践

  1. 字符串不修改时用 String:如常量定义、字符串拼接次数少的场景。
java 复制代码
String name = "Alice"; // 推荐
  1. 单线程频繁修改用StringBuilder:如循环拼接字符串。
java 复制代码
// 反例:效率低,每次循环创建新对象
String s = "";
for (int i = 0; i < 1000; i++) {
    s += i; 
}

// 正例:效率高,在原对象上操作
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
    sb.append(i);
}
String result = sb.toString();
  1. 多线程频繁修改用StringBuffer:如多线程日志拼接。
java 复制代码
// 多线程环境下保证线程安全
StringBuffer logBuffer = new StringBuffer();
// 多个线程同时调用 logBuffer.append(...)
  1. 初始化容量优化 :创建 StringBuilder/StringBuffer 时,若能预估字符串长度,指定初始容量(如 new StringBuilder(1024)),可减少内部数组扩容次数,提高效率。
  2. 避免StringStringBuilder 混用:如下代码会频繁转换类型,降低效率:
java 复制代码
// 反例
StringBuilder sb = new StringBuilder();
sb.append("a" + 1 + "b"); // 会先创建临时String对象

基本类型包装类

在 Java 中,基本数据类型(如 intcharboolean 等)不是对象,但在很多场景下需要将它们作为对象处理(如集合框架中只能存储对象)。为此,Java 提供了基本类型包装类,用于将基本类型包装为对象。这些类都位于 java.lang 包中,无需显式导入即可使用。

包装类的对应关系

Java 为 8 种基本类型提供了对应的包装类,具体对应关系如下:

基本类型 包装类(java.lang 包) 父类
byte Byte Number
short Short Number
int Integer Number
long Long Number
float Float Number
double Double Number
char Character Object
boolean Boolean Object
  • 前 6 种数值型包装类继承自 Number 类,提供了数值转换方法(如 intValue()doubleValue())。
  • CharacterBoolean 直接继承 Object 类。

包装类的核心特性

  1. 装箱与拆箱
  • 箱:将基本类型转换为对应的包装类对象。
  • 箱:将包装类对象转换为对应的基本类型。

JDK 5 引入了**自动装箱(Auto-Boxing)自动拆箱(Auto-Unboxing)**机制,编译器会自动完成转换,无需手动调用方法。

java 复制代码
// 自动装箱:int → Integer
int num = 100;
Integer i1 = num; // 等价于 Integer i1 = Integer.valueOf(num);

// 自动拆箱:Integer → int
Integer i2 = 200;
int num2 = i2; // 等价于 int num2 = i2.intValue();

// 包装类与基本类型混合运算(自动拆箱后计算,再自动装箱)
Integer i3 = 300;
i3 += 100; // 等价于 i3 = Integer.valueOf(i3.intValue() + 100);
System.out.println(i3); // 400
  1. 常量池缓存机制

为节省内存,部分包装类对一定范围内的值提供了缓存机制,当创建该范围内的对象时,会复用缓存中的对象,而不是新建对象。

  • Integer:缓存范围为 -128 ~ 127(可通过 JVM 参数 XX:AutoBoxCacheMax 调整上限)。
  • ByteShortLong:缓存范围固定为 -128 ~ 127(全部值都在范围内,因此所有对象都会被缓存)。
  • Character:缓存范围为 0 ~ 127(ASCII 字符)。
  • Boolean:缓存 TRUEFALSE 两个静态对象。
java 复制代码
// Integer 缓存示例
Integer a = 100;
Integer b = 100;
System.out.println(a == b); // true(复用缓存对象)

Integer c = 200;
Integer d = 200;
System.out.println(c == d); // false(超出缓存范围,新建对象)

// Character 缓存示例
Character ch1 = 'A'; // ASCII值65,在0~127范围内
Character ch2 = 'A';
System.out.println(ch1 == ch2); // true(复用缓存)

Character ch3 = 128; // 超出缓存范围
Character ch4 = 128;
System.out.println(ch3 == ch4); // false(新建对象)

注意: == 比较的是对象地址,equals() 比较的是值。包装类比较值时应使用 equals(),避免因缓存机制导致误判。


常用包装类及核心方法

以最常用的 IntegerCharacterBoolean 为例,介绍其核心方法。

Integer 类(对应 int)

Integer 是使用最广泛的包装类,提供了整数类型转换、进制转换等功能。

java 复制代码
// 1. 构造方法(不推荐,建议用 valueOf())
Integer i1 = new Integer(100); // 已过时
Integer i2 = new Integer("100"); // 已过时

// 2. 静态工厂方法(推荐,会使用缓存)
Integer i3 = Integer.valueOf(100);
Integer i4 = Integer.valueOf("100"); // 字符串转Integer

// 3. 基本类型转换(拆箱)
int num = i3.intValue();

// 4. 字符串转基本类型(常用)
int num2 = Integer.parseInt("123"); // 字符串→int
int num3 = Integer.parseInt("1111", 2); // 二进制"1111"→15(第二个参数指定进制)

// 5. 基本类型转字符串
String str1 = Integer.toString(123); // "123"
String str2 = Integer.toBinaryString(15); // 二进制字符串"1111"
String str3 = Integer.toHexString(255); // 十六进制字符串"ff"

// 6. 常量
System.out.println(Integer.MAX_VALUE); // 2^31-1(2147483647)
System.out.println(Integer.MIN_VALUE); // -2^31(-2147483648)
System.out.println(Integer.SIZE); // 32(位数)
Character 类(对应 char)

Character 提供了字符判断、转换等工具方法。

java 复制代码
// 1. 静态工厂方法
Character ch = Character.valueOf('a');

// 2. 拆箱
char c = ch.charValue();

// 3. 字符判断方法(静态)
System.out.println(Character.isLetter('A')); // true(是否为字母)
System.out.println(Character.isDigit('5')); // true(是否为数字)
System.out.println(Character.isWhitespace(' ')); // true(是否为空白字符)
System.out.println(Character.isUpperCase('B')); // true(是否为大写字母)

// 4. 字符转换
System.out.println(Character.toUpperCase('a')); // 'A'(转大写)
System.out.println(Character.toLowerCase('C')); // 'c'(转小写)
Boolean 类(对应 boolean)

Boolean 用于包装布尔值,提供了字符串转布尔值的方法。

java 复制代码
// 1. 静态工厂方法
Boolean b1 = Boolean.valueOf(true);
Boolean b2 = Boolean.valueOf("true"); // 字符串转Boolean(忽略大小写?不,仅"true"为true)

// 2. 字符串转基本类型
boolean flag = Boolean.parseBoolean("false"); // "false"→false

// 3. 常量
System.out.println(Boolean.TRUE); // 静态TRUE对象
System.out.println(Boolean.FALSE); // 静态FALSE对象
Number 类的通用方法(数值型包装类)

ByteShortIntegerLongFloatDouble 都继承自 Number 类,可通过以下方法转换为其他基本类型:

java 复制代码
Integer i = 100;
byte b = i.byteValue(); // 转byte
short s = i.shortValue(); // 转short
long l = i.longValue(); // 转long
float f = i.floatValue(); // 转float
double d = i.doubleValue(); // 转double

常见问题与注意事项

  1. null安全问题

包装类是对象,可能为 null,而基本类型不能为 null。自动拆箱时若包装类为 null,会抛出 NullPointerException:

java 复制代码
Integer i = null;
int num = i; // 编译通过,但运行时抛出 NullPointerException

解决:使用前判断是否为 null

java 复制代码
Integer i = null;
int num = (i != null) ? i : 0; // 安全处理
  1. 字符串转换的异常

使用 parseXxx() 方法(如 Integer.parseInt())将字符串转为基本类型时,若字符串格式不正确,会抛出 NumberFormatException:

java 复制代码
try {
    int num = Integer.parseInt("abc"); // 字符串不是数字,抛异常
} catch (NumberFormatException e) {
    e.printStackTrace();
}
  1. 与基本类型的选择
  • 优先使用基本类型:当不需要对象特性(如作为集合元素)时,基本类型效率更高(无需创建对象,节省内存)。
  • 必须使用包装类的场景:
    • 集合框架中(如 List<Integer>,不能存储 int)。
    • 泛型参数(如 T 必须是对象类型)。
    • 需表示 null 时(如数据库字段可能为 null)。

数学与数值相关类

Math 类(数学工具类)

Math 类位于 java.lang 包中,是一个final 类(不可被继承),包含大量静态方法,提供了基本数学运算(如绝对值、三角函数、随机数等),无需创建实例即可直接使用。

Math 类的核心特性
  • 无构造方法 :构造方法被 private 修饰,无法实例化(所有方法都是静态的)。
  • 静态常量
    • Math.PI:圆周率(约等于 3.141592653589793)。
    • Math.E:自然对数的底数(约等于 2.718281828459045)。
  • 方法分类:涵盖基础运算、三角函数、指数对数、随机数等。
常用方法示例
  1. 基础运算
java 复制代码
// 绝对值
int abs1 = Math.abs(-10); // 10
double abs2 = Math.abs(-3.14); // 3.14

// 最大值/最小值
int max1 = Math.max(5, 10); // 10
double max2 = Math.max(3.14, 2.71); // 3.14
int min1 = Math.min(5, 10); // 5
double min2 = Math.min(3.14, 2.71); // 2.71

// 四舍五入(返回 long 类型)
long round1 = Math.round(3.6); // 4
long round2 = Math.round(3.4); // 3

// 向上取整(返回 double,大于等于参数的最小整数)
double ceil = Math.ceil(3.2); // 4.0

// 向下取整(返回 double,小于等于参数的最大整数)
double floor = Math.floor(3.8); // 3.0
  1. 三角函数(参数为弧度)
java 复制代码
double pi = Math.PI;

// 正弦(sin(π/2) = 1)
double sin = Math.sin(pi / 2); // 1.0

// 余弦(cos(π) = -1)
double cos = Math.cos(pi); // -1.0

// 正切(tan(π/4) = 1)
double tan = Math.tan(pi / 4); // 1.0(近似值)

// 弧度转角度(π 弧度 = 180 度)
double toDegrees = Math.toDegrees(pi); // 180.0

// 角度转弧度(180 度 = π 弧度)
double toRadians = Math.toRadians(180); // 3.141592653589793(即 π)
  1. 指数与对数运算
java 复制代码
// 指数运算(a^b)
double pow1 = Math.pow(2, 3); // 8.0(2^3)
double pow2 = Math.pow(10, 2); // 100.0(10^2)

// 平方根(√a)
double sqrt = Math.sqrt(16); // 4.0

// 自然对数(ln(a),以 e 为底)
double log = Math.log(Math.E); // 1.0(ln(e) = 1)

// 以 10 为底的对数
double log10 = Math.log10(100); // 2.0(log10(100) = 2)
  1. 随机数生成

Math.random() 生成一个大于等于 0.0 且小于 1.0 的随机 double 值,可通过换算得到任意范围的随机数。

java 复制代码
// 生成 [0, 1) 之间的随机数
double random = Math.random();

// 生成 [0, 10) 之间的随机整数
int random1 = (int) (Math.random() * 10);

// 生成 [5, 15] 之间的随机整数(包含 5 和 15)
int min = 5;
int max = 15;
int random2 = min + (int) (Math.random() * (max - min + 1));

Number 类(数值包装类的父类)

Number 类是一个抽象类,位于 java.lang 包中,是所有数值型包装类的父类(如 IntegerDoubleLong 等)。它定义了将数值型对象转换为基本类型的通用方法。

核心抽象方法(数值转换)

Number 类定义了 6 个抽象方法,用于将包装类对象转换为对应的基本类型。子类必须实现这些方法:

方法 功能 示例(以 Integer 为例)
byteValue() 转换为 byte 类型 Integer i = 100; byte b = i.byteValue();
shortValue() 转换为 short 类型 short s = i.shortValue();
intValue() 转换为 int 类型 int num = i.intValue();
longValue() 转换为 long 类型 long l = i.longValue();
floatValue() 转换为 float 类型 float f = i.floatValue();
doubleValue() 转换为 double 类型 double d = i.doubleValue();
使用场景

当需要统一处理不同数值类型的包装类时,Number 类作为父类可以实现多态:

java 复制代码
// 定义一个方法,接收 Number 类型,打印其各种基本类型的值
public static void printValues(Number num) {
    System.out.println("byte: " + num.byteValue());
    System.out.println("int: " + num.intValue());
    System.out.println("double: " + num.doubleValue());
}

// 测试:传入不同的数值包装类
public static void main(String[] args) {
    printValues(100); // Integer 自动装箱
    printValues(3.14); // Double 自动装箱
    printValues(1000L); // Long 自动装箱
}

/* 输出结果:
byte: 100
int: 100
double: 100.0

byte: 3(3.14 强转为 byte 是 3)
int: 3
double: 3.14

byte: -24(1000L 强转为 byte 是 -24,因超出范围)
int: 1000
double: 1000.0
*/

异常与错误类

异常与错误的根类:Throwable

Throwable 是 Java 中所有错误(Error)和异常(Exception)的顶层父类,位于 java.lang 包中。它定义了所有异常 / 错误共有的属性和方法。

主要方法
  • getMessage():返回异常的详细描述信息(创建异常时传入的字符串)。
  • printStackTrace():打印异常的堆栈跟踪信息(包含异常类型、信息及发生位置),用于调试。
  • getCause():返回引发当前异常的原因(用于链式异常)。
  • toString():返回异常的类型和描述信息(如 java.lang.NullPointerException: 空指针异常)。
体系结构

Throwable 有两个直接子类,分别代表不同类型的问题:

plain 复制代码
Throwable
├─ Error:严重错误(程序通常无法处理)
└─ Exception:异常(程序可以处理)
   ├─ 受检异常(Checked Exception):编译期必须处理
   └─ 非受检异常(Unchecked Exception):编译期无需处理(继承自 RuntimeException)

Error 类(严重错误)

Error 表示程序运行时发生的严重错误,通常是由 JVM 或系统级问题导致的,程序无法通过代码处理,应终止运行。

常见子类
  • OutOfMemoryError:内存溢出错误(JVM 无法分配足够内存)。
  • StackOverflowError:栈溢出错误(方法调用栈过深,如无限递归)。
  • NoClassDefFoundError:类定义未找到(编译时存在该类,运行时缺失)。
  • UnsupportedClassVersionError:JVM 版本不兼容(类编译版本高于运行环境)。
特点
  • 属于非受检错误(无需在代码中处理)。
  • 通常是系统级问题,程序无法恢复,应避免捕获(捕获也无法有效处理)。

Exception 类(可处理的异常)

Exception 表示程序运行时发生的异常情况,这些情况是程序可以预测并通过代码处理的(如输入错误、文件不存在等)。根据是否必须处理,分为两类:

受检异常(Checked Exception)
  • 定义:除 RuntimeException 及其子类外的所有 Exception 子类。
  • 特点:编译期强制要求处理(必须用 try-catch 捕获或 throws 声明抛出),否则编译报错。
  • 常见子类:
    • IOException:输入输出异常(如文件读写错误)。
    • ClassNotFoundException:类未找到(动态加载类时)。
    • SQLException:数据库操作异常。
    • InterruptedException:线程被中断异常。
java 复制代码
// 读取文件(可能抛出 IOException,必须处理)
public static void readFile() throws IOException { // 声明抛出受检异常
FileReader fr = new FileReader("test.txt");
fr.read();
fr.close();
}

// 调用时必须处理(try-catch 或继续抛出)
public static void main(String[] args) {
    try {
        readFile();
    } catch (IOException e) { // 捕获并处理异常
        e.printStackTrace();
        System.out.println("文件读取失败:" + e.getMessage());
    }
}
非受检异常(Unchecked Exception)
  • 定义:RuntimeException 及其子类(继承自 Exception)。
  • 特点:编译期无需强制处理(可选择处理或不处理),通常是由代码逻辑错误导致的。
  • 常见子类:
    • NullPointerException:空指针异常(调用 null 对象的方法或属性)
    • IndexOutOfBoundsException:索引越界(如数组、集合的索引超出范围)。
    • ClassCastException:类型转换异常(将对象强制转换为不兼容的类型)。
    • ArithmeticException:算术异常(如除数为 0)。
    • IllegalArgumentException:参数非法(方法接收到不合法的参数)。

异常处理机制

Java 通过try-catch-finallythrows 关键字处理异常,核心目的是捕获异常并进行补救,避免程序崩溃。

  1. try-catch 捕获异常
java 复制代码
try {
    // 可能发生异常的代码块
    String s = null;
    System.out.println(s.length());
} catch (NullPointerException e) {
    // 捕获特定异常并处理
    System.out.println("捕获到空指针异常:" + e.getMessage());
} catch (Exception e) {
    // 捕获其他异常(父类异常需放在子类异常之后)
    System.out.println("捕获到其他异常:" + e.getMessage());
}
  1. finally 释放资源

finally 块中的代码无论是否发生异常都会执行,通常用于释放资源(如关闭文件、数据库连接)。

java 复制代码
FileReader fr = null;
try {
    fr = new FileReader("test.txt");
    fr.read();
} catch (IOException e) {
    e.printStackTrace();
} finally {
    // 确保资源关闭
    if (fr != null) {
        try {
            fr.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  1. throws 声明抛出异常

如果方法内部无法处理异常,可通过 throws 声明将异常抛给调用者处理。

java 复制代码
// 声明抛出受检异常(调用者必须处理)
public static void readFile() throws IOException {
    FileReader fr = new FileReader("test.txt");
    fr.close();
}

// 调用者处理异常
public static void main(String[] args) throws IOException { // 继续抛出,由JVM处理
    readFile();
}
  1. throw 主动抛出异常

通过 throw 关键字主动抛出异常(通常用于校验参数或业务规则)。

java 复制代码
public static void checkAge(int age) {
    if (age < 0 || age > 150) {
        // 主动抛出非法参数异常
        throw new IllegalArgumentException("年龄必须在0-150之间");
    }
}

异常处理最佳实践

  • 避免捕获 ThrowableException:应捕获具体异常,否则可能掩盖严重错误(如 Error)。
  • 不要忽略异常:catch 块中至少打印异常信息,避免空 catch 块(导致问题难以排查)。
  • 优先使用 try-with-resources:JDK 7+ 提供的自动资源关闭机制,简化资源释放代码。
java 复制代码
// 自动关闭实现了 AutoCloseable 接口的资源(如 FileReader)
try (FileReader fr = new FileReader("test.txt")) {
    fr.read();
} catch (IOException e) {
    e.printStackTrace();
}
  • 受检异常与非受检异常的选择:
    • 可恢复的错误用受检异常(如文件不存在,提示用户重新输入)。
    • 编程错误用非受检异常(如空指针,应修正代码)。
  • 异常信息要具体:抛出异常时提供详细描述(如 throw new IllegalArgumentException("用户ID不能为空")),便于调试。

线程与并发类

java.lang包提供多线程编程的核心类:

  • Thread:线程类,通过继承或实现 Runnable 接口创建线程。
  • Runnable:线程任务接口,定义了线程执行的核心方法 run()
  • ThreadLocal:为线程提供局部变量,解决多线程共享资源的并发问题。
  • StackTraceElement:用于表示线程的堆栈跟踪信息。

JUC在此只做了解,笔记整理至JUC阶段。

java.util包

java.util 包提供了大量实用工具类,其中日期时间类(LocalDate/LocalTime/LocalDateTime)、RandomUUID 是日常开发中频繁使用的工具。

日期时间类(LocalDate/LocalTime/LocalDateTime)

Java 8 引入了 java.time 包(包含在 JDK 中),提供了全新的日期时间 API,替代了传统的 DateCalendar 类。其中 LocalDateLocalTimeLocalDateTime 是最常用的三个类,它们不可变且线程安全。

核心类简介

  • LocalDate:仅包含日期(年、月、日),无时间信息。
  • LocalTime:仅包含时间(时、分、秒、纳秒),无日期信息。
  • LocalDateTime:包含日期和时间的完整信息(组合了 LocalDateLocalTime

实例化与获取当前时间

java 复制代码
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.LocalDateTime;

public class DateTimeDemo {
    public static void main(String[] args) {
        // 获取当前日期(LocalDate)
        LocalDate today = LocalDate.now();
        System.out.println("当前日期:" + today); // 输出:2024-05-20(示例)

        // 获取当前时间(LocalTime)
        LocalTime nowTime = LocalTime.now();
        System.out.println("当前时间:" + nowTime); // 输出:15:30:45.123456789(示例)

        // 获取当前日期时间(LocalDateTime)
        LocalDateTime now = LocalDateTime.now();
        System.out.println("当前日期时间:" + now); // 输出:2024-05-20T15:30:45.123456789

        // 手动创建指定日期时间
        LocalDate specificDate = LocalDate.of(2023, 10, 1); // 2023年10月1日
        LocalTime specificTime = LocalTime.of(8, 30, 0); // 8:30:00
        LocalDateTime specificDateTime = LocalDateTime.of(2023, 10, 1, 8, 30);
    }
}

常用方法(以 LocalDateTime 为例,LocalDate/LocalTime 类似)

  1. 获取日期时间字段
java 复制代码
LocalDateTime now = LocalDateTime.now();

int year = now.getYear(); // 年份(如 2024)
int month = now.getMonthValue(); // 月份(1-12)
int day = now.getDayOfMonth(); // 日(1-31)
int hour = now.getHour(); // 时(0-23)
int minute = now.getMinute(); // 分(0-59)
int second = now.getSecond(); // 秒(0-59)

// 星期(返回 DayOfWeek 枚举,如 FRIDAY)
System.out.println("星期:" + now.getDayOfWeek());
  1. 修改日期时间(返回新对象,原对象不变)
java 复制代码
LocalDateTime now = LocalDateTime.now();

// 增加/减少年份
LocalDateTime nextYear = now.plusYears(1); // 明年此时
LocalDateTime lastYear = now.minusYears(1); // 去年此时

// 增加/减少月份
LocalDateTime nextMonth = now.plusMonths(1);

// 调整到当月第一天
LocalDateTime firstDayOfMonth = now.withDayOfMonth(1);

// 调整到指定小时
LocalDateTime atThreePM = now.withHour(15);
  1. 日期时间比较
java 复制代码
LocalDate date1 = LocalDate.of(2023, 10, 1);
LocalDate date2 = LocalDate.of(2024, 1, 1);

// 比较是否相等
boolean isEqual = date1.equals(date2); // false

// 比较大小
boolean isBefore = date1.isBefore(date2); // true(date1 在 date2 之前)
boolean isAfter = date1.isAfter(date2); // false
  1. 日期时间格式化与解析

使用 DateTimeFormatter 进行格式化(线程安全,替代传统的 SimpleDateFormat):

java 复制代码
import java.time.format.DateTimeFormatter;

LocalDateTime now = LocalDateTime.now();

// 格式化:日期时间 → 字符串
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formatted = now.format(formatter);
System.out.println("格式化后:" + formatted); // 2024-05-20 15:30:45

// 解析:字符串 → 日期时间
String str = "2023-10-01 08:30:00";
LocalDateTime parsed = LocalDateTime.parse(str, formatter);

Random 类(随机数生成)

Random 类用于生成伪随机数,支持多种数据类型(intdoubleboolean 等)的随机值生成。

基本使用

java 复制代码
import java.util.Random;

public class RandomDemo {
    public static void main(String[] args) {
        // 创建 Random 实例(默认使用系统时间作为种子)
        Random random = new Random();

        // 生成随机 int(范围:Integer.MIN_VALUE ~ Integer.MAX_VALUE)
        int randomInt = random.nextInt();

        // 生成 [0, n) 范围内的随机 int(n 为正整数)
        int randomIntRange = random.nextInt(100); // 0-99 之间的随机数

        // 生成随机 double(范围:0.0 ~ 1.0)
        double randomDouble = random.nextDouble();

        // 生成随机 boolean
        boolean randomBoolean = random.nextBoolean();

        System.out.println("随机整数:" + randomInt);
        System.out.println("0-99的随机数:" + randomIntRange);
        System.out.println("随机小数:" + randomDouble);
    }
}

生成指定范围的随机数

java 复制代码
// 生成 [min, max] 范围内的随机整数(包含 min 和 max)
public static int randomInRange(Random random, int min, int max) {
    if (min >= max) {
        throw new IllegalArgumentException("min 必须小于 max");
    }
    // 公式:min + [0, max - min + 1) → [min, max]
    return min + random.nextInt(max - min + 1);
}

// 使用
Random random = new Random();
int num = randomInRange(random, 5, 10); // 5-10 之间的随机数

注意事项

  • 种子与随机性:Random 的随机数由种子(seed)决定,相同种子会生成相同序列。若需更高随机性,可使用 SecureRandom(加密级随机数生成器)。
  • 线程安全:Random 是线程安全的,但多线程下并发使用可能导致性能下降,此时可考虑每个线程创建独立的 Random 实例。

UUID 类(通用唯一标识符)

UUID(Universally Unique Identifier)是一个 128 位的唯一标识符,用于在分布式系统中标识信息(如订单号、会话 ID 等),保证全球唯一性。

结构与格式

UUID 格式为 8-4-4-4-12 的十六进制字符串(共 36 个字符),例如:

550e8400-e29b-41d4-a716-446655440000

生成UUID

java 复制代码
import java.util.UUID;

public class UUIDDemo {
    public static void main(String[] args) {
        // 生成随机 UUID(最常用,基于随机数)
        UUID uuid = UUID.randomUUID();
        System.out.println("随机 UUID:" + uuid.toString());

        // 从指定的长整数生成 UUID(很少用)
        UUID uuid2 = UUID.fromString("550e8400-e29b-41d4-a716-446655440000");
        System.out.println("解析的 UUID:" + uuid2);
    }
}

应用场景

  • 作为数据库表的主键(替代自增 ID,适合分布式系统)。
  • 生成唯一的文件名、会话 IDToken 等。
  • 分布式系统中标识消息或事件,避免冲突。

优势

  • 唯一性:通过算法保证全球范围内几乎不会重复(概率极低)。
  • 无需中心化协调:生成过程无需依赖外部系统(如数据库),适合分布式场景。
相关推荐
猿java3 分钟前
Java String.replace()原理,你真的了解吗?
java·面试·架构
SimonKing12 分钟前
优雅地实现ChatGPT式的打字机效果:Spring流式响应
java·后端·程序员
long31614 分钟前
状态设计模式
java·学习·程序人生·设计模式·状态模式·state-pattern
一根会骑马的Banana27 分钟前
关于DTO、DO、BO、VO
java
cur1es30 分钟前
数据结构Java--8
java·数据结构·算法·散列表
简单点了1 小时前
SM4加密算法
java·开发语言
用户3721574261352 小时前
Java 实现HTML转Word:从HTML文件与字符串到可编辑Word文档
java
yvya_2 小时前
Mybatis总结
java·spring·mybatis
姜太小白2 小时前
【VSCode】VSCode为Java C/S项目添加图形用户界面
java·c语言·vscode
一路向北North2 小时前
java将doc文件转pdf
java·pdf