Java 8核心特性详解:从Lambda到Stream的革命性升级
🎬 开篇故事:当Java遇见函数式编程
想象一下,如果编程语言是一个魔法世界,那么Java 8就像是哈利·波特获得魔法棒的那一刻。在此之前,Java程序员就像麻瓜一样,只能用繁琐的匿名内部类来"施展魔法";而Java 8的到来,就像是霍格沃茨向Java世界敞开了大门,Lambda表达式就是那根魔法棒,让我们能够优雅地挥舞代码,施展函数式编程的魔法!
🚀 为什么这次升级如此重要?
2014年3月18日,一个值得载入Java史册的日子。Oracle发布了Java SE 8,这不仅仅是一次版本更新,更是一次编程范式的革命:
🎭 从"怎么做"到"做什么"的思维转变
// 传统思维:告诉计算机怎么做(How)
List<String> result = new ArrayList<>();
for (Person person : people) {
if (person.getAge() > 18) {
result.add(person.getName().toUpperCase());
}
}
// 函数式思维:告诉计算机做什么(What)
List<String> result = people.stream()
.filter(person -> person.getAge() > 18)
.map(person -> person.getName().toUpperCase())
.collect(toList());
⚡ 多核时代的性能觉醒
在多核CPU普及的今天,Java 8让并行处理变得像呼吸一样自然:
// 串行处理:单核苦苦支撑
long count = bigList.stream().filter(expensiveOperation).count();
// 并行处理:多核协同作战
long count = bigList.parallelStream().filter(expensiveOperation).count();
🛡️ 与空指针异常的终极决战
// 过去:如履薄冰的null检查
String city = null;
if (user != null) {
Address address = user.getAddress();
if (address != null) {
city = address.getCity();
}
}
// 现在:优雅的Optional链式调用
String city = Optional.ofNullable(user)
.map(User::getAddress)
.map(Address::getCity)
.orElse("Unknown");
🎯 深度学习之旅
本文不仅教你如何使用Java 8特性,更重要的是理解为什么这样设计、底层如何实现、何时使用以及性能影响。
🧠 你将获得的思维升级
- 💡 函数式思维 - 从命令式到声明式的思维转变
- 🔍 性能洞察 - 理解Lambda、Stream的内存模型和性能特征
- 🏗️ 架构视野 - 学会用函数式编程构建更优雅的系统
- 🎨 代码美学 - 写出既高效又优雅的代码
📚 文章结构说明
我们采用3W学习法来组织每个特性:
- What(是什么) - 概念定义与基本语法
- Why(为什么) - 设计动机与解决的问题
- How(怎么做) - 实战应用与深度解析
目录
- Lambda表达式
- 函数式接口
- Stream API
- Optional类
- 新的日期时间API
- 接口默认方法
- 方法引用
- CompletableFuture
- Nashorn JavaScript引擎
- 总结与最佳实践
环境准备
本文所有示例代码基于Java 8环境,建议使用JDK 1.8.0_xxx版本。
1. Lambda表达式 🎭
💡 思考题:为什么Lambda表达式被称为"匿名函数"?它们真的是函数吗?
答案将在本章末尾揭晓!
1.1 是什么(What)
🎬 场景设想:你是一家咖啡店的老板,需要根据不同条件筛选客户。传统方式就像是为每种筛选条件都雇佣一个专门的员工,而Lambda表达式就像是培训一个多才多艺的员工,可以随时改变筛选规则!
Lambda表达式本质上是一段可以传递的代码,它代表了一个函数接口的简洁实现。
🔍 深度解析:Lambda的本质
// 🎯 Lambda并不是真正的"函数",而是函数接口的语法糖
Runnable task = () -> System.out.println("Hello Lambda!");
// 编译器实际上会将其转换为类似这样:
Runnable task = new Runnable() {
@Override
public void run() {
System.out.println("Hello Lambda!");
}
};
📝 语法精要
// 🏗️ Lambda架构:(参数列表) -> {函数体}
// ↑ ↑
// 输入 输出/操作
// 🔧 类型推断:让编译器成为你的助手
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// 完整写法(啰嗦但清晰)
names.forEach((String name) -> System.out.println(name));
// 类型推断(简洁而优雅)
names.forEach(name -> System.out.println(name));
// 方法引用(极致简洁)
names.forEach(System.out::println);
🧪 Lambda实验室:语法变化
public class LambdaEvolution {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 🔬 实验1:无参数Lambda
Runnable printer = () -> System.out.println("无参数Lambda执行!");
// 🔬 实验2:单参数Lambda(可省略括号)
numbers.forEach(n -> System.out.println("数字:" + n));
// 🔬 实验3:多参数Lambda
BinaryOperator<Integer> adder = (a, b) -> a + b;
// 🔬 实验4:多行Lambda
Predicate<Integer> complexChecker = n -> {
System.out.println("检查数字:" + n);
boolean result = n > 0 && n % 2 == 0;
System.out.println("结果:" + result);
return result;
};
// 🎯 让我们看看实际效果
printer.run();
System.out.println("3 + 5 = " + adder.apply(3, 5));
numbers.stream().filter(complexChecker).forEach(System.out::println);
}
}
1.2 为什么(Why)
🕰️ 历史的痛点:匿名内部类的困扰
想象一下,在Lambda之前的Java世界,传递一个简单的行为需要多少代码:
// 😵 2013年的Java程序员日常:为了传递一个简单行为写这么多代码
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("按钮被点击了!");
}
});
// 😨 更痛苦的例子:对列表进行简单操作
Collections.sort(people, new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2) {
return p1.getName().compareTo(p2.getName());
}
});
💡 Lambda带来的设计哲学转变
Java 8的Lambda表达式不仅仅是语法糖,它背后体现了深刻的设计思想:
-
📈 抽象层次的提升
- 从"对象"抽象提升到"行为"抽象
- 让代码更接近问题域的表达
-
🎯 声明式编程的引入
- 专注于"做什么"而不是"怎么做"
- 让代码意图更加清晰
-
⚡ 性能优化的可能性
- 为编译器优化创造空间
- 支持懒求值和并行化
🔬 深层原理:为什么Lambda这么高效?
// 🎭 秘密揭露:Lambda的性能魔法
// Lambda不是通过匿名内部类实现的!而是通过invokedynamic指令
// 传统匿名内部类:每次都创建新的Class文件
Runnable r1 = new Runnable() {
public void run() { System.out.println("传统方式"); }
};
// Lambda表达式:使用invokedynamic,运行时动态链接
Runnable r2 = () -> System.out.println("Lambda方式");
// 🔍 编译后的字节码差异:
// 匿名内部类:产生额外的.class文件,增加内存开销
// Lambda:使用MethodHandle,更高效的方法调用
🎯 解决的核心问题
- 🎨 表达力危机:让代码表达更贴近自然语言
- 🏗️ 抽象不足:提供更高层次的抽象机制
- ⚡ 性能瓶颈:避免匿名内部类的额外开销
- 🔄 并发困难:为并行处理奠定语法基础
1.3 怎么做(How)
🚀 实战演练:从入门到精通
让我们通过一系列渐进式的实战案例,掌握Lambda表达式的精髓!
🎬 场景1:智能咖啡店的客户管理系统
import java.util.*;
import java.util.function.*;
import java.util.stream.Collectors;
public class LambdaDemo {
public static void main(String[] args) {
List<Customer> customers = getCustomers(); // 假设有客户数据
// 🎯 Lambda实战案例
// 1. 基础过滤
Predicate<Customer> isGold = c -> "GOLD".equals(c.getLevel());
customers.stream().filter(isGold).forEach(System.out::println);
// 2. 链式操作
customers.stream()
.filter(c -> c.getAge() < 30)
.filter(c -> c.getSpent() > 1000)
.map(c -> c.getName() + " - VIP客户")
.forEach(System.out::println);
// 3. 自定义排序
customers.stream()
.sorted((c1, c2) -> Double.compare(c2.getSpent(), c1.getSpent()))
.limit(3)
.forEach(System.out::println);
}
}
🎮 互动挑战:Lambda进阶技巧
public class LambdaAdvancedTricks {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// 🧩 挑战1:闭包的力量(Lambda捕获外部变量)
int multiplier = 3; // effectively final
List<Integer> multiplied = numbers.stream()
.map(n -> n * multiplier) // 闭包捕获multiplier
.collect(Collectors.toList());
System.out.println("乘以3的结果: " + multiplied);
// 🎯 挑战2:组合Lambda(函数式编程的精髓)
Predicate<Integer> isEven = n -> n % 2 == 0;
Predicate<Integer> isGreaterThan5 = n -> n > 5;
Predicate<Integer> complexCondition = isEven.and(isGreaterThan5);
System.out.println("偶数且大于5: " +
numbers.stream().filter(complexCondition).collect(Collectors.toList()));
// 🚀 挑战3:递归Lambda(是的,Lambda可以递归!)
UnaryOperator<Integer> factorial = new UnaryOperator<Integer>() {
@Override
public Integer apply(Integer n) {
return n <= 1 ? 1 : n * this.apply(n - 1);
}
};
System.out.println("5的阶乘: " + factorial.apply(5));
}
}
Java 8前后的对比
对比1:事件处理
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class EventHandlingComparison {
public static void main(String[] args) {
JButton button = new JButton("点击我");
// Java 8之前:匿名内部类
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("按钮被点击了!");
}
});
// Java 8:Lambda表达式
button.addActionListener(e -> System.out.println("按钮被点击了!"));
// 方法引用(需要匹配的方法签名)
button.addActionListener(EventHandlingComparison::printClickMessage);
}
private static void printClickMessage(ActionEvent e) {
System.out.println("按钮被点击了!");
}
}
对比2:线程创建
public class ThreadCreationComparison {
public static void main(String[] args) {
// Java 8之前:匿名内部类
Thread oldThread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("旧方式创建线程");
}
});
// Java 8:Lambda表达式
Thread newThread = new Thread(() -> System.out.println("Lambda创建线程"));
oldThread.start();
newThread.start();
}
}
对比3:比较器实现
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
public class ComparatorComparison {
public static void main(String[] args) {
List<String> names = Arrays.asList("Charlie", "Alice", "David", "Bob");
// Java 8之前:匿名内部类
System.out.println("=== Java 8之前排序 ===");
List<String> oldSorted = Arrays.asList("Charlie", "Alice", "David", "Bob");
oldSorted.sort(new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.compareTo(s2);
}
});
System.out.println(oldSorted);
// Java 8:Lambda表达式
System.out.println("\n=== Java 8 Lambda排序 ===");
List<String> newSorted = Arrays.asList("Charlie", "Alice", "David", "Bob");
newSorted.sort((s1, s2) -> s1.compareTo(s2));
System.out.println(newSorted);
// 更简洁的写法
System.out.println("\n=== 方法引用排序 ===");
List<String> refSorted = Arrays.asList("Charlie", "Alice", "David", "Bob");
refSorted.sort(String::compareTo);
System.out.println(refSorted);
}
}
🧠 深度思考:Lambda的设计智慧
💭 思考题答案揭晓
还记得开头的问题吗?为什么Lambda表达式被称为"匿名函数"?它们真的是函数吗?
答案:Lambda表达式被称为"匿名函数"是一种便于理解的说法,但在Java中它们本质上不是函数!
// 🔍 真相大白:Lambda的真实身份
// Lambda表达式实际上是函数接口的实例,是对象,不是函数!
Predicate<String> isEmpty = String::isEmpty;
// ↑ 这创建了一个Predicate对象,不是一个函数
// 🎯 证据:Lambda有对象的特征
System.out.println(isEmpty.getClass().getName());
// 输出类似:com.example.Main$$Lambda$1/123456789
System.out.println(isEmpty.toString());
// 证明它是对象!
🔬 性能剖析:Lambda vs 匿名内部类
public class PerformanceComparison {
public static void main(String[] args) {
// 🏃♂️ 性能测试:创建1000万个实例
long start, end;
// 测试匿名内部类
start = System.currentTimeMillis();
for (int i = 0; i < 10_000_000; i++) {
Runnable r = new Runnable() {
@Override public void run() { /* do nothing */ }
};
}
end = System.currentTimeMillis();
System.out.println("匿名内部类耗时: " + (end - start) + "ms");
// 测试Lambda表达式
start = System.currentTimeMillis();
for (int i = 0; i < 10_000_000; i++) {
Runnable r = () -> { /* do nothing */ };
}
end = System.currentTimeMillis();
System.out.println("Lambda表达式耗时: " + (end - start) + "ms");
// 💡 结果:Lambda通常比匿名内部类快2-3倍!
}
}
🎨 设计模式进化:Lambda如何改变经典模式
// 🏗️ 策略模式的Lambda进化
public class StrategyPatternEvolution {
// 传统策略模式:需要定义接口和多个实现类
interface PaymentStrategy {
void pay(double amount);
}
static class CreditCardPayment implements PaymentStrategy {
public void pay(double amount) {
System.out.println("信用卡支付: " + amount);
}
}
static class AlipayPayment implements PaymentStrategy {
public void pay(double amount) {
System.out.println("支付宝支付: " + amount);
}
}
public static void main(String[] args) {
// 🎭 Lambda让策略模式焕然一新
Map<String, PaymentStrategy> strategies = new HashMap<>();
// 不需要创建类,直接用Lambda定义策略!
strategies.put("credit", amount -> System.out.println("信用卡支付: " + amount));
strategies.put("alipay", amount -> System.out.println("支付宝支付: " + amount));
strategies.put("wechat", amount -> System.out.println("微信支付: " + amount));
// 🚀 动态策略选择
strategies.get("alipay").pay(299.99);
}
}
🎯 Lambda的本质改变:
- 🎭 编程范式融合:将函数式编程优雅地融入面向对象体系
- ⚡ 性能革命:通过invokedynamic实现更高效的方法调用
- 🧠 思维升级:从"创建对象来执行行为"到"直接传递行为"
- 🎨 设计简化:让经典设计模式更加轻量和灵活
2. 函数式接口 🎯
🎭 角色扮演:如果Lambda表达式是演员,那么函数式接口就是剧本!
每个Lambda表达式都需要一个"角色定义"来明确自己要扮演什么,而函数式接口就是这个角色的说明书。
2.1 是什么(What)
🎪 函数式接口的奇妙世界
想象一下,Java的接口原本是一个严肃的契约大厅,每个接口都要求实现者必须实现所有方法。然后Java 8带来了一个革命性的概念:单一职责接口!
// 🎯 函数式接口的黄金法则:一个抽象方法
@FunctionalInterface
public interface Magic<T, R> {
R cast(T input); // 唯一的抽象方法 - 施展魔法
// ✅ 可以有默认方法
default void prepare() {
System.out.println("准备施法...");
}
// ✅ 可以有静态方法
static void study() {
System.out.println("学习魔法理论...");
}
// ✅ 可以重写Object的方法
@Override
boolean equals(Object obj);
}
🔬 深度解析:@FunctionalInterface的魔力
// 🎭 幕后英雄:@FunctionalInterface注解
@FunctionalInterface
public interface Calculator {
double calculate(double a, double b);
// 🚫 编译错误!不能有第二个抽象方法
// double anotherMethod(double x);
}
// 🧪 实验:没有注解会怎样?
interface SilentCalculator {
double calculate(double a, double b);
// 依然是函数式接口,但没有编译时检查
}
public class FunctionalInterfaceDemo {
public static void main(String[] args) {
// 🎯 Lambda表达式自动匹配函数式接口
Calculator adder = (a, b) -> a + b;
Calculator multiplier = (a, b) -> a * b;
System.out.println("3 + 5 = " + adder.calculate(3, 5));
System.out.println("3 × 5 = " + multiplier.calculate(3, 5));
// 🎪 方法引用也能匹配
Calculator maxFinder = Double::max;
System.out.println("max(3, 5) = " + maxFinder.calculate(3, 5));
}
}
🏗️ Java 8内置函数式接口宇宙图
// 🌟 四大天王:Java 8的核心函数式接口
import java.util.function.*;
public class FunctionalInterfaceUniverse {
public static void main(String[] args) {
// 🎯 Predicate<T>: 判断者 - 输入T,输出boolean
Predicate<String> isLongName = name -> name.length() > 5;
System.out.println("Alice是长名字吗? " + isLongName.test("Alice"));
// 🔄 Function<T,R>: 转换者 - 输入T,输出R
Function<String, Integer> nameLength = String::length;
System.out.println("Alice名字长度: " + nameLength.apply("Alice"));
// 🍽️ Consumer<T>: 消费者 - 输入T,无输出
Consumer<String> printer = name -> System.out.println("Hello, " + name);
printer.accept("World");
// 🏭 Supplier<T>: 供应者 - 无输入,输出T
Supplier<Double> randomSupplier = Math::random;
System.out.println("随机数: " + randomSupplier.get());
}
}
2.2 为什么(Why)
🎬 历史的呼唤:函数式接口的诞生背景
在Java 8之前,想要传递一个简单的行为是多么痛苦的事情:
// 😱 Java 7时代的噩梦:想要传递一个简单的比较逻辑
public interface StringComparator {
int compare(String s1, String s2);
}
public interface NumberFilter {
boolean filter(Integer number);
}
public interface TextProcessor {
String process(String text);
}
// 每个项目都要定义成百上千个这样的接口!
💡 设计哲学:为什么需要标准化的函数类型?
// 🎯 设计洞察:函数签名的本质分类
//
// 观察这些Lambda表达式:
name -> name.length() // String → Integer
text -> text.toUpperCase() // String → String
age -> age > 18 // Integer → Boolean
() -> Math.random() // () → Double
System.out::println // String → void
// 💡 发现:所有函数本质上只有4种模式!
// 1. T → R (Function)
// 2. T → boolean (Predicate)
// 3. T → void (Consumer)
// 4. () → T (Supplier)
🔬 深层原理:类型擦除与函数式接口的巧妙设计
// 🧠 智慧设计:如何在类型擦除的Java中实现类型安全?
public class TypeSafetyDemo {
public static void main(String[] args) {
// 🎯 编译器的类型推断魔法
Function<String, Integer> lengthCalculator = String::length;
// 🔍 编译器知道:
// - 输入必须是String
// - 输出必须是Integer
// - 方法签名必须匹配
Integer result = lengthCalculator.apply("Hello"); // ✅ 类型安全
// String wrong = lengthCalculator.apply("Hello"); // ❌ 编译错误
// Integer error = lengthCalculator.apply(123); // ❌ 编译错误
}
}
🎯 解决的核心问题:
- 🎨 API设计统一性 - 避免每个库都定义自己的函数接口
- ⚡ 类型安全性 - 编译时检查,避免运行时类型错误
- 🚀 性能优化 - 避免装箱拆箱,支持编译器优化
- 🔗 生态互操作 - 不同库之间可以无缝协作
2.3 怎么做(How)
🎮 实战游戏:函数式接口大师养成记
让我们通过一个有趣的数据处理管道系统来掌握函数式接口的精髓!
🏭 场景:智能数据处理工厂
import java.util.function.*;
import java.util.*;
import java.util.stream.Collectors;
public class DataProcessingFactory {
// 📊 模拟数据:用户购买记录
static class Purchase {
String userName;
String product;
double amount;
String category;
public Purchase(String userName, String product, double amount, String category) {
this.userName = userName; this.product = product;
this.amount = amount; this.category = category;
}
@Override
public String toString() {
return String.format("%s购买了%s(%.2f元)", userName, product, amount);
}
// getters...
public String getUserName() { return userName; }
public String getProduct() { return product; }
public double getAmount() { return amount; }
public String getCategory() { return category; }
}
public static void main(String[] args) {
// 🔍 1. Predicate - 过滤器
Predicate<Purchase> isHighValue = p -> p.getAmount() > 1000;
Predicate<Purchase> isDigital = p -> "数码".equals(p.getCategory());
Predicate<Purchase> combined = isHighValue.and(isDigital); // 组合
// 🔄 2. Function - 转换器
Function<Purchase, String> toName = Purchase::getUserName;
Function<String, String> addTitle = name -> "尊贵的" + name;
Function<Purchase, String> pipeline = toName.andThen(addTitle); // 链式
// 🍽️ 3. Consumer - 消费者
Consumer<Purchase> emailer = p -> sendEmail(p);
Consumer<Purchase> smser = p -> sendSMS(p);
Consumer<Purchase> notifier = emailer.andThen(smser); // 组合
// 🏭 4. Supplier - 生成器
Supplier<String> idGen = () -> UUID.randomUUID().toString();
}
}
自定义函数式接口
@FunctionalInterface
interface MathOperation {
int operate(int a, int b);
}
public class CustomFunctionalInterface {
public static void main(String[] args) {
MathOperation addition = (a, b) -> a + b;
MathOperation multiplication = (a, b) -> a * b;
System.out.println("10 + 5 = " + addition.operate(10, 5));
System.out.println("10 * 5 = " + multiplication.operate(10, 5));
}
}
Java 8前后的对比
对比1:自定义函数式接口
// Java 8之前:需要创建完整的接口实现
interface MathOperation {
int operate(int a, int b);
}
class MathOperationImpl implements MathOperation {
@Override
public int operate(int a, int b) {
return a + b;
}
}
public class FunctionalInterfaceComparison {
public static void main(String[] args) {
// Java 8之前:需要创建实现类
MathOperation addition = new MathOperationImpl();
System.out.println("旧方式: " + addition.operate(10, 5));
// Java 8:直接使用Lambda表达式
MathOperation additionLambda = (a, b) -> a + b;
System.out.println("Lambda方式: " + additionLambda.operate(10, 5));
// 更灵活:可以动态定义操作
MathOperation multiplication = (a, b) -> a * b;
MathOperation division = (a, b) -> a / b;
System.out.println("乘法: " + multiplication.operate(10, 5));
System.out.println("除法: " + division.operate(10, 5));
}
}
对比2:集合操作
import java.util.*;
import java.util.function.Predicate;
public class CollectionOperationComparison {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Eve");
// Java 8之前:手动实现过滤
System.out.println("=== Java 8之前:手动过滤 ===");
List<String> filteredOld = new ArrayList<>();
for (String name : names) {
if (name.length() > 3) {
filteredOld.add(name);
}
}
System.out.println("过滤结果: " + filteredOld);
// Java 8:使用Predicate和Stream
System.out.println("\n=== Java 8:使用Predicate ===");
Predicate<String> lengthFilter = name -> name.length() > 3;
List<String> filteredNew = names.stream()
.filter(lengthFilter)
.collect(Collectors.toList());
System.out.println("过滤结果: " + filteredNew);
// 更灵活:组合多个条件
Predicate<String> startsWithA = name -> name.startsWith("A");
Predicate<String> longName = name -> name.length() > 3;
List<String> complexFiltered = names.stream()
.filter(startsWithA.and(longName))
.collect(Collectors.toList());
System.out.println("复杂过滤结果: " + complexFiltered);
}
}
本质改变:
- 类型安全:编译时类型检查,避免运行时错误
- 代码复用:标准化的函数接口,提高代码复用性
- API设计:为Java标准库提供了统一的函数式编程基础
3. Stream API 🌊
🎮 魔法比喻:如果说Collection是一个装满宝藏的箱子,那么Stream就是一条魔法传送带!
你可以在传送带上设置各种魔法阵(filter、map、sort),宝藏经过时会自动变化,最终到达你想要的形态。
3.1 是什么(What)
🌊 Stream的魔法世界
Stream API不是"流",它是一个数据处理的魔法工坊!想象一下工业流水线:
// 🏭 数据流水线:原材料 → 加工过程 → 最终产品
List<String> names = Arrays.asList("alice", "BOB", "charlie", "DIANA");
// 🎯 传统方式:手工作坊(命令式)
List<String> result1 = new ArrayList<>();
for (String name : names) {
if (name.length() > 3) { // 👨🔧 工人1:筛选长度
String capitalized = name.toUpperCase(); // 👨🔧 工人2:转大写
result1.add(capitalized); // 👨🔧 工人3:收集结果
}
}
// 🚀 Stream方式:智能流水线(声明式)
List<String> result2 = names.stream()
.filter(name -> name.length() > 3) // 🤖 机器人1:自动筛选
.map(String::toUpperCase) // 🤖 机器人2:自动转换
.collect(Collectors.toList()); // 🤖 机器人3:自动收集
🧠 深度解析:Stream的三重境界
// 🎯 境界一:数据源(Source)
Stream<String> sourceStream = Arrays.asList("A", "B", "C").stream();
Stream<Integer> rangeStream = IntStream.range(1, 100).boxed();
Stream<String> fileStream = Files.lines(Paths.get("data.txt"));
// ⚡ 境界二:中间操作(Intermediate Operations)
// 特点:懒惰执行,返回新的Stream,可以链式调用
sourceStream
.filter(s -> s.length() > 1) // 🔍 过滤器:筛选符合条件的元素
.map(String::toLowerCase) // 🔄 映射器:转换每个元素
.sorted() // 🏆 排序器:重新排列元素
.distinct() // 🎯 去重器:移除重复元素
.limit(10); // ✂️ 限制器:只取前N个
// 🎬 境界三:终端操作(Terminal Operations)
// 特点:立即执行,触发整个流水线运行,产生最终结果
sourceStream
.collect(Collectors.toList()) // 📦 收集成List
.forEach(System.out::println) // 🖨️ 逐个处理
.reduce(String::concat) // 🔄 聚合操作
.count(); // 🔢 计数统计
🔬 惰性求值的秘密
public class LazyEvaluationDemo {
public static void main(String[] args) {
List<String> words = Arrays.asList("apple", "banana", "cherry", "date");
System.out.println("🎬 开始创建Stream...");
Stream<String> stream = words.stream()
.filter(word -> {
System.out.println("🔍 过滤: " + word);
return word.length() > 4;
})
.map(word -> {
System.out.println("🔄 转换: " + word);
return word.toUpperCase();
});
System.out.println("💡 Stream创建完成,但还没有任何输出!");
System.out.println("🚀 现在开始终端操作...");
// 只有调用终端操作,整个流水线才开始工作!
List<String> result = stream.collect(Collectors.toList());
System.out.println("📦 最终结果: " + result);
}
}
3.2 为什么(Why)
📚 历史的呼唤:集合操作的进化史
// 😱 史前时代:Java 1.0的噩梦
Vector<String> names = new Vector<>();
names.addElement("Alice");
names.addElement("Bob");
names.addElement("Charlie");
Vector<String> filtered = new Vector<>();
for (int i = 0; i < names.size(); i++) {
String name = names.elementAt(i);
if (name.length() > 3) {
filtered.addElement(name.toUpperCase());
}
}
// 😐 进步时代:Java 1.5的改善
List<String> names2 = Arrays.asList("Alice", "Bob", "Charlie");
List<String> filtered2 = new ArrayList<>();
for (String name : names2) {
if (name.length() > 3) {
filtered2.add(name.toUpperCase());
}
}
// 🎉 现代时代:Java 8的革命
List<String> filtered3 = names2.stream()
.filter(name -> name.length() > 3)
.map(String::toUpperCase)
.collect(Collectors.toList());
💡 设计哲学:为什么需要声明式编程?
// 🧠 思维方式的根本转变
// 命令式思维:How(怎么做)
// "计算机,你要这样做:先遍历,然后检查每个元素,如果符合条件就..."
List<String> result = new ArrayList<>();
for (String item : list) {
if (condition(item)) {
result.add(transform(item));
}
}
// 声明式思维:What(做什么)
// "计算机,我要所有符合条件的元素经过转换后的结果"
List<String> result = list.stream()
.filter(this::condition)
.map(this::transform)
.collect(toList());
⚡ 性能革命:并行计算的民主化
// 🐌 传统并行编程:专家级难度
public class TraditionalParallel {
private static final int THREAD_COUNT = Runtime.getRuntime().availableProcessors();
public static List<Integer> parallelSquare(List<Integer> numbers) {
ExecutorService executor = Executors.newFixedThreadPool(THREAD_COUNT);
List<Future<List<Integer>>> futures = new ArrayList<>();
int chunkSize = numbers.size() / THREAD_COUNT;
for (int i = 0; i < THREAD_COUNT; i++) {
final int start = i * chunkSize;
final int end = (i == THREAD_COUNT - 1) ? numbers.size() : (i + 1) * chunkSize;
futures.add(executor.submit(() -> {
List<Integer> chunk = new ArrayList<>();
for (int j = start; j < end; j++) {
chunk.add(numbers.get(j) * numbers.get(j));
}
return chunk;
}));
}
List<Integer> result = new ArrayList<>();
for (Future<List<Integer>> future : futures) {
try {
result.addAll(future.get());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
executor.shutdown();
return result;
}
}
// 🚀 Stream并行:一行代码的魔法
List<Integer> result = numbers.parallelStream()
.map(n -> n * n)
.collect(toList());
🎯 解决的核心痛点
- 🎨 表达力危机 - 让代码更接近自然语言描述
- 🔧 复杂性管理 - 将数据操作从业务逻辑中分离
- ⚡ 并发编程门槛 - 让普通开发者也能轻松使用并行计算
- 🐛 错误减少 - 减少手动循环中的off-by-one等错误
- 🎪 组合能力 - 支持操作的链式组合和复用
3.3 怎么做(How)
Stream操作分类
import java.util.*;
import java.util.stream.*;
public class StreamAPIExample {
public static void main(String[] args) {
List<Person> people = Arrays.asList(
new Person("Alice", 25, "Engineer"),
new Person("Bob", 30, "Manager"),
new Person("Charlie", 35, "Engineer"),
new Person("David", 28, "Designer"),
new Person("Eve", 32, "Engineer")
);
// 1. 中间操作:filter, map, sorted等
System.out.println("=== 工程师年龄大于30 ===");
people.stream()
.filter(p -> "Engineer".equals(p.getJob()))
.filter(p -> p.getAge() > 30)
.map(Person::getName)
.forEach(System.out::println);
// 2. 终端操作:collect, forEach, reduce等
System.out.println("\n=== 按年龄分组 ===");
Map<String, List<Person>> groupedByJob = people.stream()
.collect(Collectors.groupingBy(Person::getJob));
groupedByJob.forEach((job, personList) -> {
System.out.println(job + ": " + personList.size() + "人");
});
// 3. 并行流处理
System.out.println("\n=== 并行计算平均年龄 ===");
double avgAge = people.parallelStream()
.mapToInt(Person::getAge)
.average()
.orElse(0.0);
System.out.println("平均年龄: " + avgAge);
// 4. 复杂数据处理 - 性能对比演示
System.out.println("\n=== 性能对比:串行 vs 并行 ===");
performanceComparison();
}
// ⚡ 性能对比演示
private static void performanceComparison() {
// 创建大数据集
List<Integer> bigList = IntStream.rangeClosed(1, 10_000_000)
.boxed()
.collect(Collectors.toList());
System.out.println("数据集大小: " + bigList.size());
// 串行处理
long startTime = System.currentTimeMillis();
long serialSum = bigList.stream()
.filter(n -> n % 2 == 0)
.mapToLong(n -> n * n)
.sum();
long serialTime = System.currentTimeMillis() - startTime;
// 并行处理
startTime = System.currentTimeMillis();
long parallelSum = bigList.parallelStream()
.filter(n -> n % 2 == 0)
.mapToLong(n -> n * n)
.sum();
long parallelTime = System.currentTimeMillis() - startTime;
System.out.printf("串行处理: 结果=%d, 耗时=%dms%n", serialSum, serialTime);
System.out.printf("并行处理: 结果=%d, 耗时=%dms%n", parallelSum, parallelTime);
System.out.printf("性能提升: %.2fx%n", (double) serialTime / parallelTime);
}
}
🧙♂️ 高级技巧:Stream API的魔法秘籍
🧠 核心技巧总结:
- flatMap扁平化:
// 处理嵌套结构
List<String> flat = nestedList.stream()
.flatMap(List::stream)
.collect(toList());
- 无限Stream:
// 斐波那契数列
Stream.iterate(new int[]{0, 1}, arr -> new int[]{arr[1], arr[0] + arr[1]})
.limit(10);
- 短路操作:
// 找到就停止
Optional<Integer> first = numbers.stream()
.filter(condition)
.findFirst();
class Person {
private String name;
private int age;
private String job;
public Person(String name, int age, String job) {
this.name = name;
this.age = age;
this.job = job;
}
// getters
public String getName() { return name; }
public int getAge() { return age; }
public String getJob() { return job; }
}
#### Stream操作详解
**中间操作(Intermediate Operations)**
```java
public class StreamOperations {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// filter - 过滤
System.out.println("偶数: " +
numbers.stream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList()));
// map - 转换
System.out.println("平方数: " +
numbers.stream()
.map(n -> n * n)
.collect(Collectors.toList()));
// flatMap - 扁平化
List<List<Integer>> nestedLists = Arrays.asList(
Arrays.asList(1, 2), Arrays.asList(3, 4), Arrays.asList(5, 6)
);
System.out.println("扁平化: " +
nestedLists.stream()
.flatMap(List::stream)
.collect(Collectors.toList()));
// sorted - 排序
System.out.println("降序: " +
numbers.stream()
.sorted(Comparator.reverseOrder())
.collect(Collectors.toList()));
// distinct - 去重
List<Integer> duplicates = Arrays.asList(1, 2, 2, 3, 3, 3, 4);
System.out.println("去重: " +
duplicates.stream()
.distinct()
.collect(Collectors.toList()));
}
}
终端操作(Terminal Operations)
public class TerminalOperations {
public static void main(String[] args) {
List<String> words = Arrays.asList("hello", "world", "java", "stream", "api");
// forEach - 遍历
System.out.println("遍历输出:");
words.stream().forEach(System.out::println);
// collect - 收集
List<String> upperCaseWords = words.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
System.out.println("大写: " + upperCaseWords);
// reduce - 归约
String concatenated = words.stream()
.reduce("", (a, b) -> a + " " + b);
System.out.println("连接: " + concatenated);
// anyMatch, allMatch, noneMatch - 匹配
boolean hasLongWord = words.stream().anyMatch(s -> s.length() > 4);
boolean allShort = words.stream().allMatch(s -> s.length() <= 5);
boolean noEmpty = words.stream().noneMatch(String::isEmpty);
System.out.println("有长单词: " + hasLongWord);
System.out.println("都短: " + allShort);
System.out.println("无空字符串: " + noEmpty);
// findFirst, findAny - 查找
Optional<String> first = words.stream().findFirst();
Optional<String> any = words.stream().findAny();
System.out.println("第一个: " + first.orElse("无"));
System.out.println("任意一个: " + any.orElse("无"));
}
}
Java 8前后的对比
对比1:集合过滤和转换
import java.util.*;
import java.util.stream.Collectors;
public class StreamComparisonExample {
public static void main(String[] args) {
List<Person> people = Arrays.asList(
new Person("Alice", 25, "Engineer"),
new Person("Bob", 30, "Manager"),
new Person("Charlie", 35, "Engineer"),
new Person("David", 28, "Designer"),
new Person("Eve", 32, "Engineer")
);
// Java 8之前:手动实现过滤和转换
System.out.println("=== Java 8之前:手动实现 ===");
List<String> engineerNamesOld = new ArrayList<>();
for (Person person : people) {
if ("Engineer".equals(person.getJob())) {
if (person.getAge() > 30) {
engineerNamesOld.add(person.getName().toUpperCase());
}
}
}
System.out.println("工程师名字(大写): " + engineerNamesOld);
// Java 8:使用Stream API
System.out.println("\n=== Java 8:Stream API ===");
List<String> engineerNamesNew = people.stream()
.filter(p -> "Engineer".equals(p.getJob()))
.filter(p -> p.getAge() > 30)
.map(Person::getName)
.map(String::toUpperCase)
.collect(Collectors.toList());
System.out.println("工程师名字(大写): " + engineerNamesNew);
}
}
对比2:数据分组统计
public class GroupingComparisonExample {
public static void main(String[] args) {
List<Person> people = Arrays.asList(
new Person("Alice", 25, "Engineer"),
new Person("Bob", 30, "Manager"),
new Person("Charlie", 35, "Engineer"),
new Person("David", 28, "Designer"),
new Person("Eve", 32, "Engineer")
);
// Java 8之前:手动实现分组
System.out.println("=== Java 8之前:手动分组 ===");
Map<String, List<Person>> groupedByJobOld = new HashMap<>();
for (Person person : people) {
String job = person.getJob();
if (!groupedByJobOld.containsKey(job)) {
groupedByJobOld.put(job, new ArrayList<>());
}
groupedByJobOld.get(job).add(person);
}
// 计算每个职业的人数
Map<String, Integer> jobCountOld = new HashMap<>();
for (Map.Entry<String, List<Person>> entry : groupedByJobOld.entrySet()) {
jobCountOld.put(entry.getKey(), entry.getValue().size());
}
System.out.println("职业统计: " + jobCountOld);
// Java 8:使用Stream API
System.out.println("\n=== Java 8:Stream API ===");
Map<String, Long> jobCountNew = people.stream()
.collect(Collectors.groupingBy(
Person::getJob,
Collectors.counting()
));
System.out.println("职业统计: " + jobCountNew);
// 更复杂的统计:按职业分组,计算平均年龄
Map<String, Double> avgAgeByJob = people.stream()
.collect(Collectors.groupingBy(
Person::getJob,
Collectors.averagingInt(Person::getAge)
));
System.out.println("职业平均年龄: " + avgAgeByJob);
}
}
对比3:并行处理
public class ParallelProcessingComparison {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// Java 8之前:手动实现并行处理
System.out.println("=== Java 8之前:手动并行 ===");
long startTime = System.currentTimeMillis();
// 创建多个线程处理
int threadCount = 4;
int chunkSize = numbers.size() / threadCount;
List<Thread> threads = new ArrayList<>();
List<Integer> results = Collections.synchronizedList(new ArrayList<>());
for (int i = 0; i < threadCount; i++) {
final int start = i * chunkSize;
final int end = (i == threadCount - 1) ? numbers.size() : (i + 1) * chunkSize;
Thread thread = new Thread(() -> {
for (int j = start; j < end; j++) {
int num = numbers.get(j);
// 模拟复杂计算
try { Thread.sleep(100); } catch (InterruptedException e) {}
results.add(num * num);
}
});
threads.add(thread);
thread.start();
}
// 等待所有线程完成
for (Thread thread : threads) {
try { thread.join(); } catch (InterruptedException e) {}
}
long endTime = System.currentTimeMillis();
System.out.println("手动并行处理时间: " + (endTime - startTime) + "ms");
System.out.println("结果数量: " + results.size());
// Java 8:使用并行流
System.out.println("\n=== Java 8:并行流 ===");
startTime = System.currentTimeMillis();
List<Integer> parallelResults = numbers.parallelStream()
.map(num -> {
try { Thread.sleep(100); } catch (InterruptedException e) {}
return num * num;
})
.collect(Collectors.toList());
endTime = System.currentTimeMillis();
System.out.println("并行流处理时间: " + (endTime - startTime) + "ms");
System.out.println("结果数量: " + parallelResults.size());
}
}
4. Optional类
4.1 是什么(What)
Optional是Java 8引入的一个容器类,用于包装可能为null的对象。它提供了一种优雅的方式来处理null值,避免NullPointerException。
核心概念:
- 容器类:包装可能为null的对象
- 类型安全:泛型支持,编译时类型检查
- 函数式风格:支持链式调用和函数组合
- 空值语义:明确表达"可能为空"的语义
4.2 为什么(Why)
解决的问题:
- 空指针异常:减少NullPointerException的发生
- 代码可读性:明确表达"可能为空"的语义
- 函数式编程:支持链式调用和函数组合
- API设计:强制开发者考虑空值情况
- 代码健壮性:提高程序的稳定性和可靠性
4.3 怎么做(How)
基本用法
import java.util.Optional;
public class OptionalExample {
public static void main(String[] args) {
// 创建Optional对象
Optional<String> empty = Optional.empty();
Optional<String> of = Optional.of("Hello");
Optional<String> ofNullable = Optional.ofNullable(null);
// 判断是否为空
System.out.println("empty.isPresent(): " + empty.isPresent());
System.out.println("of.isPresent(): " + of.isPresent());
System.out.println("ofNullable.isPresent(): " + ofNullable.isPresent());
// 获取值(不安全)
try {
String value = empty.get(); // 抛出NoSuchElementException
} catch (Exception e) {
System.out.println("获取空值异常: " + e.getMessage());
}
// 安全获取值
String safeValue = of.orElse("默认值");
String safeValue2 = ofNullable.orElseGet(() -> "计算得到的默认值");
String safeValue3 = ofNullable.orElseThrow(() -> new RuntimeException("值不存在"));
System.out.println("安全获取: " + safeValue);
System.out.println("安全获取2: " + safeValue2);
}
}
高级用法
public class OptionalAdvancedExample {
public static void main(String[] args) {
// 链式操作
Optional<String> result = Optional.of("hello world")
.filter(s -> s.length() > 5)
.map(String::toUpperCase)
.map(s -> s + "!");
System.out.println("链式操作结果: " + result.orElse("无结果"));
// 条件执行
Optional<String> name = Optional.of("Alice");
name.ifPresent(n -> System.out.println("Hello, " + n));
// 组合多个Optional
Optional<String> firstName = Optional.of("John");
Optional<String> lastName = Optional.of("Doe");
String fullName = firstName.flatMap(f ->
lastName.map(l -> f + " " + l)
).orElse("Unknown");
System.out.println("全名: " + fullName);
// 实际应用场景
User user = new User("bob@example.com");
String displayName = Optional.of(user)
.map(User::getEmail)
.map(email -> email.substring(0, email.indexOf('@')))
.map(String::toUpperCase)
.orElse("Unknown User");
System.out.println("显示名称: " + displayName);
}
}
class User {
private String email;
public User(String email) {
this.email = email;
}
public String getEmail() {
return email;
}
}
最佳实践
public class OptionalBestPractices {
public static void main(String[] args) {
// 不要这样使用Optional
Optional<String> bad = Optional.of("value");
if (bad.isPresent()) {
String value = bad.get(); // 反模式
System.out.println(value);
}
// 应该这样使用
Optional<String> good = Optional.of("value");
good.ifPresent(System.out::println);
// 避免Optional.of(null)
try {
Optional<String> bad2 = Optional.of(null); // 抛出异常
} catch (Exception e) {
System.out.println("不能使用Optional.of(null): " + e.getMessage());
}
// 使用Optional.ofNullable
Optional<String> good2 = Optional.ofNullable(null); // 安全
System.out.println("ofNullable(null) isPresent: " + good2.isPresent());
}
}
Java 8前后的对比
对比1:空值处理
public class NullHandlingComparison {
public static void main(String[] args) {
// Java 8之前:手动空值检查
System.out.println("=== Java 8之前:手动空值检查 ===");
String name = getUserName(); // 可能返回null
String displayName;
if (name != null) {
if (name.length() > 0) {
displayName = name.toUpperCase();
} else {
displayName = "Unknown";
}
} else {
displayName = "Unknown";
}
System.out.println("显示名称: " + displayName);
// Java 8:使用Optional
System.out.println("\n=== Java 8:使用Optional ===");
String displayNameNew = Optional.ofNullable(getUserName())
.filter(n -> n.length() > 0)
.map(String::toUpperCase)
.orElse("Unknown");
System.out.println("显示名称: " + displayNameNew);
}
private static String getUserName() {
// 模拟可能返回null的方法
return Math.random() > 0.5 ? "Alice" : null;
}
}
对比2:方法链式调用
public class MethodChainingComparison {
public static void main(String[] args) {
User user = getUser(); // 可能返回null
// Java 8之前:嵌套空值检查
System.out.println("=== Java 8之前:嵌套检查 ===");
String email = null;
if (user != null) {
Profile profile = user.getProfile();
if (profile != null) {
ContactInfo contactInfo = profile.getContactInfo();
if (contactInfo != null) {
email = contactInfo.getEmail();
}
}
}
String displayEmail = email != null ? email : "No email";
System.out.println("邮箱: " + displayEmail);
// Java 8:使用Optional链式调用
System.out.println("\n=== Java 8:Optional链式调用 ===");
String displayEmailNew = Optional.ofNullable(user)
.map(User::getProfile)
.map(Profile::getContactInfo)
.map(ContactInfo::getEmail)
.orElse("No email");
System.out.println("邮箱: " + displayEmailNew);
}
private static User getUser() {
// 模拟可能返回null的方法
return Math.random() > 0.5 ? new User() : null;
}
}
// 模拟类
class User {
public Profile getProfile() {
return Math.random() > 0.5 ? new Profile() : null;
}
}
class Profile {
public ContactInfo getContactInfo() {
return Math.random() > 0.5 ? new ContactInfo() : null;
}
}
class ContactInfo {
public String getEmail() {
return "user@example.com";
}
}
对比3:集合中的空值处理
import java.util.*;
public class CollectionNullHandlingComparison {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", null, "Bob", null, "Charlie");
// Java 8之前:手动过滤null值
System.out.println("=== Java 8之前:手动过滤null ===");
List<String> validNamesOld = new ArrayList<>();
for (String name : names) {
if (name != null && name.length() > 0) {
validNamesOld.add(name.toUpperCase());
}
}
System.out.println("有效名字: " + validNamesOld);
// Java 8:使用Optional和Stream
System.out.println("\n=== Java 8:Optional + Stream ===");
List<String> validNamesNew = names.stream()
.map(Optional::ofNullable)
.filter(Optional::isPresent)
.map(Optional::get)
.filter(name -> name.length() > 0)
.map(String::toUpperCase)
.collect(Collectors.toList());
System.out.println("有效名字: " + validNamesNew);
// 更简洁的写法
List<String> validNamesSimple = names.stream()
.filter(Objects::nonNull)
.filter(name -> name.length() > 0)
.map(String::toUpperCase)
.collect(Collectors.toList());
System.out.println("简化写法: " + validNamesSimple);
}
}
5. 新的日期时间API
5.1 是什么(What)
Java 8引入了全新的日期时间API(java.time包),提供了不可变、线程安全的日期时间处理类。
核心类:
- LocalDate:表示日期(年-月-日)
- LocalTime:表示时间(时:分:秒)
- LocalDateTime:表示日期时间
- ZonedDateTime:表示带时区的日期时间
- DateTimeFormatter:日期时间格式化
5.2 为什么(Why)
解决的问题:
- 可变性:Date和Calendar是可变的,线程不安全
- 设计缺陷:月份从0开始,年份从1900开始
- 时区处理复杂:缺乏统一的时区处理机制
- 格式化困难:SimpleDateFormat线程不安全
- API一致性:提供统一的日期时间处理方式
5.3 怎么做(How)
核心类介绍
import java.time.*;
import java.time.format.*;
import java.time.temporal.*;
public class NewDateTimeAPIExample {
public static void main(String[] args) {
// LocalDate - 日期
LocalDate today = LocalDate.now();
LocalDate specificDate = LocalDate.of(2024, 1, 15);
LocalDate parsedDate = LocalDate.parse("2024-01-15");
System.out.println("今天: " + today);
System.out.println("特定日期: " + specificDate);
System.out.println("解析日期: " + parsedDate);
// LocalTime - 时间
LocalTime now = LocalTime.now();
LocalTime specificTime = LocalTime.of(14, 30, 45);
LocalTime parsedTime = LocalTime.parse("14:30:45");
System.out.println("现在时间: " + now);
System.out.println("特定时间: " + specificTime);
System.out.println("解析时间: " + parsedTime);
// LocalDateTime - 日期时间
LocalDateTime dateTime = LocalDateTime.now();
LocalDateTime combined = LocalDateTime.of(specificDate, specificTime);
System.out.println("当前日期时间: " + dateTime);
System.out.println("组合日期时间: " + combined);
// ZonedDateTime - 带时区的日期时间
ZonedDateTime zonedDateTime = ZonedDateTime.now();
ZoneId tokyoZone = ZoneId.of("Asia/Tokyo");
ZonedDateTime tokyoTime = ZonedDateTime.now(tokyoZone);
System.out.println("本地时区: " + zonedDateTime);
System.out.println("东京时间: " + tokyoTime);
}
}
日期时间操作
public class DateTimeOperations {
public static void main(String[] args) {
LocalDate today = LocalDate.now();
// 日期计算
LocalDate tomorrow = today.plusDays(1);
LocalDate nextWeek = today.plusWeeks(1);
LocalDate nextMonth = today.plusMonths(1);
LocalDate nextYear = today.plusYears(1);
System.out.println("明天: " + tomorrow);
System.out.println("下周: " + nextWeek);
System.out.println("下月: " + nextMonth);
System.out.println("明年: " + nextYear);
// 日期比较
LocalDate future = LocalDate.of(2025, 12, 31);
boolean isFuture = future.isAfter(today);
boolean isPast = today.isBefore(future);
boolean isEqual = today.equals(today);
System.out.println("是未来: " + isFuture);
System.out.println("是过去: " + isPast);
System.out.println("是今天: " + isEqual);
// 日期信息获取
DayOfWeek dayOfWeek = today.getDayOfWeek();
int dayOfMonth = today.getDayOfMonth();
int dayOfYear = today.getDayOfYear();
Month month = today.getMonth();
int year = today.getYear();
System.out.println("星期: " + dayOfWeek);
System.out.println("月中第几天: " + dayOfMonth);
System.out.println("年中第几天: " + dayOfYear);
System.out.println("月份: " + month);
System.out.println("年份: " + year);
}
}
格式化与解析
public class DateTimeFormatting {
public static void main(String[] args) {
LocalDateTime now = LocalDateTime.now();
// 预定义格式
DateTimeFormatter formatter1 = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
String formatted1 = now.format(formatter1);
System.out.println("ISO格式: " + formatted1);
// 自定义格式
DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
String formatted2 = now.format(formatter2);
System.out.println("中文格式: " + formatted2);
// 解析字符串
String dateStr = "2024-01-15 14:30:00";
DateTimeFormatter formatter3 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime parsed = LocalDateTime.parse(dateStr, formatter3);
System.out.println("解析结果: " + parsed);
// 本地化格式
DateTimeFormatter formatter4 = DateTimeFormatter.ofLocalizedDateTime(
FormatStyle.MEDIUM
).withLocale(java.util.Locale.CHINA);
String localized = now.format(formatter4);
System.out.println("本地化格式: " + localized);
}
}
时区处理
public class TimeZoneHandling {
public static void main(String[] args) {
// 获取所有可用时区
Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
System.out.println("可用时区数量: " + availableZoneIds.size());
// 时区转换
LocalDateTime localDateTime = LocalDateTime.now();
ZoneId localZone = ZoneId.systemDefault();
ZoneId utcZone = ZoneId.of("UTC");
ZoneId tokyoZone = ZoneId.of("Asia/Tokyo");
ZonedDateTime localZoned = localDateTime.atZone(localZone);
ZonedDateTime utcZoned = localZoned.withZoneSameInstant(utcZone);
ZonedDateTime tokyoZoned = localZoned.withZoneSameInstant(tokyoZone);
System.out.println("本地时间: " + localZoned);
System.out.println("UTC时间: " + utcZoned);
System.out.println("东京时间: " + tokyoZoned);
// 时区偏移
ZoneOffset offset = ZoneOffset.ofHours(8);
OffsetDateTime offsetDateTime = localDateTime.atOffset(offset);
System.out.println("偏移时间: " + offsetDateTime);
}
}
Java 8前后的对比
对比1:日期创建和操作
import java.util.*;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
public class DateCreationComparison {
public static void main(String[] args) {
// Java 8之前:使用Date和Calendar
System.out.println("=== Java 8之前:Date和Calendar ===");
// 创建当前时间
Date now = new Date();
System.out.println("当前时间: " + now);
// 创建特定日期(注意:月份从0开始)
Calendar calendar = Calendar.getInstance();
calendar.set(2024, Calendar.JANUARY, 15, 14, 30, 0); // 月份从0开始!
Date specificDate = calendar.getTime();
System.out.println("特定日期: " + specificDate);
// 日期计算(加一天)
calendar.add(Calendar.DAY_OF_MONTH, 1);
Date tomorrow = calendar.getTime();
System.out.println("明天: " + tomorrow);
// 格式化日期
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
String formatted = sdf.format(tomorrow);
System.out.println("格式化后: " + formatted);
// Java 8:新的日期时间API
System.out.println("\n=== Java 8:新的日期时间API ===");
// 创建当前时间
LocalDateTime nowNew = LocalDateTime.now();
System.out.println("当前时间: " + nowNew);
// 创建特定日期(月份从1开始,更直观)
LocalDateTime specificDateNew = LocalDateTime.of(2024, 1, 15, 14, 30, 0);
System.out.println("特定日期: " + specificDateNew);
// 日期计算(加一天)
LocalDateTime tomorrowNew = specificDateNew.plusDays(1);
System.out.println("明天: " + tomorrowNew);
// 格式化日期
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
String formattedNew = tomorrowNew.format(formatter);
System.out.println("格式化后: " + formattedNew);
}
}
对比2:时区处理
public class TimeZoneComparison {
public static void main(String[] args) {
// Java 8之前:时区处理复杂
System.out.println("=== Java 8之前:复杂时区处理 ===");
Calendar calendar = Calendar.getInstance();
TimeZone localZone = TimeZone.getDefault();
TimeZone tokyoZone = TimeZone.getTimeZone("Asia/Tokyo");
// 设置时区
calendar.setTimeZone(tokyoZone);
Date tokyoTime = calendar.getTime();
// 转换时区
calendar.setTimeZone(localZone);
Date localTime = calendar.getTime();
System.out.println("东京时间: " + tokyoTime);
System.out.println("本地时间: " + localTime);
// 获取时区偏移
int offset = tokyoZone.getOffset(System.currentTimeMillis());
int hours = offset / (1000 * 60 * 60);
System.out.println("东京时区偏移: " + hours + "小时");
// Java 8:简洁的时区处理
System.out.println("\n=== Java 8:简洁时区处理 ===");
LocalDateTime localDateTime = LocalDateTime.now();
ZoneId localZoneId = ZoneId.systemDefault();
ZoneId tokyoZoneId = ZoneId.of("Asia/Tokyo");
ZonedDateTime localZoned = localDateTime.atZone(localZoneId);
ZonedDateTime tokyoZoned = localDateTime.atZone(tokyoZoneId);
System.out.println("本地时区时间: " + localZoned);
System.out.println("东京时区时间: " + tokyoZoned);
// 时区转换
ZonedDateTime converted = localZoned.withZoneSameInstant(tokyoZoneId);
System.out.println("转换到东京时区: " + converted);
// 获取时区偏移
ZoneOffset offsetNew = tokyoZoned.getOffset();
System.out.println("东京时区偏移: " + offsetNew.getTotalSeconds() / 3600 + "小时");
}
}
对比3:日期解析和验证
public class DateParsingComparison {
public static void main(String[] args) {
String dateStr = "2024-01-15";
// Java 8之前:使用SimpleDateFormat(线程不安全)
System.out.println("=== Java 8之前:SimpleDateFormat ===");
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date parsedDate = sdf.parse(dateStr);
System.out.println("解析结果: " + parsedDate);
// 验证日期(需要额外检查)
Calendar cal = Calendar.getInstance();
cal.setTime(parsedDate);
cal.setLenient(false); // 严格模式
cal.getTime(); // 会抛出异常如果日期无效
} catch (Exception e) {
System.out.println("解析异常: " + e.getMessage());
}
// Java 8:使用DateTimeFormatter(线程安全)
System.out.println("\n=== Java 8:DateTimeFormatter ===");
try {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDate parsedDateNew = LocalDate.parse(dateStr, formatter);
System.out.println("解析结果: " + parsedDateNew);
// 验证日期(自动验证)
LocalDate validDate = LocalDate.of(2024, 1, 15);
System.out.println("有效日期: " + validDate);
// 无效日期会抛出异常
try {
LocalDate invalidDate = LocalDate.of(2024, 2, 30); // 2月没有30号
System.out.println("无效日期: " + invalidDate);
} catch (Exception e) {
System.out.println("无效日期异常: " + e.getMessage());
}
} catch (Exception e) {
System.out.println("解析异常: " + e.getMessage());
}
}
}
// Java 8:接口默认方法
interface EnhancedCollection<T> extends Collection<T> {
default void forEach(Consumer<? super T> action) {
for (T item : this) {
action.accept(item);
}
}
default boolean removeIf(Predicate<? super T> filter) {
boolean removed = false;
Iterator<T> iterator = iterator();
while (iterator.hasNext()) {
if (filter.test(iterator.next())) {
iterator.remove();
removed = true;
}
}
return removed;
}
}
public class InterfaceEvolutionComparison {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// Java 8之前:使用工具类
System.out.println("=== Java 8之前:工具类 ===");
CollectionUtils.forEach(names, name -> System.out.println("Hello, " + name));
// Java 8:直接使用接口默认方法
System.out.println("\n=== Java 8:接口默认方法 ===");
names.forEach(name -> System.out.println("Hello, " + name));
// 更自然的使用方式
List<String> mutableNames = new ArrayList<>(names);
mutableNames.removeIf(name -> name.startsWith("A"));
System.out.println("移除A开头的名字: " + mutableNames);
}
}
对比3:多重继承支持
// Java 8之前:无法实现多重继承
interface Flyable {
void fly();
}
interface Swimmable {
void swim();
}
// 必须选择实现其中一个,或者创建组合类
class Bird implements Flyable {
@Override
public void fly() {
System.out.println("鸟儿飞翔");
}
}
class Fish implements Swimmable {
@Override
public void swim() {
System.out.println("鱼儿游泳");
}
}
// Java 8:通过默认方法实现有限的多重继承
interface FlyableNew {
default void fly() {
System.out.println("飞翔");
}
}
interface SwimmableNew {
default void swim() {
System.out.println("游泳");
}
}
// 一个类可以实现多个接口,获得默认行为
class Duck implements FlyableNew, SwimmableNew {
// 不需要实现任何方法,直接获得默认行为
// 也可以重写默认方法
@Override
public void fly() {
System.out.println("鸭子飞翔");
}
}
public class MultipleInheritanceComparison {
public static void main(String[] args) {
// Java 8之前:需要分别创建对象
Bird bird = new Bird();
Fish fish = new Fish();
bird.fly();
fish.swim();
// Java 8:一个对象具有多种能力
System.out.println("\n=== Java 8:多重继承 ===");
Duck duck = new Duck();
duck.fly();
duck.swim();
}
}
6. 接口默认方法
6.1 是什么(What)
接口默认方法是Java 8引入的特性,允许在接口中定义具有默认实现的方法。这使得接口可以包含具体的方法实现,而不仅仅是抽象方法声明。
核心概念:
- 默认实现:接口可以包含具体方法实现
- 向后兼容:可以在不破坏现有实现的情况下添加新方法
- 多重继承:提供有限的多重继承机制
- 接口演化:支持接口的渐进式改进
6.2 为什么(Why)
解决的问题:
- 接口演化:可以在不破坏现有实现的情况下向接口添加新方法
- 向后兼容性:新方法有默认实现,现有代码无需修改
- 多重继承:提供了一种有限的多重继承机制
- API设计:可以定义通用的默认行为
- 代码复用:避免重复实现相同的功能
6.3 怎么做(How)
基本语法
public interface DefaultMethodExample {
// 抽象方法
void abstractMethod();
// 默认方法
default void defaultMethod() {
System.out.println("这是默认方法实现");
}
// 静态方法
static void staticMethod() {
System.out.println("这是静态方法");
}
}
class Implementation implements DefaultMethodExample {
@Override
public void abstractMethod() {
System.out.println("实现抽象方法");
}
// 可以选择重写默认方法,也可以使用默认实现
@Override
public void defaultMethod() {
System.out.println("重写默认方法");
}
}
实际应用示例
import java.util.*;
public class DefaultMethodPracticalExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// 使用List接口的默认方法
names.forEach(System.out::println);
// 使用Collection接口的默认方法
names.removeIf(name -> name.startsWith("A"));
System.out.println("移除A开头的名字后: " + names);
// 使用Iterable接口的默认方法
names.spliterator().forEachRemaining(System.out::println);
}
}
// 自定义接口示例
interface Logger {
void log(String message);
default void logError(String message) {
log("ERROR: " + message);
}
default void logInfo(String message) {
log("INFO: " + message);
}
default void logWarning(String message) {
log("WARNING: " + message);
}
}
class ConsoleLogger implements Logger {
@Override
public void log(String message) {
System.out.println(message);
}
}
class FileLogger implements Logger {
@Override
public void log(String message) {
// 写入文件的实现
System.out.println("写入文件: " + message);
}
// 可以选择重写默认方法
@Override
public void logError(String message) {
log("严重错误: " + message);
}
}
多重继承冲突解决
interface A {
default void method() {
System.out.println("A的默认方法");
}
}
interface B {
default void method() {
System.out.println("B的默认方法");
}
}
// 必须明确指定使用哪个接口的默认方法
class C implements A, B {
@Override
public void method() {
// 调用A的默认方法
A.super.method();
// 或者调用B的默认方法
// B.super.method();
// 或者提供自己的实现
System.out.println("C的实现");
}
}
Java 8前后的对比
对比1:接口演化
// Java 8之前:接口无法添加新方法
interface OldLogger {
void log(String message);
// 如果要添加新方法,会破坏所有现有实现
// void logError(String message); // 这会导致编译错误
}
class OldLoggerImpl implements OldLogger {
@Override
public void log(String message) {
System.out.println(message);
}
// 必须实现所有接口方法
}
// Java 8:接口可以添加默认方法
interface NewLogger {
void log(String message);
// 可以添加新方法而不破坏现有实现
default void logError(String message) {
log("ERROR: " + message);
}
default void logInfo(String message) {
log("INFO: " + message);
}
}
class NewLoggerImpl implements NewLogger {
@Override
public void log(String message) {
System.out.println(message);
}
// 不需要实现默认方法,可以直接使用
}
对比2:工具方法集成
import java.util.*;
// Java 8之前:工具类模式
class CollectionUtils {
public static <T> void forEach(Collection<T> collection, Consumer<T> action) {
for (T item : collection) {
action.accept(item);
}
}
public static <T> boolean removeIf(Collection<T> collection, Predicate<T> filter) {
boolean removed = false;
Iterator<T> iterator = collection.iterator();
while (iterator.hasNext()) {
if (filter.test(iterator.next())) {
iterator.remove();
removed = true;
}
}
return removed;
}
}
// Java 8:接口默认方法
interface EnhancedCollection<T> extends Collection<T> {
default void forEach(Consumer<? super T> action) {
for (T item : this) {
action.accept(item);
}
}
default boolean removeIf(Predicate<? super T> filter) {
boolean removed = false;
Iterator<T> iterator = iterator();
while (iterator.hasNext()) {
if (filter.test(iterator.next())) {
iterator.remove();
removed = true;
}
}
return removed;
}
}
public class InterfaceEvolutionComparison {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// Java 8之前:使用工具类
System.out.println("=== Java 8之前:工具类 ===");
CollectionUtils.forEach(names, name -> System.out.println("Hello, " + name));
// Java 8:直接使用接口默认方法
System.out.println("\n=== Java 8:接口默认方法 ===");
names.forEach(name -> System.out.println("Hello, " + name));
// 更自然的使用方式
List<String> mutableNames = new ArrayList<>(names);
mutableNames.removeIf(name -> name.startsWith("A"));
System.out.println("移除A开头的名字: " + mutableNames);
}
}
本质改变:
- 接口演化:可以在不破坏现有实现的情况下向接口添加新方法
- 向后兼容性:新方法有默认实现,现有代码无需修改
- 多重继承:提供了一种有限的多重继承机制
- API设计:可以定义通用的默认行为
7. 方法引用
7.1 是什么(What)
方法引用是Lambda表达式的一种简化写法,它允许直接引用已有的方法。当Lambda表达式只是调用一个已存在的方法时,可以使用方法引用来简化代码。
核心概念:
- 方法引用:直接引用已有方法的语法糖
- 类型推断:编译器自动推断方法引用类型
- 性能优化:比Lambda表达式更高效
- 代码简洁:减少样板代码
7.2 为什么(Why)
解决的问题:
- 代码简洁性:避免编写简单的Lambda表达式
- 可读性提升:方法引用比Lambda表达式更直观
- 性能优化:编译器可以更好地优化方法引用
- 代码复用:直接引用现有的方法
- 类型安全:编译时类型检查
7.3 怎么做(How)
方法引用类型
import java.util.*;
import java.util.function.*;
public class MethodReferenceExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// 1. 静态方法引用
names.forEach(System.out::println);
// 2. 实例方法引用(特定对象)
String prefix = "Hello, ";
names.forEach(prefix::concat);
// 3. 实例方法引用(任意对象)
names.forEach(String::toUpperCase);
// 4. 构造方法引用
List<String> upperNames = names.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
// 5. 数组构造方法引用
Function<Integer, String[]> arrayCreator = String[]::new;
String[] array = arrayCreator.apply(5);
}
}
详细示例
public class MethodReferenceDetailedExample {
public static void main(String[] args) {
// 静态方法引用
Function<String, Integer> parseInt = Integer::parseInt;
System.out.println("解析数字: " + parseInt.apply("123"));
// 实例方法引用(特定对象)
String prefix = "User: ";
Function<String, String> addPrefix = prefix::concat;
System.out.println("添加前缀: " + addPrefix.apply("Alice"));
// 实例方法引用(任意对象)
Function<String, String> toUpper = String::toUpperCase;
System.out.println("转大写: " + toUpper.apply("hello"));
// 构造方法引用
Supplier<StringBuilder> sbCreator = StringBuilder::new;
StringBuilder sb = sbCreator.get();
sb.append("Hello");
System.out.println("StringBuilder: " + sb);
// 数组构造方法引用
IntFunction<int[]> arrayCreator = int[]::new;
int[] numbers = arrayCreator.apply(5);
System.out.println("数组长度: " + numbers.length);
}
}
Java 8前后的对比
对比1:Lambda表达式 vs 方法引用
import java.util.*;
import java.util.function.*;
public class LambdaVsMethodReferenceComparison {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// Java 8:Lambda表达式
System.out.println("=== Lambda表达式 ===");
names.forEach(name -> System.out.println(name));
names.stream()
.map(name -> name.toUpperCase())
.forEach(name -> System.out.println(name));
// Java 8:方法引用(更简洁)
System.out.println("\n=== 方法引用 ===");
names.forEach(System.out::println);
names.stream()
.map(String::toUpperCase)
.forEach(System.out::println);
// 对比:构造方法
System.out.println("\n=== 构造方法对比 ===");
// Lambda方式
Supplier<StringBuilder> sbLambda = () -> new StringBuilder();
// 方法引用方式
Supplier<StringBuilder> sbMethodRef = StringBuilder::new;
System.out.println("Lambda创建: " + sbLambda.get());
System.out.println("方法引用创建: " + sbMethodRef.get());
}
}
对比2:传统匿名内部类 vs 方法引用
public class AnonymousVsMethodReferenceComparison {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// Java 8之前:匿名内部类
System.out.println("=== Java 8之前:匿名内部类 ===");
names.forEach(new Consumer<String>() {
@Override
public void accept(String name) {
System.out.println("Hello, " + name);
}
});
// Java 8:Lambda表达式
System.out.println("\n=== Java 8:Lambda表达式 ===");
names.forEach(name -> System.out.println("Hello, " + name));
// Java 8:方法引用(最简洁)
System.out.println("\n=== Java 8:方法引用 ===");
names.forEach(name -> System.out.println("Hello, " + name));
// 自定义方法引用
names.forEach(this::greet);
}
private void greet(String name) {
System.out.println("Greetings, " + name);
}
}
对比3:函数式接口实现
public class FunctionalInterfaceComparison {
public static void main(String[] args) {
// Java 8之前:需要创建完整的实现类
System.out.println("=== Java 8之前:完整实现类 ===");
Comparator<String> oldComparator = new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.compareTo(s2);
}
};
List<String> names = Arrays.asList("Charlie", "Alice", "Bob");
names.sort(oldComparator);
System.out.println("排序结果: " + names);
// Java 8:Lambda表达式
System.out.println("\n=== Java 8:Lambda表达式 ===");
List<String> names2 = Arrays.asList("Charlie", "Alice", "Bob");
names2.sort((s1, s2) -> s1.compareTo(s2));
System.out.println("排序结果: " + names2);
// Java 8:方法引用(最简洁)
System.out.println("\n=== Java 8:方法引用 ===");
List<String> names3 = Arrays.asList("Charlie", "Alice", "Bob");
names3.sort(String::compareTo);
System.out.println("排序结果: " + names3);
// 性能对比
System.out.println("\n=== 性能对比 ===");
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
names.sort(oldComparator);
}
long endTime = System.currentTimeMillis();
System.out.println("匿名内部类耗时: " + (endTime - startTime) + "ms");
startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
names2.sort((s1, s2) -> s1.compareTo(s2));
}
endTime = System.currentTimeMillis();
System.out.println("Lambda表达式耗时: " + (endTime - startTime) + "ms");
startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
names3.sort(String::compareTo);
}
endTime = System.currentTimeMillis();
System.out.println("方法引用耗时: " + (endTime - startTime) + "ms");
}
}
// 自定义类的方法引用示例
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() { return name; }
public int getAge() { return age; }
public static int compareByAge(Person a, Person b) {
return Integer.compare(a.age, b.age);
}
public static Person create(String name, int age) {
return new Person(name, age);
}
@Override
public String toString() {
return name + "(" + age + ")";
}
}
class MethodReferenceCustomExample {
public static void main(String[] args) {
List<Person> people = Arrays.asList(
new Person("Alice", 25),
new Person("Bob", 30),
new Person("Charlie", 20)
);
// 静态方法引用
people.sort(Person::compareByAge);
System.out.println("按年龄排序: " + people);
// 构造方法引用
BiFunction<String, Integer, Person> personCreator = Person::new;
Person newPerson = personCreator.apply("David", 35);
System.out.println("新创建的人: " + newPerson);
// 实例方法引用
Function<Person, String> getName = Person::getName;
people.stream()
.map(getName)
.forEach(System.out::println);
}
}
8. CompletableFuture
8.1 是什么(What)
CompletableFuture是Java 8引入的一个异步编程工具,它实现了Future接口,并提供了更强大的异步编程能力。它支持异步任务的组合、异常处理、超时控制等高级功能。
核心概念:
- 异步执行:支持异步任务的创建和执行
- 任务组合:可以组合多个异步任务
- 异常处理:内置异常处理机制
- 回调机制:支持完成后的回调处理
- 线程池集成:与ExecutorService无缝集成
8.2 为什么(Why)
解决的问题:
- 异步编程复杂性:简化异步任务的编写和管理
- 任务组合困难:传统Future难以组合多个异步任务
- 异常处理复杂:异步任务的异常处理更加困难
- 回调地狱:避免嵌套回调导致的代码可读性问题
- 性能提升:支持并行执行和任务组合
8.3 怎么做(How)
基本用法
import java.util.concurrent.*;
import java.util.function.*;
public class CompletableFutureBasicExample {
public static void main(String[] args) throws Exception {
// 创建异步任务
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1000);
return "异步任务完成";
} catch (InterruptedException e) {
return "任务被中断";
}
});
// 等待结果
String result = future.get();
System.out.println("结果: " + result);
// 异步处理结果
CompletableFuture<String> processed = future.thenApply(str -> str + " - 已处理");
System.out.println("处理后的结果: " + processed.get());
// 异步消费结果
CompletableFuture<Void> consumed = future.thenAccept(str ->
System.out.println("消费结果: " + str)
);
consumed.get(); // 等待消费完成
}
}
高级用法
public class CompletableFutureAdvancedExample {
public static void main(String[] args) throws Exception {
// 任务组合
CompletableFuture<String> task1 = CompletableFuture.supplyAsync(() -> "任务1");
CompletableFuture<String> task2 = CompletableFuture.supplyAsync(() -> "任务2");
CompletableFuture<String> task3 = CompletableFuture.supplyAsync(() -> "任务3");
// 等待所有任务完成
CompletableFuture<Void> allTasks = CompletableFuture.allOf(task1, task2, task3);
allTasks.get();
System.out.println("所有任务完成: " + task1.get() + ", " + task2.get() + ", " + task3.get());
// 等待任一任务完成
CompletableFuture<Object> anyTask = CompletableFuture.anyOf(task1, task2, task3);
System.out.println("任一任务完成: " + anyTask.get());
// 异常处理
CompletableFuture<String> errorTask = CompletableFuture.supplyAsync(() -> {
if (true) throw new RuntimeException("模拟异常");
return "成功";
}).exceptionally(throwable -> "异常处理: " + throwable.getMessage());
System.out.println("异常处理结果: " + errorTask.get());
// 超时控制
CompletableFuture<String> timeoutTask = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(3000);
return "长时间任务";
} catch (InterruptedException e) {
return "被中断";
}
}).orTimeout(2, TimeUnit.SECONDS)
.exceptionally(throwable -> "超时: " + throwable.getMessage());
System.out.println("超时控制结果: " + timeoutTask.get());
}
}
实际应用场景
public class CompletableFuturePracticalExample {
public static void main(String[] args) throws Exception {
// 模拟用户服务
CompletableFuture<String> userInfo = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(100);
return "用户信息";
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
// 模拟订单服务
CompletableFuture<String> orderInfo = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(150);
return "订单信息";
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
// 模拟商品服务
CompletableFuture<String> productInfo = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(200);
return "商品信息";
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
// 组合所有服务结果
CompletableFuture<String> combinedResult = userInfo
.thenCombine(orderInfo, (user, order) -> user + " + " + order)
.thenCombine(productInfo, (combined, product) -> combined + " + " + product);
System.out.println("组合结果: " + combinedResult.get());
// 异步处理结果
CompletableFuture<String> processedResult = combinedResult
.thenApplyAsync(result -> "处理后的: " + result)
.thenApplyAsync(result -> result + " - 完成");
System.out.println("最终结果: " + processedResult.get());
}
}
Java 8前后的对比
对比1:异步任务创建
import java.util.concurrent.*;
import java.util.function.*;
public class AsyncTaskCreationComparison {
public static void main(String[] args) throws Exception {
// Java 8之前:使用ExecutorService和Future
System.out.println("=== Java 8之前:ExecutorService + Future ===");
ExecutorService executor = Executors.newFixedThreadPool(2);
Future<String> future1 = executor.submit(new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(1000);
return "任务1完成";
}
});
Future<String> future2 = executor.submit(new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(1500);
return "任务2完成";
}
});
// 等待结果
String result1 = future1.get();
String result2 = future2.get();
System.out.println("结果1: " + result1);
System.out.println("结果2: " + result2);
executor.shutdown();
// Java 8:使用CompletableFuture
System.out.println("\n=== Java 8:CompletableFuture ===");
CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1000);
return "任务1完成";
} catch (InterruptedException e) {
return "任务1被中断";
}
});
CompletableFuture<String> cf2 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1500);
return "任务2完成";
} catch (InterruptedException e) {
return "任务2被中断";
}
});
// 等待结果
String cfResult1 = cf1.get();
String cfResult2 = cf2.get();
System.out.println("结果1: " + cfResult1);
System.out.println("结果2: " + cfResult2);
}
}
对比2:任务组合
public class TaskCombinationComparison {
public static void main(String[] args) throws Exception {
// Java 8之前:手动组合任务
System.out.println("=== Java 8之前:手动组合 ===");
ExecutorService executor = Executors.newFixedThreadPool(3);
// 创建三个任务
Future<String> task1 = executor.submit(() -> {
Thread.sleep(100);
return "用户信息";
});
Future<String> task2 = executor.submit(() -> {
Thread.sleep(150);
return "订单信息";
});
Future<String> task3 = executor.submit(() -> {
Thread.sleep(200);
return "商品信息";
});
// 手动等待所有任务完成
String result1 = task1.get();
String result2 = task2.get();
String result3 = task3.get();
// 手动组合结果
String combined = result1 + " + " + result2 + " + " + result3;
System.out.println("组合结果: " + combined);
executor.shutdown();
// Java 8:使用CompletableFuture组合
System.out.println("\n=== Java 8:CompletableFuture组合 ===");
CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(100);
return "用户信息";
} catch (InterruptedException e) {
return "用户信息获取失败";
}
});
CompletableFuture<String> cf2 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(150);
return "订单信息";
} catch (InterruptedException e) {
return "订单信息获取失败";
}
});
CompletableFuture<String> cf3 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(200);
return "商品信息";
} catch (InterruptedException e) {
return "商品信息获取失败";
}
});
// 自动组合所有任务
CompletableFuture<String> combinedCF = CompletableFuture.allOf(cf1, cf2, cf3)
.thenApply(v -> {
try {
return cf1.get() + " + " + cf2.get() + " + " + cf3.get();
} catch (Exception e) {
return "组合失败";
}
});
System.out.println("组合结果: " + combinedCF.get());
}
}
对比3:异常处理
public class ExceptionHandlingComparison {
public static void main(String[] args) throws Exception {
// Java 8之前:手动异常处理
System.out.println("=== Java 8之前:手动异常处理 ===");
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(new Callable<String>() {
@Override
public String call() throws Exception {
if (Math.random() > 0.5) {
throw new RuntimeException("模拟异常");
}
return "成功";
}
});
try {
String result = future.get();
System.out.println("结果: " + result);
} catch (ExecutionException e) {
System.out.println("异常: " + e.getCause().getMessage());
}
executor.shutdown();
// Java 8:使用CompletableFuture异常处理
System.out.println("\n=== Java 8:CompletableFuture异常处理 ===");
CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
if (Math.random() > 0.5) {
throw new RuntimeException("模拟异常");
}
return "成功";
}).exceptionally(throwable -> "异常处理: " + throwable.getMessage());
String cfResult = cf.get();
System.out.println("结果: " + cfResult);
// 更高级的异常处理
CompletableFuture<String> cfAdvanced = CompletableFuture.supplyAsync(() -> {
if (Math.random() > 0.5) {
throw new RuntimeException("模拟异常");
}
return "成功";
}).handle((result, throwable) -> {
if (throwable != null) {
return "异常处理: " + throwable.getMessage();
}
return "处理结果: " + result;
});
String cfAdvancedResult = cfAdvanced.get();
System.out.println("高级处理结果: " + cfAdvancedResult);
}
}
9. Nashorn JavaScript引擎
9.1 是什么(What)
Nashorn是Java 8引入的JavaScript引擎,它完全用Java编写,运行在JVM上。它允许在Java应用程序中执行JavaScript代码,提供了Java和JavaScript之间的互操作性。
核心概念:
- JavaScript引擎:在JVM上执行JavaScript代码
- Java集成:Java和JavaScript之间的双向调用
- 性能优化:比Rhino引擎性能更好
- 标准支持:支持ECMAScript 5.1标准
9.2 为什么(Why)
解决的问题:
- 脚本集成:在Java应用中集成JavaScript脚本
- 动态配置:支持运行时配置和规则引擎
- 插件系统:为Java应用提供插件扩展能力
- 原型开发:快速原型开发和测试
- 跨语言互操作:Java和JavaScript的互操作性
9.3 怎么做(How)
基本用法
import javax.script.*;
import java.io.*;
public class NashornExample {
public static void main(String[] args) throws Exception {
// 创建脚本引擎
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("nashorn");
// 执行简单JavaScript代码
Object result = engine.eval("var x = 10; var y = 20; x + y;");
System.out.println("JavaScript计算结果: " + result);
// 执行JavaScript函数
engine.eval("function add(a, b) { return a + b; }");
Invocable invocable = (Invocable) engine;
Object sum = invocable.invokeFunction("add", 15, 25);
System.out.println("函数调用结果: " + sum);
// 从文件加载JavaScript
try (Reader reader = new FileReader("script.js")) {
engine.eval(reader);
} catch (FileNotFoundException e) {
System.out.println("脚本文件未找到,使用内联脚本");
engine.eval("function greet(name) { return 'Hello, ' + name + '!'; }");
}
Object greeting = invocable.invokeFunction("greet", "World");
System.out.println("问候语: " + greeting);
}
}
Java与JavaScript互操作
public class JavaJavaScriptInterop {
public static void main(String[] args) throws Exception {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("nashorn");
// 将Java对象传递给JavaScript
engine.put("javaList", Arrays.asList("Java", "JavaScript", "Python"));
engine.eval("var jsArray = javaList.toArray();");
engine.eval("for (var i = 0; i < jsArray.length; i++) { print(jsArray[i]); }");
// 从JavaScript调用Java方法
engine.eval("var javaSystem = Java.type('java.lang.System');");
engine.eval("javaSystem.out.println('从JavaScript调用Java方法');");
// 创建Java对象
engine.eval("var date = new java.util.Date();");
engine.eval("print('当前时间: ' + date);");
// 使用Java集合
engine.eval("var map = new java.util.HashMap();");
engine.eval("map.put('key1', 'value1');");
engine.eval("map.put('key2', 'value2');");
engine.eval("print('Map大小: ' + map.size());");
}
}
Java 8前后的对比
对比1:脚本执行方式
import javax.script.*;
import java.io.*;
public class ScriptExecutionComparison {
public static void main(String[] args) throws Exception {
// Java 8之前:使用Rhino引擎(需要单独引入)
System.out.println("=== Java 8之前:Rhino引擎 ===");
try {
// 注意:Rhino引擎在Java 8之前需要单独引入
// ScriptEngineManager manager = new ScriptEngineManager();
// ScriptEngine engine = manager.getEngineByName("rhino");
System.out.println("Rhino引擎需要单独引入,配置复杂");
} catch (Exception e) {
System.out.println("Rhino引擎不可用: " + e.getMessage());
}
// Java 8:内置Nashorn引擎
System.out.println("\n=== Java 8:内置Nashorn引擎 ===");
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("nashorn");
if (engine != null) {
System.out.println("Nashorn引擎可用");
// 执行简单JavaScript
Object result = engine.eval("var x = 10; var y = 20; x + y;");
System.out.println("JavaScript计算结果: " + result);
} else {
System.out.println("Nashorn引擎不可用");
}
}
}
对比2:性能对比
public class PerformanceComparison {
public static void main(String[] args) throws Exception {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("nashorn");
if (engine == null) {
System.out.println("Nashorn引擎不可用");
return;
}
// 测试JavaScript执行性能
System.out.println("=== JavaScript执行性能测试 ===");
// 简单计算
long startTime = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
engine.eval("var x = " + i + "; var y = " + (i * 2) + "; x + y;");
}
long endTime = System.currentTimeMillis();
System.out.println("简单计算耗时: " + (endTime - startTime) + "ms");
// 函数调用
engine.eval("function add(a, b) { return a + b; }");
startTime = System.currentTimeMillis();
Invocable invocable = (Invocable) engine;
for (int i = 0; i < 10000; i++) {
invocable.invokeFunction("add", i, i * 2);
}
endTime = System.currentTimeMillis();
System.out.println("函数调用耗时: " + (endTime - startTime) + "ms");
// 对比Java原生性能
System.out.println("\n=== Java原生性能对比 ===");
startTime = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
int x = i;
int y = i * 2;
int result = x + y;
}
endTime = System.currentTimeMillis();
System.out.println("Java原生计算耗时: " + (endTime - startTime) + "ms");
}
}
对比3:集成复杂度
public class IntegrationComplexityComparison {
public static void main(String[] args) throws Exception {
// Java 8之前:复杂的脚本集成
System.out.println("=== Java 8之前:复杂集成 ===");
System.out.println("1. 需要单独引入脚本引擎依赖");
System.out.println("2. 需要配置类路径和依赖");
System.out.println("3. 版本兼容性问题");
System.out.println("4. 性能优化困难");
System.out.println("5. 调试和错误处理复杂");
// Java 8:内置集成
System.out.println("\n=== Java 8:内置集成 ===");
System.out.println("1. 内置Nashorn引擎,无需额外依赖");
System.out.println("2. 与JDK版本完全兼容");
System.out.println("3. 性能经过优化");
System.out.println("4. 错误处理更加友好");
System.out.println("5. 调试支持更好");
// 实际演示
try {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("nashorn");
if (engine != null) {
System.out.println("\n=== 实际集成演示 ===");
// 执行配置脚本
engine.eval("var config = { timeout: 5000, retries: 3 };");
engine.eval("print('配置加载成功: ' + JSON.stringify(config));");
// 动态配置Java对象
engine.put("javaSystem", System.class);
engine.eval("javaSystem.out.println('从JavaScript调用Java成功');");
System.out.println("集成成功!");
}
} catch (Exception e) {
System.out.println("集成失败: " + e.getMessage());
}
}
}
10. 总结与最佳实践
10.1 是什么(What)
Java 8的发布标志着Java语言的一个重要转折点,从纯面向对象语言转向支持函数式编程的混合范式。
核心价值:
- 函数式编程:支持Lambda表达式和函数式接口
- 流式处理:Stream API提供声明式数据处理
- 异步编程:CompletableFuture简化异步任务
- 空值安全:Optional类提供空值处理
- 现代日期时间:新的日期时间API
- 代码简洁性:大幅减少样板代码,提高开发效率
10.2 为什么(Why)
解决的问题:
- 编程范式转变:从纯面向对象转向函数式编程
- 代码质量提升:减少样板代码,提高可读性
- 性能优化:新的API设计带来更好的性能
- 开发效率:简化常见编程任务
- 现代化:跟上编程语言发展趋势
10.3 怎么做(How)
最佳实践建议
Lambda表达式使用建议
// 好的实践
names.stream()
.filter(name -> name.length() > 3)
.map(String::toUpperCase)
.forEach(System.out::println);
// 避免过度复杂的Lambda
names.stream()
.filter(name -> {
// 避免在Lambda中写复杂逻辑
if (name == null) return false;
if (name.length() < 2) return false;
return name.matches("[a-zA-Z]+");
})
.forEach(System.out::println);
Stream API使用建议
// 优先使用Stream API
List<String> result = names.stream()
.filter(name -> name.startsWith("A"))
.collect(Collectors.toList());
// 避免过度使用Stream
// 简单循环用传统for循环更清晰
for (String name : names) {
if (name.startsWith("A")) {
System.out.println(name);
}
}
Optional使用建议
// 好的实践
Optional.ofNullable(user)
.map(User::getName)
.orElse("Unknown");
// 避免反模式
Optional<String> name = Optional.of("value");
if (name.isPresent()) {
String value = name.get(); // 反模式
}
性能考虑
- Stream vs 传统循环:简单操作用传统循环,复杂操作用Stream
- 并行流使用:数据量大且操作独立时使用并行流
- 方法引用:优先使用方法引用而不是Lambda表达式
- 延迟执行:Stream的中间操作不会立即执行,注意性能影响
迁移策略
- 渐进式迁移:逐步将现有代码迁移到Java 8特性
- 团队培训:确保团队成员熟悉新特性的使用
- 代码审查:在代码审查中关注新特性的正确使用
- 性能测试:迁移后进行性能测试,确保性能提升
未来展望
Java 8的成功为后续版本奠定了基础:
- Java 9:模块系统、REPL工具
- Java 10:局部变量类型推断
- Java 11:长期支持版本
- Java 17:下一个长期支持版本
结语
Java 8的发布是Java发展史上的一个重要里程碑,它引入了许多革命性的特性,彻底改变了Java的编程范式。通过Lambda表达式、Stream API、Optional类等新特性,Java变得更加现代化、高效和易用。
掌握这些特性不仅能够提高开发效率,还能写出更加优雅、可维护的代码。希望本文能够帮助您深入理解Java 8的核心特性,并在实际项目中灵活运用。
📚 参考文档与扩展阅读
官方文档
-
Oracle Java 8 官方文档
-
Oracle Java Tutorials
技术规范 (JSR)
- JSR 335: Lambda Expressions for the Java Programming Language
- JSR 310: Date and Time API
- JSR 223: Scripting for the Java Platform
权威书籍
- 《Java 8 in Action》 - Raoul-Gabriel Urma, Mario Fusco, Alan Mycroft
- 《Modern Java in Action》 - Raoul-Gabriel Urma, Mario Fusco, Alan Mycroft
- 《Effective Java (Third Edition)》 - Joshua Bloch
- 《Java: The Complete Reference (Eleventh Edition)》 - Herbert Schildt
- 《Java 8函数式编程》 - Richard Warburton
在线教程与博客
-
Baeldung Java 8 系列
-
Oracle官方博客
实践项目与示例
性能与最佳实践
-
性能分析文章
- “Java 8 Stream Performance” - Vladimir Gitlevich
- “Lambda Expression Performance” - Sergey Kuksenko
- “Java 8 Parallel Streams Performance” - Michael Vorburger
-
最佳实践指南