JAVA常用API
Math类
Java中的Math
类位于java.lang
包中,提供了许多用于执行基本数学运算的静态方法,如指数、对数、平方根和三角函数等。
主要特点
- 静态方法:所有方法都是静态的,可以直接通过类名调用
- 不可继承 :
Math
类是final
类,不能被继承 - 不可实例化 :构造函数是私有的,不能创建
Math
类的对象
常用方法
基本运算
Math.abs(a)
- 返回绝对值Math.max(a, b)
- 返回两个值中的较大值Math.min(a, b)
- 返回两个值中的较小值
指数和对数
Math.exp(a)
- 返回e的a次幂Math.log(a)
- 返回自然对数(底为e)Math.log10(a)
- 返回底为10的对数Math.pow(a, b)
- 返回a的b次幂Math.sqrt(a)
- 返回平方根
三角函数
Math.sin(a)
- 正弦函数Math.cos(a)
- 余弦函数Math.tan(a)
- 正切函数Math.asin(a)
- 反正弦函数Math.acos(a)
- 反余弦函数Math.atan(a)
- 反正切函数
舍入运算
Math.ceil(a)
- 向上取整Math.floor(a)
- 向下取整Math.round(a)
- 四舍五入Math.rint(a)
- 返回最接近的整数(double类型)
随机数
Math.random()
- 返回[0.0, 1.0)之间的随机double值
常量
Math.PI
- π的近似值Math.E
- e的近似值(自然对数的底)
示例代码
typescript
public class MathExample {
public static void main(String[] args) {
// 基本运算
System.out.println("绝对值: " + Math.abs(-5)); // 5
System.out.println("最大值: " + Math.max(10, 20)); // 20
// 指数和对数
System.out.println("2的3次方: " + Math.pow(2, 3)); // 8.0
System.out.println("平方根: " + Math.sqrt(16)); // 4.0
// 三角函数
System.out.println("sin(π/2): " + Math.sin(Math.PI/2)); // 1.0
// 舍入运算
System.out.println("向上取整: " + Math.ceil(3.2)); // 4.0
System.out.println("四舍五入: " + Math.round(3.6)); // 4
// 随机数
System.out.println("随机数: " + Math.random());
// 常量
System.out.println("π的值: " + Math.PI);
}
}
注意事项
Math
类的方法都是静态的,不需要创建对象即可使用- 对于大数运算,可以考虑使用
BigInteger
和BigDecimal
类 - 随机数生成更复杂的需求可以使用
java.util.Random
类
Java8之后,还新增了,Math
类的增强方法,如精确加法Math.addExact()
等,可以在运算溢出时抛出异常
System类
System
类是Java核心类库中的一个重要类,位于java.lang
包中,提供了与系统相关的实用方法和字段。它不能被实例化,所有方法和字段都是静态的。
主要功能
标准I/O流
System.out
- 标准输出流(通常是控制台)System.in
- 标准输入流System.err
- 标准错误输出流
系统属性和环境变量
System.getProperties()
- 获取所有系统属性System.getProperty(String key)
- 获取指定系统属性System.getenv()
- 获取所有环境变量System.getenv(String name)
- 获取指定环境变量
系统操作
System.currentTimeMillis()
- 获取当前时间(毫秒)System.nanoTime()
- 获取高精度时间(纳秒)System.exit(int status)
- 终止JVMSystem.gc()
- 建议JVM运行垃圾回收System.arraycopy()
- 数组复制
示例代码
arduino
// 输出到控制台
System.out.println("Hello World");
// 读取用户输入
Scanner scanner = new Scanner(System.in);
String input = scanner.nextLine();
// 输出错误信息
System.err.println("Error occurred");
// 获取所有系统属性
Properties props = System.getProperties();
props.list(System.out);
// 获取特定属性
String osName = System.getProperty("os.name");
String javaVersion = System.getProperty("java.version");
String userHome = System.getProperty("user.home");
System.out.println("OS: " + osName);
System.out.println("Java Version: " + javaVersion);
System.out.println("User Home: " + userHome);
// 获取所有环境变量
Map<String, String> env = System.getenv();
env.forEach((k, v) -> System.out.println(k + "=" + v));
// 获取特定环境变量
String path = System.getenv("PATH");
System.out.println("PATH: " + path);
// 获取当前时间(毫秒)
long start = System.currentTimeMillis();
// 执行一些操作
Thread.sleep(1000);
long end = System.currentTimeMillis();
System.out.println("耗时: " + (end - start) + "ms");
// 高精度时间(纳秒)
long nanoStart = System.nanoTime();
// 执行一些操作
long nanoEnd = System.nanoTime();
System.out.println("耗时: " + (nanoEnd - nanoStart) + "ns");
// 数组复制
int[] src = {1, 2, 3, 4, 5};
int[] dest = new int[5];
System.arraycopy(src, 0, dest, 0, src.length);
System.out.println(Arrays.toString(dest));
// 垃圾回收(只是建议)
System.gc();
// 退出程序
System.exit(0); // 0表示正常退出
常用系统属性
属性名 | 描述 |
---|---|
java.version | Java运行时环境版本 |
java.home | Java安装目录 |
os.name | 操作系统名称 |
os.name | 操作系统版本 |
user.name | 用户账户名称 |
user.home | 用户主目录 |
user.dir |
注意事项
System.exit()
会立即终止JVM,应谨慎使用System.gc()
只是建议JVM进行垃圾回收,不保证立即执行- 系统属性和环境变量在不同操作系统上可能不同
nanoTime()
适合测量时间间隔,不适合获取当前时间
System
类提供了许多与系统交互的基础功能,是Java编程中常用的工具类之一。
Runtime类
Runtime
类是Java中表示运行时环境的类,允许应用程序与其运行的环境进行交互。每个Java应用程序都有一个Runtime
实例,可以通过Runtime.getRuntime()
方法获取。
主要功能
- 执行系统命令 - 可以运行外部程序
- 内存管理 - 查看和调整JVM内存使用情况
- 关闭钩子 - 添加JVM关闭时执行的代码
- 垃圾回收 - 控制垃圾收集器
- 终止JVM - 停止Java虚拟机运行
获取Runtime实例
由于Runtime
类的构造函数是私有的,不能直接实例化,必须通过静态方法获取:
ini
Runtime runtime = Runtime.getRuntime();
常用方法
1. 执行外部程序
arduino
// 执行简单命令
Process process = runtime.exec("notepad.exe");
// 执行带参数的命令
Process process = runtime.exec(new String[]{"cmd", "/c", "dir"});
// 获取命令输出
BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
// 等待命令执行完成
int exitCode = process.waitFor();
System.out.println("Exit code: " + exitCode);
2. 内存管理
csharp
// 获取JVM最大内存量(字节)
long maxMemory = runtime.maxMemory();
System.out.println("Max memory: " + maxMemory / (1024 * 1024) + "MB");
// 获取JVM已分配内存量
long totalMemory = runtime.totalMemory();
System.out.println("Total memory: " + totalMemory / (1024 * 1024) + "MB");
// 获取JVM空闲内存量
long freeMemory = runtime.freeMemory();
System.out.println("Free memory: " + freeMemory / (1024 * 1024) + "MB");
// 计算已使用内存
long usedMemory = totalMemory - freeMemory;
System.out.println("Used memory: " + usedMemory / (1024 * 1024) + "MB");
3. 垃圾回收
scss
// 建议JVM进行垃圾回收
runtime.gc();
// 等同于System.gc()
System.gc();
4. 关闭钩子
csharp
// 添加JVM关闭时执行的代码
runtime.addShutdownHook(new Thread() {
public void run() {
System.out.println("JVM正在关闭...");
// 执行清理工作
}
});
5. 终止JVM
arduino
// 终止JVM运行,参数为状态码(0表示正常退出)
runtime.exit(0);
// 等同于System.exit(0)
System.exit(0);
完整示例
arduino
Runtime runtime = Runtime.getRuntime();
// 内存信息
System.out.println("=== 内存信息 ===");
System.out.printf("Max memory: %.2f MB\n", runtime.maxMemory() / 1024.0 / 1024);
System.out.printf("Total memory: %.2f MB\n", runtime.totalMemory() / 1024.0 / 1024);
System.out.printf("Free memory: %.2f MB\n", runtime.freeMemory() / 1024.0 / 1024);
// 添加关闭钩子
runtime.addShutdownHook(new Thread(() -> {
System.out.println("\n执行清理工作...");
}));
// 执行外部程序
try {
System.out.println("\n=== 执行记事本 ===");
Process process = runtime.exec("notepad.exe");
// 等待5秒后关闭记事本
Thread.sleep(5000);
process.destroy();
System.out.println("\n=== 执行dir命令 ===");
Process dirProcess = runtime.exec(new String[]{"cmd", "/c", "dir"});
// 读取命令输出
BufferedReader reader = new BufferedReader(new InputStreamReader(dirProcess.getInputStream(), "GBK"));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
int exitCode = dirProcess.waitFor();
System.out.println("Exit code: " + exitCode);
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
// 建议垃圾回收
runtime.gc();
注意事项
- 安全性 :
exec()
方法可能带来安全风险,需谨慎使用 - 平台依赖性:执行的命令在不同操作系统上可能不同
- 资源释放 :
Process
对象使用后应调用destroy()
释放资源 - 阻塞风险 :
exec()
可能阻塞,应考虑使用线程处理 - 内存限制 :
maxMemory()
返回的是JVM最大可用内存,不是系统总内存
Runtime
类提供了与系统运行时环境交互的强大功能,特别是在需要执行外部命令或管理内存时非常有用。
Object类和Objects
Object
Object
类是Java中所有类的超类(根类),位于java.lang
包中。每个类都直接或间接继承自Object类,即使没有显式声明extends Object
。
主要方法
1. toStirng()
返回对象的字符串表示形式,默认返回"类名@哈希码"。
typescript
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
重写示例:
typescript
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + "}";
}
2. equals(Object obj)
比较两个对象是否"相等",默认实现是比较引用是否相同(==)。
typescript
public boolean equals(Object obj) {
return (this == obj);
}
重写示例:
ini
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && Objects.equals(name, person.name);
}
3. hashCode()
返回对象的哈希码值,用于哈希表(HashMap)中
csharp
public native int hashCode();
重写规则:
- 如果两个对象的equals()返回true,它们的hashCode()必须相同
- 但hashCode()相同的对象,equals()不一定返回true
重写示例:
csharp
@Override
public int hashCode() {
return Objects.hash(name, age);
}
4. getClass()
返回对象运行时类(Class对象)
arduino
public final native Class<?> getClass();
使用示例:
ini
Class<?> clazz = obj.getClass();
System.out.println("Class name: " + clazz.getName());
5. clone()
创建并返回对象的一个副本(浅拷贝)
java
protected native Object clone() throws CloneNotSupportedException;
使用要求:
- 类必须实现
Cloneable
接口 - 通常需要重写为public方法
示例:
java
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
6. finalize()
垃圾回收器在回收对象前调用的方法(已弃用,JDK9+)
csharp
protected void finalize() throws Throwable { }
7. wait(),notify(),notifyAll()
线程同步相关方法:
java
public final void wait() throws InterruptedException;
public final native void notify();
public final native void notifyAll();
重要特性
- 所有类的超类:包括数组也继承自Object
- 可以存储任意对象:Object引用可以指向任何Java对象
- 数组也是对象:数组类型是隐式扩展Object的特殊类
完整示例
java
public class Person implements Cloneable {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + "}";
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
public static void main(String[] args) throws CloneNotSupportedException {
Person p1 = new Person("Alice", 25);
Person p2 = new Person("Alice", 25);
Person p3 = (Person) p1.clone();
System.out.println(p1); // 自动调用toString()
System.out.println("p1.equals(p2): " + p1.equals(p2));
System.out.println("p1 == p2: " + (p1 == p2));
System.out.println("p1.hashCode(): " + p1.hashCode());
System.out.println("p2.hashCode(): " + p2.hashCode());
System.out.println("p1.getClass(): " + p1.getClass());
System.out.println("Clone: " + p3);
}
}
最佳实践
- 总是重写toString() :提供有意义的对象描述
- 重写equals()时总要重写hashCode() :遵守两者协定
- 谨慎使用clone() :考虑使用拷贝构造器或工厂方法
- 避免使用finalize() :已被标记为@Deprecated
- 使用Objects工具类:Java 7+提供Objects.equals()等辅助方法
Object类是Java面向对象设计的基石,理解其方法对编写正确、高效的Java代码至关重要。
Objects
Objects
是 Java 7 引入的一个实用工具类,位于 java.util
包中,提供了一系列静态方法来操作对象或检查对象状态。这些方法大多是 null 安全的(null-tolerant),可以避免 NullPointerException。
主要方法
1. 对象判等
equals(Object a, Object b)
- 安全地比较两个对象是否相等deepEquals(Object a, Object b)
- 深度比较两个对象(包括数组)
ini
String str1 = null;
String str2 = "hello";
// 传统方式可能抛出NullPointerException
// boolean equal = str1.equals(str2);
// 安全比较
boolean equal = Objects.equals(str1, str2); // false
2. 哈希码生成
hash(Object... values)
- 为一系列输入值生成哈希码hashCode(Object o)
- 安全地获取对象的哈希码(null返回0)
ini
String name = null;
int age = 30;
// 传统方式可能抛出NullPointerException
// int hash = name.hashCode() ^ age;
// 安全哈希码生成
int hash = Objects.hash(name, age);
3. 对象检查
isNull(Object obj)
- 检查对象是否为nullnonNull(Object obj)
- 检查对象是否非nullrequireNonNull(T obj)
- 检查对象非null,否则抛出NullPointerExceptionrequireNonNull(T obj, String message)
- 带自定义错误消息的检查
ini
String input = null;
// 检查null
if (Objects.isNull(input)) {
System.out.println("Input is null");
}
// 要求非null
String value = Objects.requireNonNull(input, "Input cannot be null");
// 抛出NullPointerException: Input cannot be null
4. 字符串表示
toString(Object o)
- 安全地调用对象的toString()toString(Object o, String nullDefault)
- 为null对象提供默认字符串
rust
String str = null;
// 安全toString
System.out.println(Objects.toString(str)); // "null"
System.out.println(Objects.toString(str, "default")); // "default"
5. 比较
compare(T a, T b, Comparator<? super T> c)
- 安全比较两个对象
ini
String s1 = null;
String s2 = "java";
int result = Objects.compare(s1, s2,
Comparator.nullsFirst(Comparator.naturalOrder()));
// result为负数,因为null被认为小于非null值
使用场景
- 安全地处理可能为null的对象:避免NullPointerException
- 实现equals和hashCode方法:简化代码并提高安全性
- 参数验证:在方法开头验证参数非null
- 日志记录:安全地记录可能为null的对象信息
- 比较操作:进行null安全的比较
与Object类的区别
特性 | Object类 | Objects工具类 |
---|---|---|
类型 | 所有类的超类 | 实用工具类 |
方法 | 基本对象方法 | 操作对象的实用方法 |
null处理 | 不处理null(会抛出NPE) | 多数方法null安全 |
使用方式 | 通过对象实例调用 | 静态方法调用 |
Objects工具类极大地简化了null安全的对象操作,是现代Java编程中推荐使用的工具类之一。
BigInteger与BigDecimal
BigInteger
BigInteger
是 Java 中用于表示任意精度整数的类,位于 java.math
包中。它可以表示理论上无限大的整数(仅受内存限制),适用于基本数据类型(如 long
)无法满足需求的大整数运算。
主要特点
- 不可变性:所有操作都返回新对象,原对象不变
- 任意精度:不受固定位数限制
- 丰富操作:提供各种数学运算方法
- 线程安全:由于其不可变性
创建BigInteger对象
1. 使用字符串创建
ini
BigInteger bigInt1 = new BigInteger("123456789012345678901234567890");
2. 使用字节数组构造
ini
byte[] bytes = {0x12, 0x34, 0x56, 0x78};
BigInteger bigInt2 = new BigInteger(bytes);
3. 使用静态工厂方法
ini
BigInteger bigInt3 = BigInteger.valueOf(1234567890L);
常用方法
基本运算
ini
BigInteger a = new BigInteger("123456789");
BigInteger b = new BigInteger("987654321");
// 加法
BigInteger sum = a.add(b);
// 减法
BigInteger difference = a.subtract(b);
// 乘法
BigInteger product = a.multiply(b);
// 除法
BigInteger quotient = a.divide(b);
// 取余
BigInteger remainder = a.remainder(b);
// 幂运算
BigInteger power = a.pow(3); // a的3次方
比较操作
css
int comparison = a.compareTo(b);
// 返回 -1(a<b), 0(a==b), 1(a>b)
boolean isEqual = a.equals(b); // 值相等性检查
位运算
ini
BigInteger and = a.and(b); // 按位与
BigInteger or = a.or(b); // 按位或
BigInteger xor = a.xor(b); // 按位异或
BigInteger not = a.not(); // 按位非
BigInteger shiftLeft = a.shiftLeft(2); // 左移2位
BigInteger shiftRight = a.shiftRight(2); // 右移2位
数学运算
ini
BigInteger gcd = a.gcd(b); // 最大公约数
BigInteger mod = a.mod(b); // 取模(结果非负)
BigInteger modPow = a.modPow(b, new BigInteger("100000")); // 模幂
BigInteger modInverse = a.modInverse(b); // 模逆元
类型转换
ini
int intValue = a.intValue();
long longValue = a.longValue();
double doubleValue = a.doubleValue();
String stringValue = a.toString();
byte[] byteArray = a.toByteArray();
常量
ini
BigInteger zero = BigInteger.ZERO;
BigInteger one = BigInteger.ONE;
BigInteger ten = BigInteger.TEN;
完整示例
csharp
import java.math.BigInteger;
public class BigIntegerExample {
public static void main(String[] args) {
// 创建BigInteger
BigInteger a = new BigInteger("12345678901234567890");
BigInteger b = BigInteger.valueOf(987654321L);
// 基本运算
System.out.println("a + b = " + a.add(b));
System.out.println("a - b = " + a.subtract(b));
System.out.println("a * b = " + a.multiply(b));
System.out.println("a / b = " + a.divide(b));
System.out.println("a % b = " + a.remainder(b));
System.out.println("a^3 = " + a.pow(3));
// 比较
System.out.println("a.compareTo(b): " + a.compareTo(b));
System.out.println("a.equals(b): " + a.equals(b));
// 数学运算
System.out.println("GCD: " + a.gcd(b));
System.out.println("ModPow: " + a.modPow(b, new BigInteger("100000")));
// 素数测试(概率性)
System.out.println("Is probable prime: " +
a.isProbablePrime(100)); // 确定性参数
// 转换
System.out.println("Long value: " + b.longValue());
System.out.println("String: " + a.toString(16)); // 16进制表示
}
}
注意事项
- 性能考虑:BigInteger运算比基本数据类型慢
- 内存使用:大整数会消耗更多内存
- 不可变性:所有运算都返回新对象
- 异常处理:某些操作可能抛出ArithmeticException(如除以零)
- 素数测试:isProbablePrime()是概率性测试,参数越大准确性越高
实际应用场景
- 密码学(RSA等算法)
- 大数计算(如阶乘、斐波那契数列)
- 金融计算(需要高精度)
- 科学计算
- 需要超出long范围的整数运算
BigInteger类为Java提供了处理任意大小整数的能力,是处理大整数问题的理想选择。
BigDecimal
BigDecimal
是 Java 中用于高精度计算的类,位于 java.math
包中。它可以精确表示和计算浮点数,避免了 float
和 double
类型在计算时可能出现的精度问题。
主要特点
- 任意精度:可以表示任意精度的十进制数
- 不可变性:所有运算都返回新对象,原对象不变
- 精确计算:解决了浮点数计算中的精度问题
- 舍入控制:提供多种舍入模式
- 线程安全:由于其不可变性
创建BigDecimal对象
1. 使用字符串构造(推荐)
ini
BigDecimal bd1 = new BigDecimal("0.1"); // 精确表示0.1
2. 使用double构造(不推荐,可能有精度问题)
ini
BigDecimal bd2 = new BigDecimal(0.1); // 实际值为0.100000000000000005551115...
3. 使用静态工厂方法
ini
BigDecimal bd3 = BigDecimal.valueOf(0.1); // 内部使用字符串构造
BigDecimal bd4 = BigDecimal.valueOf(123456789L); // 从long创建
常用方法
基本运算
ini
BigDecimal a = new BigDecimal("10.5");
BigDecimal b = new BigDecimal("3.2");
// 加法
BigDecimal sum = a.add(b);
// 减法
BigDecimal difference = a.subtract(b);
// 乘法
BigDecimal product = a.multiply(b);
// 除法(需要指定舍入模式)
BigDecimal quotient = a.divide(b, 2, RoundingMode.HALF_UP);
// 取余
BigDecimal remainder = a.remainder(b);
比较操作
css
int comparison = a.compareTo(b);
// 返回 -1(a<b), 0(a==b), 1(a>b)
boolean isEqual = a.equals(b); // 值相等性检查(包括精度)
舍入控制
ini
BigDecimal rounded = a.setScale(2, RoundingMode.HALF_UP); // 四舍五入保留2位小数
数学运算
ini
BigDecimal absValue = a.abs(); // 绝对值
BigDecimal negated = a.negate(); // 取反
BigDecimal power = a.pow(3); // 幂运算
BigDecimal sqrt = a.sqrt(MathContext.DECIMAL32); // 平方根
类型转换
ini
int intValue = a.intValue();
long longValue = a.longValue();
double doubleValue = a.doubleValue();
String stringValue = a.toString();
舍入模式
模式 | 描述 |
---|---|
UP | 远离零方向舍入 |
DOWN | 向零方向舍入 |
CEILING | 向正无穷方向舍入 |
FLOOR | 向负无穷方向舍入 |
HALF_UP | 四舍五入(>=0.5向上) |
HALF_DOWN | 五舍六入(>0.5向上) |
HALF_EVEN | 银行家舍入法(向最近的偶数舍入) |
UNNECESSARY | 不需要舍入(精确值) |
完整示例
public static void main(String[] args) { // 创建BigDecimal(推荐使用字符串构造) BigDecimal price = new BigDecimal("19.99"); BigDecimal quantity = new BigDecimal("2.5"); BigDecimal taxRate = new BigDecimal("0.0825"); // 8.25%
ini
// 计算总金额(价格×数量)
BigDecimal subtotal = price.multiply(quantity);
System.out.println("小计: $" + subtotal.setScale(2, RoundingMode.HALF_UP));
// 计算税费
BigDecimal tax = subtotal.multiply(taxRate)
.setScale(2, RoundingMode.HALF_UP);
System.out.println("税费: $" + tax);
// 计算总金额
BigDecimal total = subtotal.add(tax);
System.out.println("总计: $" + total.setScale(2, RoundingMode.HALF_UP));
// 比较
BigDecimal otherPrice = new BigDecimal("20.00");
System.out.println("compareTo比较结果: " + price.compareTo(otherPrice)); // -1
BigDecimal price1 = new BigDecimal("19.9900");
System.out.println("equals比较结果: " + price.equals(price1)); //equals比较值和精度
// 精度控制
BigDecimal pi = new BigDecimal("3.141592653589793");
System.out.println("PI (2位小数): " + pi.setScale(2, RoundingMode.HALF_UP));
System.out.println("PI (4位小数): " + pi.setScale(4, RoundingMode.HALF_UP));
// 除法示例
BigDecimal dividend = new BigDecimal("10");
BigDecimal divisor = new BigDecimal("3");
System.out.println("10/3 (精确): " +
dividend.divide(divisor, 10, RoundingMode.HALF_UP));
}
注意事项
- 构造方法选择:优先使用字符串构造,避免double构造的精度问题
- 除法运算:必须指定舍入模式或精度,否则可能抛出ArithmeticException
- 性能考虑:BigDecimal运算比基本数据类型慢
- 不可变性:所有运算都返回新对象
- equals与compareTo:equals比较值和精度,compareTo仅比较值
实际应用场景
- 金融计算(货币、利率等)
- 科学计算(需要高精度)
- 统计计算
- 任何需要精确小数运算的场景
- 避免浮点数精度问题的场景
BigDecimal类为Java提供了精确的十进制运算能力,是处理财务计算和其他需要高精度计算的理想选择。
正则表达式
正则表达式(Regular Expression)是一种强大的文本处理工具,Java通过java.util.regex
包提供了对正则表达式的支持。下面详细介绍Java中正则表达式的使用。
1. 核心类
Java正则表达式主要涉及三个类:
- Pattern:正则表达式的编译表示
- Matcher:通过解释Pattern对字符序列执行匹配操作的引擎
- PatternSyntaxException:正则表达式语法异常
2. 基本使用步骤
2.1 编译正则表达式
ini
Pattern pattern = Pattern.compile("正则表达式");
2.2 创建匹配器
ini
Matcher matcher = pattern.matcher("要匹配的字符串");
2.3 执行匹配操作
ini
boolean matches = matcher.matches(); // 全词匹配
boolean find = matcher.find(); // 查找子串
3. 常用匹配方法
3.1 全词匹配
ini
String regex = "a*b";
boolean isMatch = Pattern.matches(regex, "aaaaab"); // true
3.2 查找匹配
csharp
Pattern pattern = Pattern.compile("\\d+"); // 匹配数字
Matcher matcher = pattern.matcher("abc123def456");
while (matcher.find()) {
System.out.println("找到: " + matcher.group());
}
// 输出:
// 找到: 123
// 找到: 456
3.3 分组匹配
csharp
Pattern pattern = Pattern.compile("(\\d{3})-(\\d{2})");
Matcher matcher = pattern.matcher("123-45");
if (matcher.matches()) {
System.out.println("组1: " + matcher.group(1)); // 123
System.out.println("组2: " + matcher.group(2)); // 45
}
4. 常用正则表达式元字符
| 元字符 | 描述 |
|-----------|---------------------------|-----|
| . | 匹配任意单个字符(除换行符) |
| \d | 数字[0-9] |
| \D | 非数字[^0-9] |
| \s | 空白字符[\t\n\x0B\f\r] |
| \S | 非空白字符[^\s] |
| \w | 单词字符[a-zA-Z_0-9] |
| \W | 非单词字符[^\w] |
| \W | 行开头 |
| $ | 行结尾 |
| * | 0次或多次 |
| + | 1次或多次 |
| ? | 0次或1次 |
| {n} | 恰好n次 |
| {n,} | 至少n次 |
| {n,m} | n到m次 |
| [...] | 字符集合 |
| [^...] | 否定字符集合 |
| | | 或操作 |
5. 常用正则表达式示例
5.1 验证邮箱
ini
String emailRegex = "^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$";
Pattern pattern = Pattern.compile(emailRegex);
System.out.println(pattern.matcher("[email protected]").matches()); // true
5.2 验证手机号
ini
String phoneRegex = "^1[3-9]\\d{9}$";
System.out.println("13812345678".matches(phoneRegex)); // true
5.3 提取HTML标签内容
ini
String html = "<h1>标题</h1><p>内容</p>";
Pattern tagPattern = Pattern.compile("<([a-z][a-z0-9]*)[^>]*>(.*?)</\\1>");
Matcher tagMatcher = tagPattern.matcher(html);
while (tagMatcher.find()) {
System.out.println("标签: " + tagMatcher.group(1) + ", 内容: " + tagMatcher.group(2));
}
6. 字符串类中的正则方法
String类也提供了一些基于正则表达式的方法:
ini
// 分割字符串
String[] parts = "a,b,c".split(",");
// 替换
String newStr = "a1b2c3".replaceAll("\\d", "-"); // "a-b-c-"
// 匹配检查
boolean isMatch = "123".matches("\\d+"); // true
7. 高级特性
7.1 非贪婪匹配
ini
// 贪婪匹配
Pattern greedy = Pattern.compile("a.*b");
Matcher m1 = greedy.matcher("aabab");
m1.find();
System.out.println(m1.group()); // aabab
// 非贪婪匹配
Pattern reluctant = Pattern.compile("a.*?b");
Matcher m2 = reluctant.matcher("aabab");
m2.find();
System.out.println(m2.group()); // aab
7.2 前后查找
ini
// 正向肯定预查
Pattern pattern = Pattern.compile("Windows(?=95|98|NT)");
Matcher matcher = pattern.matcher("Windows98");
System.out.println(matcher.find()); // true
// 正向否定预查
pattern = Pattern.compile("Windows(?!95|98|NT)");
matcher = pattern.matcher("WindowsXP");
System.out.println(matcher.find()); // true
8. 性能优化建议
- 预编译Pattern对象并重用
- 避免过度复杂的正则表达式
- 考虑使用非捕获组(?:...)提高性能
- 对于简单匹配,优先使用String类的方法
Java正则表达式功能强大,可以处理各种复杂的文本匹配和替换需求,是Java开发中处理文本的重要工具。
时间类
JDK7
在JDK7及之前版本中,Java提供了以下几个主要的时间处理类:
1. java.util.Date
Date
类是Java最早引入的时间处理类,位于java.util
包中。
主要特点:
- 表示特定的瞬间,精确到毫秒
- 从1970年1月1日00:00:00 GMT(Unix纪元)开始计算
- 大部分方法已过时(deprecated)
常用方法:
ini
Date date = new Date(); // 当前时间
long time = date.getTime(); // 获取毫秒数
date.setTime(time); // 设置时间
问题:
- 年份从1900年开始计算
- 月份从0开始(0表示一月)
- 线程不安全
- 设计混乱,很多方法已过时
2. java.util.Calendar
Calendar
类是为了解决Date
类的不足而引入的抽象类,常用的实现类是GregorianCalendar
。
主要特点:
- 提供更丰富的日期时间操作
- 支持时区
- 仍然是可变对象
常用方法:
ini
Calendar calendar = Calendar.getInstance(); // 默认时区的当前时间
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH); // 0-11
int day = calendar.get(Calendar.DAY_OF_MONTH);
calendar.add(Calendar.DAY_OF_MONTH, 1); // 增加一天
calendar.set(Calendar.YEAR, 2020); // 设置年份
问题:
- 月份仍然从0开始
- 性能较差
- 代码冗长
- 仍然是可变对象
3. java.text.SimpleDateFormat
用于格式化和解析日期时间。
常用方法:
ini
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String formatted = sdf.format(new Date()); // 日期转字符串
Date parsedDate = sdf.parse("2020-01-01 12:00:00"); // 字符串转日期
问题:
- 线程不安全(不能在多线程中共享实例)
- 解析不严格(如"2020-02-30"会被解析为2020-03-01)
4. java.sql.Date/Timestamp/Time
这些是JDBC相关的日期时间类:
java.sql.Date
- 只包含日期部分java.sql.Time
- 只包含时间部分java.sql.Timestamp
- 包含日期和时间,精确到纳秒
JDK7之前时间类的缺点
- 设计混乱 :
Date
类同时包含日期和时间,但又有单独的java.sql.Date
只表示日期 - 可变性:所有类都是可变的,不适合在多线程环境中使用
- 月份从0开始:容易导致错误
- 时区处理复杂:需要手动处理时区转换
- 线程不安全 :如
SimpleDateFormat
- 扩展性差:难以添加新的日历系统
正是由于这些问题,Java在JDK8中引入了全新的java.time
包(JSR 310),提供了更现代、更合理的时间日期API。
JDK8
JDK8 引入了全新的日期时间 API(JSR 310),位于 java.time
包中,解决了旧 API(Date、Calendar 等)的各种问题,提供了更清晰、更易用、线程安全的日期时间处理方式。
核心类
1. 主要日期时间类
类名 | 描述 | 示例值 |
---|---|---|
LocalDate |
只包含日期(年-月-日) | 2023-05-20 |
LocalTime |
只包含时间(时:分:秒.纳秒) | 14:30:15.123 |
LocalDateTime |
包含日期和时间 | 2023-05-20T14:30:15 |
ZonedDateTime |
包含日期、时间和时区 | 2023-05-20T14:30:15+08:00[Asia/Shanghai] |
Instant |
时间戳(从1970-01-01T00:00:00Z开始的秒/纳秒) | 1684578615.123456789 |
2. 时段和周期类
类名 | 描述 |
---|---|
Duration |
时间间隔(精确到纳秒),用于 LocalTime、Instant |
Period |
日期间隔(年、月、日),用于 LocalDate |
3. 其他实用类
类名 | 描述 |
---|---|
DateTimeFormatter |
替代 SimpleDateFormat,线程安全 |
ZoneId |
时区标识(如 "Asia/Shanghai") |
Clock |
用于获取当前时刻的时钟 |
使用示例
创建对象
ini
// 当前日期
LocalDate today = LocalDate.now();
// 指定日期
LocalDate birthday = LocalDate.of(1990, Month.MAY, 20);
// 当前时间
LocalTime now = LocalTime.now();
// 指定时间
LocalTime lunchTime = LocalTime.of(12, 30);
// 当前日期时间
LocalDateTime current = LocalDateTime.now();
// 指定日期时间
LocalDateTime meeting = LocalDateTime.of(2023, 6, 15, 14, 30);
// 带时区的日期时间
ZonedDateTime zoned = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
// 时间戳
Instant instant = Instant.now();
日期时间操作
ini
LocalDate tomorrow = today.plusDays(1);
LocalTime anHourLater = now.plusHours(1);
LocalDateTime nextWeek = current.plusWeeks(1);
// 使用 Period 和 Duration
Period tenDays = Period.ofDays(10);
LocalDate inTenDays = today.plus(tenDays);
Duration twoHours = Duration.ofHours(2);
LocalTime later = now.plus(twoHours);
日期时间比较
ini
boolean isAfter = today.isAfter(birthday);
boolean isBefore = now.isBefore(lunchTime);
boolean isEqual = current.isEqual(meeting);
格式化与解析
ini
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
// 格式化
String formatted = current.format(formatter); // "2023-05-20 14:30:15"
// 解析
LocalDateTime parsed = LocalDateTime.parse("2023-05-20 14:30:15", formatter);
与旧API转换
scss
// Date 转 Instant
Instant instant = new Date().toInstant();
// Instant 转 Date
Date date = Date.from(Instant.now());
// Calendar 转 ZonedDateTime
ZonedDateTime zdt = Calendar.getInstance().toInstant()
.atZone(ZoneId.systemDefault());
主要优势
- 清晰的设计:分离日期、时间、日期时间等概念
- 不可变且线程安全:所有类都是不可变的
- 流畅的API:方法链式调用更直观
- 更好的时区处理:明确区分本地时间和带时区时间
- 扩展性强:支持自定义日历系统
- 月份从1开始:更符合人类习惯
新的 java.time
API 已经成为 Java 处理日期时间的标准方式,推荐在新项目中使用它替代旧的 Date
和 Calendar
类。
包装类
Java 包装类是为八种基本数据类型提供的对象表示形式,位于 java.lang
包中。它们将基本类型"包装"成对象,使得基本类型可以像对象一样操作。
包装类与基本类型的对应关系
基本数据类型 | 包装类 | 继承关系 |
---|---|---|
byte | Byte | extends Number |
short | Short | extends Number |
int | Integer | extends Number |
long | Long | extends Number |
float | Float | extends Number |
double | Double | extends Number |
char | Character | 不继承Number(特殊处理) |
boolean | Boolean | 不继承Number(特殊处理) |
包装类的主要用途
- 在集合中使用:集合类(如ArrayList)只能存储对象,不能存储基本类型
- 提供实用方法:如类型转换、进制转换等
- 允许null值:基本类型不能为null,包装类可以
- 泛型支持:泛型类型参数必须是类类型
自动装箱与拆箱(Autoboxing & Unboxing)
JDK5 引入了自动装箱和拆箱机制:
ini
// 自动装箱:基本类型 -> 包装类(编译器自动转换)
Integer i = 10; // 等价于 Integer i = Integer.valueOf(10);
// 自动拆箱:包装类 -> 基本类型
int n = i; // 等价于 int n = i.intValue();
常用方法
1. 构造方法(JDK9后已废弃,推荐使用valueOf())
ini
Integer num = new Integer(10); // 已废弃
Integer num = Integer.valueOf(10); // 推荐方式
2. 类型转换
ini
// 字符串转数值
int i = Integer.parseInt("123"); // 返回int
Integer i = Integer.valueOf("123"); // 返回Integer
// 数值转字符串
String s = Integer.toString(123);
String s = 123 + ""; // 简便方式
// 其他进制转换
String binary = Integer.toBinaryString(10); // 1010
String hex = Integer.toHexString(255); // ff
3. 比较方法
css
Integer a = 100;
Integer b = 100;
a.equals(b); // true - 比较值
a == b; // true (在-128~127范围内为true,超出此范围则为false)
a.compareTo(b); // 0 (相等), 正数(a>b), 负数(a<b)
注意事项
- 缓存机制:包装类对常用值(-128~127)有缓存,valueOf()会返回缓存对象
ini
Integer a = 127;
Integer b = 127;
a == b; // true (同一对象)
Integer c = 128;
Integer d = 128;
c == d; // false (不同对象)
- NPE风险:自动拆箱时如果包装类为null会抛出NullPointerException
ini
Integer num = null;
int n = num; // 抛出NullPointerException
- 性能考虑:包装类比基本类型占用更多内存,操作也更耗时
各包装类特有方法
Character 类特有方法
arduino
Character.isDigit('9'); // 是否数字
Character.isLetter('a'); // 是否字母
Character.isWhitespace(' '); // 是否空白字符
Character.toUpperCase('a'); // 转大写
Boolean 类特有方法
javascript
Boolean.parseBoolean("true"); // 字符串转boolean
Boolean.TRUE; // 预定义常量
Number 类方法
所有数值包装类的父类Number提供的方法:
scss
byteValue(), shortValue(), intValue(),
longValue(), floatValue(), doubleValue()
最佳实践
- 优先使用基本类型(性能更好)
- 需要对象表示时使用包装类(如集合、泛型)
- 比较包装类时使用equals()而非==
- 注意自动拆箱时的NPE风险
- JDK9+推荐使用valueOf()而非构造函数
包装类在Java中扮演着重要角色,特别是在集合框架和面向对象编程中,理解它们的特性和正确使用方法对于编写健壮的Java代码非常重要。
Arrays工具类
java.util.Arrays
是 Java 中专门用于操作数组的工具类,提供了各种静态方法来操作数组(排序、搜索、比较、填充等)。这个工具类在 JDK 1.2 引入,并随着 Java 版本更新不断增加了新方法。
一、核心功能概览
功能类别 | 主要方法 |
---|---|
排序 | sort(), parallelSort() |
搜索 | binarySearch() |
比较 | equals(), deepEquals() |
填充 | fill(), setAll(), parallelSetAll() |
转换 | asList(), toString(), deepToString() |
复制 | copyOf(), copyOfRange() |
流操作 | stream() |
并行处理 | parallelPrefix() |
哈希计算 | hashCode(), deepHashCode() |
新特性 | mismatch() (JDK9), compare()/compareUnsigned() (JDK9) |
二、常用方法详解
1. 排序方法
ini
// 基本类型数组排序
int[] intArr = {3, 1, 4, 1, 5};
Arrays.sort(intArr); // [1, 1, 3, 4, 5]
// 并行排序(大数据量更高效)
Arrays.parallelSort(intArr);
// 对象数组排序(需实现Comparable或提供Comparator)
String[] strArr = {"banana", "apple", "pear"};
Arrays.sort(strArr); // ["apple", "banana", "pear"]
Arrays.sort(strArr, Comparator.reverseOrder()); // 逆序
// 部分排序
Arrays.sort(intArr, 1, 4); // 只排序索引1到3的元素
2. 二分查找
ini
// 必须先排序!
int[] sortedArr = {1, 3, 5, 7, 9};
int index = Arrays.binarySearch(sortedArr, 5); // 返回2
int notFound = Arrays.binarySearch(sortedArr, 4); // 返回-3 (插入点为2+1)
// 对象数组搜索
String[] fruits = {"apple", "banana", "pear"};
int pos = Arrays.binarySearch(fruits, "pear"); // 2
3.数组比较
ini
int[] a = {1, 2, 3};
int[] b = {1, 2, 3};
int[] c = {1, 3, 2};
boolean eq1 = Arrays.equals(a, b); // true
boolean eq2 = Arrays.equals(a, c); // false
// 多维数组比较
int[][] deep1 = {{1,2}, {3,4}};
int[][] deep2 = {{1,2}, {3,4}};
boolean deepEq = Arrays.deepEquals(deep1, deep2); // true
4. 数组填充
scss
int[] arr = new int[5];
Arrays.fill(arr, 1); // [1, 1, 1, 1, 1]
// 部分填充
Arrays.fill(arr, 1, 3, 9); // [1, 9, 9, 1, 1]
// 使用生成函数填充
Arrays.setAll(arr, i -> i * 2); // [0, 2, 4, 6, 8]
Arrays.parallelSetAll(arr, i -> i * i); // [0, 1, 4, 9, 16]
5. 数组复制
ini
int[] original = {1, 2, 3, 4, 5};
// 完整/截断复制
int[] copy1 = Arrays.copyOf(original, 3); // [1, 2, 3]
int[] copy2 = Arrays.copyOf(original, 7); // [1,2,3,4,5,0,0]
// 范围复制
int[] rangeCopy = Arrays.copyOfRange(original, 1, 4); // [2, 3, 4]
6. 数组转字符串
ini
int[] arr = {1, 2, 3};
System.out.println(Arrays.toString(arr)); // [1, 2, 3]
int[][] deepArr = {{1,2}, {3,4}};
System.out.println(Arrays.deepToString(deepArr)); // [[1, 2], [3, 4]]
7. 数组转List
ini
String[] arr = {"a", "b", "c"};
List<String> list = Arrays.asList(arr); // 固定大小列表
// 注意:返回的ArrayList是Arrays的内部类,不是java.util.ArrayList
list.add("d"); // 抛出UnsupportedOperationException
8. Java8+新增方法
ini
// 数组流处理
int[] numbers = {1, 2, 3};
int sum = Arrays.stream(numbers).sum();
// 并行前缀计算(累积和)
int[] arr = {1, 2, 3, 4};
Arrays.parallelPrefix(arr, (a, b) -> a + b); // [1, 3, 6, 10]
// JDK9: 查找第一个不匹配的索引
int[] a = {1, 2, 3};
int[] b = {1, 2, 4};
int mismatch = Arrays.mismatch(a, b); // 2
// JDK9: 数组比较
int compare = Arrays.compare(a, b); // 负数(a<b)
三、性能注意事项
-
sort() vs parallelSort()
- 小数组(长度 < 2^13):
sort()
更快 - 大数组:
parallelSort()
利用多核优势
- 小数组(长度 < 2^13):
-
binarySearch() 前提
- 必须对数组先排序,否则结果未定义
-
asList() 的限制
- 返回的列表大小固定
- 修改原始数组会影响列表
-
基本类型 vs 对象数组
- 基本类型方法有专门优化(避免装箱开销)
四、实际应用示例
示例1:统计成绩
ini
double[] scores = {85.5, 92.0, 76.5, 88.0};
Arrays.sort(scores); // 排序
double average = Arrays.stream(scores).average().orElse(0);
示例2:矩阵操作
scss
int[][] matrix = new int[3][3];
Arrays.stream(matrix).forEach(row -> Arrays.fill(row, 1)); // 填充1
示例3:数据验证
ini
String[] validCodes = {"A1", "B2", "C3"};
Arrays.sort(validCodes); // 二分查找需要先排序
boolean isValid = Arrays.binarySearch(validCodes, inputCode) >= 0;
五、总结
Arrays
工具类提供了:
- 丰富的数组操作方法
- 对基本类型和对象数组的分别处理
- 逐步增强的并行处理能力
- Java 8+ 的流式集成
最佳实践:
- 大数据集考虑使用并行方法(parallelSort等)
- 优先使用专门的基本类型方法(避免自动装箱)
- 注意asList()等方法的特殊行为
- 保持数组排序以便使用二分查找
Lambda表达式
Lambda 表达式是 Java 8 引入的最重要特性之一,它极大地简化了函数式编程在 Java 中的实现方式,使代码更加简洁、灵活。
一、Lambda 表达式基础
1. 基本语法
rust
(parameters) -> expression
或
(parameters) -> { statements; }
2. 核心特征
- 匿名:没有显式的名称
- 函数式:属于某个函数式接口
- 简洁:比匿名类更紧凑
- 可传递:可以作为参数传递或存储在变量中
3. 组件解析
部分 | 说明 |
---|---|
参数列表 | 可以省略参数类型(编译器推断),空参数使用() |
箭头符号 -> |
分隔参数和Lambda体 |
Lambda体 | 单个表达式(隐含return)或代码块(需要显式return) |
二、Lambda 表达式示例
1. 不同形式的Lambda
ini
// 1. 无参数
Runnable r = () -> System.out.println("Hello");
// 2. 单参数,可省略括号
Consumer<String> c = s -> System.out.println(s);
// 3. 多参数
Comparator<Integer> comp = (a, b) -> a.compareTo(b);
// 4. 显式声明参数类型
BinaryOperator<Long> add = (Long x, Long y) -> x + y;
// 5. 多行代码块
Function<String, Integer> f = s -> {
int len = s.length();
return len * 2;
};
2. 方法引用(更简洁的Lambda)
javascript
// 静态方法引用
Function<String, Integer> p = Integer::parseInt;
// 实例方法引用
Consumer<String> printer = System.out::println;
// 任意对象的实例方法引用
Function<String, String> upper = String::toUpperCase;
// 构造方法引用
Supplier<List<String>> listSupplier = ArrayList::new;
三、函数式接口
1. 核心函数式接口
接口 | 方法签名 | 用途 |
---|---|---|
Supplier<T> |
T get() |
提供值(工厂) |
Consumer<T> |
void accept(T t) |
消费值(操作) |
Function<T,R> |
R apply(T t) |
转换值(映射) |
Predicate<T> |
boolean test(T t) |
测试值(过滤) |
UnaryOperator<T> |
T apply(T t) |
一元运算(继承Function) |
BinaryOperator<T> |
T apply(T t1, T t2) |
二元运算(继承BiFunction) |
2. 自定义函数式接口
scss
@FunctionalInterface
interface StringProcessor {
String process(String input);
// 可以有默认方法
default void info() {
System.out.println("String processor");
}
}
StringProcessor sp = s -> s.toUpperCase();
四、Lambda 实际应用
1. 集合操作
ini
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// 遍历
names.forEach(name -> System.out.println(name));
// 过滤
List<String> longNames = names.stream()
.filter(n -> n.length() > 4)
.collect(Collectors.toList());
// 映射
List<Integer> lengths = names.stream()
.map(String::length)
.collect(Collectors.toList());
2. 线程初始化
csharp
// 传统方式
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Running");
}
}).start();
// Lambda方式
new Thread(() -> System.out.println("Running")).start();
3. 事件处理
less
button.addActionListener(e -> System.out.println("Button clicked"));
4. 排序比较
ini
List<Person> people = ...;
people.sort((p1, p2) -> p1.getAge() - p2.getAge());
// 更简洁的方式
people.sort(Comparator.comparingInt(Person::getAge));
五、Lambda 高级特性
1. 变量捕获
Lambda可以捕获:
- 实例变量和静态变量(无限制)
- 局部变量(必须为final或等效final)
ini
int limit = 10; // 等效final
Runnable r = () -> {
for (int i = 0; i < limit; i++) {
System.out.println(i);
}
};
2. 方法引用类型
类型 | 语法示例 | 对应的Lambda表达式 |
---|---|---|
静态方法引用 | ClassName::staticMethod |
(args) -> ClassName.staticMethod(args) |
实例方法引用(特定对象) | instance::method |
(args) -> instance.method(args) |
实例方法引用(任意对象) | ClassName::method |
(obj, args) -> obj.method(args) |
构造方法引用 | ClassName::new |
(args) -> new ClassName(args) |
3. 组合Lambda
ini
Predicate<String> startsWithA = s -> s.startsWith("A");
Predicate<String> endsWithZ = s -> s.endsWith("Z");
// 组合谓词
Predicate<String> startsWithAAndEndsWithZ = startsWithA.and(endsWithZ);
Function<Integer, Integer> multiplyBy2 = x -> x * 2;
Function<Integer, Integer> add3 = x -> x + 3;
// 函数组合
Function<Integer, Integer> multiplyThenAdd = multiplyBy2.andThen(add3);
Function<Integer, Integer> addThenMultiply = multiplyBy2.compose(add3);
六、Lambda 注意事项
-
性能考虑:
- Lambda首次调用会有初始化开销
- 简单操作可能不如传统方式高效
- 高频调用场景需测试性能
-
调试困难:
- 匿名特性使调试栈信息不直观
- 复杂Lambda可提取为方法引用
-
过度使用问题:
- 复杂业务逻辑不适合用Lambda
- 多行Lambda影响可读性
-
序列化限制:
- Lambda表达式默认不可序列化
- 需要实现Serializable接口的特殊处理
七、Java后续版本增强
Java 8+
- 引入
java.util.function
包 - 新增Stream API配合Lambda使用
Java 11
- 允许
var
用于Lambda参数:
csharp
(var x, var y) -> x + y
Lambda表达式极大地改变了Java的编程范式,使函数式编程风格与面向对象风格能够和谐共存。合理使用Lambda可以使代码更简洁、更富有表达力,但也需要注意不要过度使用导致代码可读性下降。