> 技术文档 > Java 8+ 特性(Lambda表达式、Stream API、Optional类等)必会知识汇总

Java 8+ 特性(Lambda表达式、Stream API、Optional类等)必会知识汇总


目录:

  • 🧠 一、Lambda 表达式
    • 1. 基本概念
    • 2. 使用场景
    • 3. 示例
    • 4. 函数式接口
    • 5. 方法引用
  • 🧩 二、Stream API
    • 1. 核心概念
    • 2. 创建 Stream
    • 3. 中间操作(Intermediate)
    • 4. 终端操作(Terminal)
    • 5. 示例
    • 6. 注意事项
  • 🧱 三、Optional 类
    • 1. 核心概念
    • 2. 常见方法
    • 3. 示例
    • 4. 注意事项
  • 📌 四、接口默认方法与静态方法
    • 1. 默认方法(Default Method)
    • 2. 静态方法(Static Method)
    • 3. 使用场景
  • 📦 五、新日期时间 API(java.time)**
    • 1. 核心类
    • 2. 示例
    • 3. 优点
  • 🧩 六、常用函数式接口
  • 📊 七、常见面试题及答案
    • 1. Lambda 表达式与匿名内部类的区别?
    • 2. Stream 的 map 和 flatMap 的区别?
    • 3. Optional 的 orElse() 和 orElseGet() 的区别?
    • 4. Collectors 常用方法?
    • 5. Stream 的 filter 和 map 的执行顺序?
  • ✅ 八、总结:Java 8+ 核心特性
  • 📚 九、推荐学习资料
  • 📄 十、完整代码示例(含 Stream + Optional + Lambda)

🧠 一、Lambda 表达式

1. 基本概念

  • 作用:简化匿名内部类的写法,支持函数式编程。
  • 语法
    (parameters) -> expression
    (parameters) -> { statements; }

2. 使用场景

  • 替代匿名内部类(如 Runnable、Comparator)。
  • 简化集合操作(结合 Stream API 使用)。

3. 示例

// 传统匿名类new Thread(new Runnable() { public void run() { System.out.println(\"Hello\"); }}).start();
// Lambda 表达式new Thread(() -> System.out.println(\"Hello\")).start();
// 集合排序List<String> list = Arrays.asList(\"a\", \"b\", \"c\");list.sort((s1, s2) -> s1.compareTo(s2));

4. 函数式接口

  • 定义:只有一个抽象方法的接口(可包含默认方法和静态方法)。
  • 常见内置函数式接口
    • Consumer:消费型接口(无返回值)
    • Function:函数型接口(输入 T,输出 R)
    • Predicate:断言型接口(返回 boolean)
    • Supplier:供给型接口(无输入,返回 T)

5. 方法引用

  • 语法
    • 对象::实例方法
    • 类::静态方法
    • 类::实例方法(第一个参数是实例)

示例

