核心类库_常用类

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 等。
  • 分布式系统中标识消息或事件,避免冲突。

优势

  • 唯一性:通过算法保证全球范围内几乎不会重复(概率极低)。
  • 无需中心化协调:生成过程无需依赖外部系统(如数据库),适合分布式场景。
相关推荐
考虑考虑16 小时前
Jpa使用union all
java·spring boot·后端
用户37215742613516 小时前
Java 实现 Excel 与 TXT 文本高效互转
java
浮游本尊17 小时前
Java学习第22天 - 云原生与容器化
java
Moonbit18 小时前
用MoonBit开发一个C编译器
后端·编程语言·编译器
渣哥19 小时前
原来 Java 里线程安全集合有这么多种
java
间彧19 小时前
Spring Boot集成Spring Security完整指南
java
间彧19 小时前
Spring Secutiy基本原理及工作流程
java
Java水解20 小时前
JAVA经典面试题附答案(持续更新版)
java·后端·面试
洛小豆1 天前
在Java中,Integer.parseInt和Integer.valueOf有什么区别
java·后端·面试
前端小张同学1 天前
服务器上如何搭建jenkins 服务CI/CD😎😎
java·后端