JDK 1.8(Java 8)是 Java 历史上的里程碑版本,引入了大量改变开发模式的新语法和特性,核心聚焦于函数式编程 和简化代码。
一、核心:Lambda 表达式(函数式编程基础)
Lambda 表达式是 JDK8 最核心的语法升级,用于简化函数式接口(仅含一个抽象方法的接口)的匿名内部类实现,本质是 "可传递的代码块"。
语法格式
bash
(参数列表) -> { 执行语句; }
// 简化规则:
// 1. 单参数可省略括号:param -> { ... }
// 2. 单执行语句可省略大括号和分号:param -> statement
// 3. 有返回值且单语句可省略return:param -> expression
示例:替代匿名内部类
java
// 传统匿名内部类(Runnable接口)
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("传统方式");
}
}).start();
// Lambda简化
new Thread(() -> System.out.println("Lambda方式")).start();
// 示例2:Comparator排序(简化多参数场景)
List<String> list = Arrays.asList("b", "a", "c");
// 传统方式
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
});
// Lambda简化
Collections.sort(list, (o1, o2) -> o1.compareTo(o2));
二、函数式接口(Lambda 的载体)
JDK8 正式定义 "函数式接口":仅包含一个抽象方法 的接口(可含默认方法 / 静态方法),并提供@FunctionalInterface注解校验(非强制,但推荐使用)。
核心特性
- 注解
@FunctionalInterface:编译期校验接口是否符合函数式规范; - JDK8 内置了大量常用函数式接口(位于
java.util.function包),避免重复定义:
| 接口 | 抽象方法 | 用途 | 示例 |
|---|---|---|---|
Consumer<T> |
accept(T t) |
消费型(入参无返回) | list.forEach(s -> System.out.println(s)) |
Supplier<T> |
get() |
供给型(无入参有返回) | () -> new ArrayList<>() |
Function<T,R> |
apply(T t) |
函数型(入参 T 返回 R) | s -> s.length() |
Predicate<T> |
test(T t) |
断言型(入参返回布尔) | s -> s.isEmpty() |
示例:使用内置函数式接口
java
// Predicate:过滤空字符串
Predicate<String> isEmpty = s -> s.isEmpty();
System.out.println(isEmpty.test("")); // true
// Function:字符串转长度
Function<String, Integer> strLength = s -> s.length();
System.out.println(strLength.apply("Java8")); // 5
三、方法引用(Lambda 的简化版)
方法引用是 Lambda 的语法糖,当 Lambda 体仅调用一个已存在的方法时,可进一步简化代码,格式为类名/对象::方法名。
java
wrapper.like(StringUtils.isNotBlank(username),User::getName,"a")
.gt(ageBegin != null,User::getAge,ageBegin)
.lt(ageEnd != null,User::getAge,ageEnd);
四种类型的方法引用
| 类型 | 语法示例 | 对应 Lambda |
|---|---|---|
| 静态方法引用 | 类名::静态方法 |
(a,b) -> 类名.静态方法(a,b) |
| 实例方法引用(任意对象) | 类名::实例方法 |
(obj, a) -> obj.实例方法(a) |
| 实例方法引用(特定对象) | 对象::实例方法 |
(a) -> 对象.实例方法(a) |
| 构造器引用 | 类名::new |
() -> new 类名() |
示例
java
// 1. 静态方法引用:Integer::parseInt 等价于 s -> Integer.parseInt(s)
Function<String, Integer> f1 = Integer::parseInt;
System.out.println(f1.apply("123")); // 123
// 2. 特定对象的实例方法引用:System.out::println 等价于 s -> System.out.println(s)
Consumer<String> f2 = System.out::println;
f2.accept("方法引用示例");
// 3. 构造器引用:ArrayList::new 等价于 () -> new ArrayList<>()
Supplier<List<String>> f3 = ArrayList::new;
List<String> list = f3.get();
四、接口的默认方法(default)和静态方法(static)
JDK8 前,接口只能包含抽象方法;JDK8 允许接口定义:
- 默认方法 (
default):带方法体的实例方法,子类可重写,解决 "接口升级兼容问题"; - 静态方法 (
static):带方法体的静态方法,通过接口名直接调用。
java
public interface MyInterface {
// 抽象方法(必须实现)
void abstractMethod();
// 默认方法(子类可继承/重写)
default void defaultMethod() {
System.out.println("接口默认方法");
}
// 静态方法(接口名调用)
static void staticMethod() {
System.out.println("接口静态方法");
}
}
// 实现类
class MyImpl implements MyInterface {
@Override
public void abstractMethod() {
System.out.println("实现抽象方法");
}
// 可选重写默认方法
@Override
public void defaultMethod() {
System.out.println("重写默认方法");
}
}
// 调用
MyInterface.staticMethod(); // 接口静态方法
MyImpl impl = new MyImpl();
impl.defaultMethod(); // 重写默认方法
五、Stream API(集合流式处理)
Stream API 是 JDK8 为集合提供的函数式流式处理语法,支持链式操作、并行处理,简化集合遍历 / 过滤 / 映射等操作(类似 SQL 的声明式语法)。
核心特性
- 流式操作:分为 "中间操作"(延迟执行,返回 Stream)和 "终止操作"(立即执行,返回结果);
- 无状态 / 有状态:中间操作分为无状态(filter/map)和有状态(sorted/distinct);
- 并行流 :利用多核 CPU,通过
parallel()切换并行处理。
语法示例:链式操作
java
List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
// 需求:过滤偶数 → 乘以2 → 求和
int sum = nums.stream()
.filter(n -> n % 2 == 0) // 中间操作:过滤偶数
.map(n -> n * 2) // 中间操作:映射乘2
.reduce(0, Integer::sum); // 终止操作:求和
System.out.println(sum); // (2+4+6+8)*2 = 40
// 并行流(适合大数据量)
int parallelSum = nums.parallelStream()
.filter(n -> n % 2 == 0)
.mapToInt(n -> n * 2)
.sum();
六、Optional 类(解决空指针 NPE)
Optional 是 JDK8 提供的 "空安全" 容器,封装可能为null的对象,强制开发者处理空值,避免直接判空(if (obj == null))。
核心方法
| 方法 | 用途 |
|---|---|
Optional.of(T) |
创建非空 Optional(null 则抛 NPE) |
Optional.ofNullable(T) |
创建可空 Optional |
ifPresent(Consumer) |
非空时执行消费逻辑 |
orElse(T) |
空时返回默认值 |
orElseGet(Supplier) |
空时通过 Supplier 生成默认值 |
orElseThrow(Supplier) |
空时抛自定义异常 |
示例
java
// 传统空判(易漏判)
String str = null;
if (str != null) {
System.out.println(str.length());
}
// Optional简化
Optional<String> opt = Optional.ofNullable(str);
opt.ifPresent(s -> System.out.println(s.length())); // 非空才执行
String defaultStr = opt.orElse("默认值"); // 空则返回默认值
String defaultStr2 = opt.orElseGet(() -> "动态生成默认值");
opt.orElseThrow(() -> new IllegalArgumentException("值不能为空"));
七、新日期时间 API(JSR 310)
替代旧的Date/Calendar(线程不安全、设计混乱),提供不可变、线程安全 的日期时间处理类,位于java.time包。
核心类
| 类 | 用途 | 示例 |
|---|---|---|
LocalDate |
本地日期(年 / 月 / 日) | LocalDate.now() → 2025-11-29 |
LocalTime |
本地时间(时 / 分 / 秒) | LocalTime.now() → 10:30:00 |
LocalDateTime |
本地日期时间 | LocalDateTime.now() |
Instant |
时间戳(UTC) | Instant.now() |
Duration |
时间间隔(秒 / 纳秒) | Duration.between(t1, t2) |
Period |
日期间隔(年 / 月 / 日) | Period.between(d1, d2) |
DateTimeFormatter |
日期格式化(替代 SimpleDateFormat) | DateTimeFormatter.ofPattern("yyyy-MM-dd") |
示例
java
// 1. 获取当前日期时间
LocalDateTime now = LocalDateTime.now();
System.out.println(now); // 2025-11-29T10:35:20.123
// 2. 格式化
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formatStr = now.format(formatter);
System.out.println(formatStr); // 2025-11-29 10:35:20
// 3. 时间计算
LocalDateTime tomorrow = now.plusDays(1); // 加1天
LocalDateTime lastMonth = now.minusMonths(1); // 减1月
// 4. 解析字符串
LocalDate date = LocalDate.parse("2025-12-01", formatter);
八、其他次要语法 / 特性
重复注解(@Repeatable)
允许同一注解在同一位置多次使用,解决旧版本注解只能用一次的问题:
java
@Repeatable(Roles.class) // 声明可重复
@interface Role { String value(); }
@interface Roles { Role[] value(); }
// 使用
@Role("admin")
@Role("user")
public class User {}
类型注解
注解可用于任意类型上下文(如泛型、数组、方法参数类型等),配合静态检查工具(如 FindBugs)提升代码安全性:
java
// 泛型类型注解
List<@NonNull String> list = new ArrayList<>();
// 数组类型注解
String @NonNull [] arr = new String[10];
Base64 内置支持
新增java.util.Base64类,替代第三方 Base64 库(如 Apache Commons),支持标准 / URL 安全 / MIME 编码:
java
String str = "Java8";
// 编码
String encode = Base64.getEncoder().encodeToString(str.getBytes());
// 解码
byte[] decode = Base64.getDecoder().decode(encode);
System.out.println(new String(decode)); // Java8