Java 8-17核心特性全景解析之Java8
版本演进时间轴
版本 | 发布日期 | 代号 | 重大特性 | 主要应用场景 |
---|---|---|---|---|
Java 8 (LTS) | 2014年3月 | - | Lambda表达式、Stream API、新日期时间API | 函数式编程、集合处理优化、时间处理标准化 |
Java 9 | 2017年9月 | - | 模块系统(Jigsaw)、JShell、集合工厂方法 | 应用模块化、交互式开发、代码简化 |
Java 10 | 2018年3月 | - | 局部变量类型推断(var)、G1并行Full GC | 代码简化、GC性能提升 |
Java 11 (LTS) | 2018年9月 | - | HTTP Client API、String新方法、ZGC | 现代HTTP通信、字符串处理增强、低延迟GC |
Java 12 | 2019年3月 | - | Switch表达式(预览)、Shenandoah GC | 代码简化、低延迟GC |
Java 13 | 2019年9月 | - | 文本块(预览)、ZGC改进 | 多行字符串处理、GC性能提升 |
Java 14 | 2020年3月 | - | Switch表达式(正式)、Records(预览)、Pattern Matching(预览) | 代码简洁性、数据类简化、条件处理优化 |
Java 15 | 2020年9月 | - | 文本块(正式)、Records(第二预览)、Sealed Classes(预览) | 多行字符串处理、数据类简化、类型系统增强 |
Java 16 | 2021年3月 | - | Records(正式)、Pattern Matching(第二预览)、Vector API(孵化) | 数据类简化、条件处理优化、向量计算 |
Java 17 (LTS) | 2021年9月 | - | Sealed Classes(正式)、Pattern Matching for switch(预览)、强封装JDK内部API | 类型系统增强、模式匹配、安全性提升 |
Java 8 核心特性解析
Java 8是一次革命性的版本更新,引入了函数式编程范式,显著改变了Java开发模式。作为长期支持(LTS)版本,它至今仍被广泛使用。
Lambda表达式与函数式接口
特性概述
Lambda表达式是Java 8引入的最重要特性,它为Java带来了函数式编程的能力,使代码更加简洁、可读性更强。
技术细节
Lambda表达式本质上是一个匿名函数,由参数列表、箭头操作符和函数体组成:
// 基本语法: (参数) -> { 表达式 }
Runnable r1 = () -> System.out.println("Hello Lambda"); // 无参数
Comparator<Integer> c1 = (a, b) -> a.compareTo(b); // 多参数
Function<String, Integer> f1 = s -> s.length(); // 单参数可省略括号
函数式接口是Lambda表达式的基础,它是只包含一个抽象方法的接口,可以使用@FunctionalInterface
注解标记:
@FunctionalInterface
public interface Calculator {
int calculate(int a, int b);
// 默认方法不影响函数式接口的定义
default void printInfo() {
System.out.println("这是一个计算器接口");
}
}
// 使用Lambda表达式实现
Calculator addition = (a, b) -> a + b;
Calculator subtraction = (a, b) -> a - b;
应用场景
- 集合迭代与过滤
// 传统方式
for (String name : names) {
if (name.startsWith("A")) {
System.out.println(name);
}
}
// Lambda方式
names.stream()
.filter(name -> name.startsWith("A"))
.forEach(System.out::println);
- 事件处理
// 传统方式
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("按钮被点击");
}
});
// Lambda方式
button.addActionListener(e -> System.out.println("按钮被点击"));
- 多线程实现
// 传统方式
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程执行");
}
}).start();
// Lambda方式
new Thread(() -> System.out.println("线程执行")).start();
Stream API
特性概述
Stream API提供了一种函数式的集合操作方式,支持串行和并行处理,极大地简化了集合操作。
技术细节
Stream操作分为中间操作和终端操作:
- 中间操作:返回一个新的Stream,如filter、map、sorted等
- 终端操作:返回一个结果或副作用,如collect、forEach、reduce等
// Stream创建
Stream<String> streamFromCollection = list.stream(); // 从集合创建
Stream<String> streamFromArray = Arrays.stream(array); // 从数组创建
Stream<Integer> streamFromValues = Stream.of(1, 2, 3); // 从值创建
Stream<Integer> infiniteStream = Stream.iterate(0, n -> n+2); // 无限流创建
// Stream操作链
List<String> result = persons.stream() // 获取流
.filter(p -> p.getAge() > 18) // 过滤
.map(Person::getName) // 映射转换
.sorted() // 排序
.limit(10) // 限制数量
.collect(Collectors.toList()); // 收集结果
应用场景
- 数据转换
// 将人员列表转换为姓名列表
List<String> names = persons.stream()
.map(Person::getName)
.collect(Collectors.toList());
- 数据统计
// 计算所有人的平均年龄
double averageAge = persons.stream()
.mapToInt(Person::getAge)
.average()
.orElse(0);
- 数据分组
// 按年龄段分组
Map<AgeGroup, List<Person>> personsByAgeGroup = persons.stream()
.collect(Collectors.groupingBy(person -> {
if (person.getAge() < 18) return AgeGroup.UNDER_18;
else if (person.getAge() < 65) return AgeGroup.ADULT;
else return AgeGroup.SENIOR;
}));
方法引用
特性概述
方法引用是Lambda表达式的一种简化形式,当Lambda表达式的内容仅仅是调用一个已存在的方法时,可以使用方法引用来替代。
技术细节
方法引用有四种形式:
// 1. 静态方法引用:ClassName::staticMethodName
Function<String, Integer> parseInt = Integer::parseInt;
// 2. 实例方法引用:instance::methodName
String str = "Hello";
Supplier<Integer> getLength = str::length;
// 3. 对象方法引用:ClassName::methodName
Function<String, Integer> getStringLength = String::length;
// 4. 构造方法引用:ClassName::new
Supplier<Person> personCreator = Person::new;
应用场景
- 集合操作
// 打印集合元素
list.forEach(System.out::println);
// 获取所有人的名字
List<String> names = persons.stream()
.map(Person::getName) // 使用方法引用替代 p -> p.getName()
.collect(Collectors.toList());
- 排序操作
// 按姓名排序
persons.sort(Comparator.comparing(Person::getName));
默认方法与静态方法
特性概述
Java 8允许在接口中定义默认方法和静态方法,这使得接口的设计更加灵活,同时保持了向后兼容性。
技术细节
public interface Vehicle {
// 抽象方法
void start();
// 默认方法
default void honk() {
System.out.println("嘟嘟");
}
// 静态方法
static Vehicle createElectricVehicle() {
return new ElectricVehicle();
}
}
应用场景
- API演进
// 在Collection接口中添加新方法而不破坏现有实现
default boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
boolean removed = false;
final Iterator<E> each = iterator();
while (each.hasNext()) {
if (filter.test(each.next())) {
each.remove();
removed = true;
}
}
return removed;
}
- 多重继承行为
public interface Flyable {
default void fly() {
System.out.println("飞行中");
}
}
public interface Swimmable {
default void swim() {
System.out.println("游泳中");
}
}
// 一个类可以实现多个带有默认方法的接口
public class Duck implements Flyable, Swimmable {
// 同时获得了fly()和swim()方法
}
新日期时间API
特性概述
Java 8引入了全新的日期时间API (java.time包),解决了旧API的设计缺陷,提供了不可变、线程安全的日期时间处理类。
技术细节
核心类包括:
- LocalDate:表示日期 (年-月-日)
- LocalTime:表示时间 (时:分:秒.毫秒)
- LocalDateTime:表示日期和时间
- ZonedDateTime:带时区的日期和时间
- Instant:时间戳
- Duration:两个时间之间的间隔
- Period:两个日期之间的间隔
// 创建日期时间
LocalDate date = LocalDate.of(2023, 3, 25);
LocalTime time = LocalTime.of(13, 45, 20);
LocalDateTime dateTime = LocalDateTime.of(date, time);
ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
// 日期时间操作
LocalDate tomorrow = date.plusDays(1);
LocalDate lastMonth = date.minusMonths(1);
boolean isLeapYear = date.isLeapYear();
// 日期时间格式化
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formattedDateTime = dateTime.format(formatter);
应用场景
- 日期计算
// 计算两个日期之间的天数
LocalDate startDate = LocalDate.of(2023, 1, 1);
LocalDate endDate = LocalDate.of(2023, 12, 31);
long daysBetween = ChronoUnit.DAYS.between(startDate, endDate);
- 时区处理
// 在不同时区之间转换时间
ZonedDateTime tokyoTime = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));
ZonedDateTime newYorkTime = tokyoTime.withZoneSameInstant(ZoneId.of("America/New_York"));
- 日期时间解析
// 解析日期字符串
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDate date = LocalDate.parse("2023-03-25", formatter);
Java 9
见下章