List<String> list = Arrays.asList(\"a\", \"b\", \"c\");list.forEach(System.out::println); // 对象::实例方法

🧩 二、Stream API

1. 核心概念

  • 作用:对集合进行函数式操作(过滤、映射、聚合等)。
  • 特点:链式调用、惰性求值、支持并行处理。

2. 创建 Stream

  • 方式
Stream<String> stream = list.stream(); // 从集合创建Stream<String> stream = Stream.of(\"a\", \"b\"); // 直接创建

3. 中间操作(Intermediate)

操作 说明 filter(Predicate) 过滤符合条件的元素 map(Function) 转换元素(如转换类型) flatMap(Function) 扁平化处理(如 List -> List) limit(n) 取前 n 个元素 skip(n) 跳过前 n 个元素 sorted() 排序 distinct() 去重(基于 hashCode 和 equals)

4. 终端操作(Terminal)

操作 说明 forEach(Consumer) 遍历元素 collect(Collector) 收集结果(如转为 List、Map) reduce(BinaryOperator) 聚合操作(如求和) count() 统计元素数量 anyMatch(Predicate) 是否有任意元素匹配 allMatch(Predicate) 是否所有元素匹配 noneMatch(Predicate) 是否没有元素匹配

5. 示例

List<String> list = Arrays.asList(\"apple\", \"banana\", \"cherry\");// 过滤并收集List<String> filtered = list.stream() .filter(s -> s.startsWith(\"a\")) .collect(Collectors.toList());// 求和int sum = list.stream() .mapToInt(String::length) .sum();// 分组Map<Integer, List<String>> grouped = list.stream() .collect(Collectors.groupingBy(String::length));

6. 注意事项

  • 不要用于小数据量:Stream 的性能优势在大数据量时更明显。
  • 避免中间操作无终端操作:中间操作是惰性的,只有终端操作才会执行。
  • 避免在 Stream 中修改外部变量:应使用不可变操作。

🧱 三、Optional 类

1. 核心概念

  • 作用:避免空指针异(NullPointerException)。
  • 使用场景:替代 null 检查,使代码更简洁。

2. 常见方法

方法 说明 Optional.of(T) 创建非空 Optional Optional.ofNullable(T) 创建可为 null 的 Optional isPresent() 判断值是否存在 ifPresent(Consumer) 存在时执行操作 orElse(T) 不存在时返回默认值 orElseGet(Supplier) 不存在时生成默认值 orElseThrow(Supplier) 不存在时抛出异常

3. 示例

String name = Optional.ofNullable(getName()) .orElse(\"Default\");// 避免嵌套 null 检查Optional<User> user = Optional.ofNullable(findUser());user.flatMap(User::getAddress) .ifPresent(System.out::println);

4. 注意事项

  • 不要滥用 get():使用前必须调用 isPresent() 检查。
  • 避免 Optional 作为类字段:可能导致序列化问题。
  • 优先使用orElseGet() 而非 orElse():避免不必要的计算。

📌 四、接口默认方法与静态方法

1. 默认方法(Default Method)

  • 作用:在接口中提供默认实现,避免接口升级时破坏实现类。
  • 语法
public interface MyInterface { default void defaultMethod() { System.out.println(\"Default Method\"); }}

2. 静态方法(Static Method)

  • 作用:在接口中定义工具方法。
  • 语法
public interface MyInterface { static void staticMethod() { System.out.println(\"Static Method\"); }}

3. 使用场景

  • 默认方法:为接口添加新方法时兼容旧实现类。
  • 静态方法:提供与接口相关的工具方法(如 Comparator.naturalOrder())。

📦 五、新日期时间 API(java.time)**

1. 核心类

类名 说明 LocalDate 日期(如 2023-10-23) LocalTime 时间(如 15:30:00) LocalDateTime 日期+时间(如 2023-10-23T15:30:00) ZonedDateTime 带时区的日期时间 Duration 时间间隔(基于时间,如 Duration.ofHours(2)) Period 日期间隔(基于日期,如 Period.ofDays(3))

2. 示例

LocalDate today = LocalDate.now();LocalDate tomorrow = today.plusDays(1);LocalTime now = LocalTime.now();LocalTime twoHoursLater = now.plusHours(2);// 计算两个日期间隔Period period = LocalDate.of(2023, 10, 1).until(LocalDate.of(2023, 10, 10));System.out.println(period.get(ChronoUnit.DAYS)); // 输出 9

3. 优点

  • 线程安全:java.util.Date 是可变对象,LocalDate 是不可变的。
  • 更直观的 API:如 plusDays()、minusDays()。

🧩 六、常用函数式接口

接口 抽象方法 说明 Consumer void accept(T t) 消费型,无返回值 Function R apply(T t) 函数型,输入 T,输出 R Predicate boolean test(T t) 断言型,返回 boolean Supplier T get() 供给型,无输入,返回 T BiFunction R apply(T t, U u) 双输入函数型

📊 七、常见面试题及答案

1. Lambda 表达式与匿名内部类的区别?

  • Lambda 表达式:只能用于函数式接口,语法更简洁。
  • 匿名内部类:可以实现任意接口,语法冗长。

2. Stream 的 map 和 flatMap 的区别?

  • map:将每个元素转换为新元素(如 Stream → Stream)。
  • flatMap:将每个元素转换为一个流,然后扁平化为一个流(如 Stream → Stream)。

3. Optional 的 orElse() 和 orElseGet() 的区别?

  • orElse(T):无论 Optional 是否为空,都会执行 T 的创建。
  • orElseGet(Supplier):仅在 Optional 为空时才执行 Supplier。

4. Collectors 常用方法?

方法 说明 toList() 收集为 List toSet() 收集为 Set toMap() 收集为 Map groupingBy() 分组(如按年龄分组) partitioningBy() 分区(如按条件分为 true/false 两组)

5. Stream 的 filter 和 map 的执行顺序?

  • 顺序执行:先 filter 再 map,避免不必要的转换。
  • 惰性求值:中间操作不会立即执行,终端操作触发处理。

✅ 八、总结:Java 8+ 核心特性

Java 8+ 特性(Lambda表达式、Stream API、Optional类等)必会知识汇总

📚 九、推荐学习资料

  • 《Java 8 实战》(Cay S. Horstmann)
  • 《Java 9 并发编程实战》
  • B站、慕课网、CSDN、知乎 等平台的 Java 8 教程
  • Java 官方文档:https://docs.oracle.com/javase/8/docs/

📄 十、完整代码示例(含 Stream + Optional + Lambda)

List<User> users = Arrays.asList( new User(\"Alice\", 25), new User(\"Bob\", 30), new User(\"Charlie\", 25));// 过滤年龄为25的用户,按姓名排序List<String> names = users.stream() .filter(user -> user.getAge() == 25) .sorted(Comparator.comparing(User::getName)) .map(User::getName) .collect(Collectors.toList());// 使用 Optional 避免 nullOptional<User> userOpt = Optional.ofNullable(findUser(\"Alice\"));userOpt.ifPresent(user -> System.out.println(user.getName()));// 分组(按年龄)Map<Integer, List<User>> groupedByAge = users.stream() .collect(Collectors.groupingBy(User::getAge));