【Java基础】Java 8-21新特性 :Lambda表达式、函数式接口、Stream流、Optional(附《思维导图》+《面试高频考点清单》)

简介: 本文系统梳理Java 8–21核心新特性,聚焦面试高频考点:Lambda表达式、函数式接口、Stream流(惰性求值/并行流/map与flatMap区别)、Optional空值安全处理,并涵盖JDK9–21关键演进(模块化、var、Record、虚拟线程等),辅以原理剖析与实战代码,助力高效备战。

思维导图

Java基础:Java 8-21新特性核心知识体系(面试版)

一、整体演进与核心价值

Java 8是Java语言发展史上的里程碑,引入了函数式编程范式,彻底改变了Java代码的编写风格。后续Java 9-21版本在Java 8基础上持续优化和增强,使函数式编程更加完善、高效。

核心价值

  • 代码更简洁、可读性更高
  • 支持并行计算,充分利用多核CPU
  • 减少空指针异常(Optional)
  • 提供声明式编程风格,专注于"做什么"而非"怎么做"

二、Lambda表达式

2.1 定义与本质

Lambda表达式是可传递的匿名函数,本质是函数式接口的实例。它没有名称,但有参数列表、函数体和返回类型。

2.2 语法格式

(参数列表) -> {
    函数体 }

语法简化规则

  1. 参数类型可省略,编译器自动推断
  2. 单个参数时,括号可省略
  3. 函数体只有一条语句时,大括号和return可省略

示例

// 完整写法
Comparator<Integer> comparator1 = (Integer a, Integer b) -> {
    return a.compareTo(b); };

// 简化写法
Comparator<Integer> comparator2 = (a, b) -> a.compareTo(b);

2.3 变量捕获

  • Lambda可以访问外部局部变量,但该变量必须是final或事实上的final(Java 8+)
  • Lambda可以访问实例变量静态变量
  • Lambda内部不能修改局部变量的值

示例

int num = 10; // 事实上的final
Runnable runnable = () -> System.out.println(num);
// num = 20; // 编译错误,不能修改

2.4 方法引用与构造器引用

方法引用是Lambda表达式的进一步简化,当Lambda体只调用一个方法时使用。

类型 语法 示例
静态方法引用 类名::静态方法名 Integer::parseInt
实例方法引用 对象::实例方法名 System.out::println
类名::实例方法名 类名::实例方法名 String::compareTo
构造器引用 类名::new ArrayList::new

2.5 底层原理

  • Lambda表达式在编译时会生成私有静态方法
  • 运行时通过invokedynamic指令动态调用
  • 不会生成匿名内部类的class文件,性能更高

三、函数式接口

3.1 定义

只有一个抽象方法的接口称为函数式接口,可以用@FunctionalInterface注解标记(可选,但推荐使用,编译器会检查)。

3.2 四大核心函数式接口

这是Java 8提供的最基础、最常用的函数式接口,位于java.util.function包。

接口 抽象方法 作用 泛型说明
Consumer<T> void accept(T t) 消费型接口:接收一个参数,无返回值 T:输入参数类型
Supplier<T> T get() 供给型接口:无参数,返回一个值 T:返回值类型
Function<T, R> R apply(T t) 函数型接口:接收一个参数,返回一个值 T:输入参数类型,R:返回值类型
Predicate<T> boolean test(T t) 断言型接口:接收一个参数,返回布尔值 T:输入参数类型

3.3 扩展函数式接口

为了处理基本类型(避免自动装箱拆箱的性能损耗)和多参数场景,Java提供了大量扩展接口:

  • 基本类型特化IntConsumerLongSupplierDoubleFunction
  • 二元操作BiConsumer<T, U>BiFunction<T, U, R>BiPredicate<T, U>
  • 一元操作UnaryOperator<T>(Function的子接口,输入输出类型相同)
  • 二元操作BinaryOperator<T>(BiFunction的子接口,输入输出类型相同)

3.4 自定义函数式接口

@FunctionalInterface
public interface MyFunction<T, R> {
   
    R apply(T t);

    // 可以有默认方法和静态方法
    default void defaultMethod() {
   }
    static void staticMethod() {
   }
}

四、Stream流

4.1 定义与特点

Stream是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。

核心特点

  • 不存储数据,只是对数据进行计算
  • 不改变源数据,会生成一个新的流
  • 惰性求值:只有调用终止操作时,中间操作才会执行
  • 一次性消费:流只能使用一次,使用后会关闭

4.2 流的操作流程

数据源 -> 中间操作1 -> 中间操作2 -> ... -> 终止操作

4.3 流的创建

// 1. 集合创建(最常用)
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream1 = list.stream(); // 串行流
Stream<String> parallelStream1 = list.parallelStream(); // 并行流

// 2. 数组创建
String[] array = {
   "a", "b", "c"};
Stream<String> stream2 = Arrays.stream(array);

// 3. 值创建
Stream<String> stream3 = Stream.of("a", "b", "c");

// 4. 无限流
Stream<Integer> stream4 = Stream.iterate(0, n -> n + 2); // 迭代
Stream<Double> stream5 = Stream.generate(Math::random); // 生成

4.4 中间操作

中间操作返回一个新的流,可以链式调用。

4.4.1 筛选与切片

方法 作用
filter(Predicate<T>) 过滤流中满足条件的元素
distinct() 去重(根据equals()方法)
limit(long n) 截断流,只保留前n个元素
skip(long n) 跳过前n个元素

4.4.2 映射

方法 作用
map(Function<T, R>) 将流中的每个元素映射成另一个元素
flatMap(Function<T, Stream<R>>) 将流中的每个元素映射成一个流,然后将所有流连接成一个流

map与flatMap的区别

  • map:一对一映射
  • flatMap:一对多映射,会"扁平化"流

4.4.3 排序

方法 作用
sorted() 自然排序(元素必须实现Comparable接口)
sorted(Comparator<T>) 定制排序

4.5 终止操作

终止操作会触发流的计算,计算完成后流就关闭了。

4.5.1 匹配与查找

方法 作用 返回值
allMatch(Predicate<T>) 检查是否所有元素都满足条件 boolean
anyMatch(Predicate<T>) 检查是否至少有一个元素满足条件 boolean
noneMatch(Predicate<T>) 检查是否没有元素满足条件 boolean
findFirst() 返回第一个元素 Optional
findAny() 返回任意一个元素(并行流中效率更高) Optional

4.5.2 归约

方法 作用
reduce(T identity, BinaryOperator<T>) 从初始值开始,将流中元素累加
reduce(BinaryOperator<T>) 没有初始值,返回Optional

示例

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
int sum = list.stream().reduce(0, Integer::sum); // 15
Optional<Integer> max = list.stream().reduce(Integer::max); // Optional[5]

4.5.3 收集

collect(Collector<T, A, R>)是最常用的终止操作,将流转换为其他数据结构。

常用Collector

// 转换为集合
List<String> list = stream.collect(Collectors.toList());
Set<String> set = stream.collect(Collectors.toSet());
Map<String, Integer> map = stream.collect(Collectors.toMap(String::length, Function.identity()));

// 分组
Map<Integer, List<String>> groupByLength = stream.collect(Collectors.groupingBy(String::length));

// 分区
Map<Boolean, List<String>> partitionByLength = stream.collect(Collectors.partitioningBy(s -> s.length() > 3));

// 聚合
long count = stream.collect(Collectors.counting());
Optional<String> max = stream.collect(Collectors.maxBy(String::compareTo));
String joining = stream.collect(Collectors.joining(", "));

4.6 并行流

  • 并行流使用Fork/Join框架,将任务分解成多个子任务并行执行
  • 创建方式:list.parallelStream()stream.parallel()
  • 注意事项:
    • 确保线程安全
    • 避免在并行流中使用有状态的中间操作
    • 数据量小时,并行流可能比串行流慢(线程切换开销)

4.7 Java 9-21 Stream增强

  • Java 9takeWhile()dropWhile()ofNullable()iterate()重载方法
  • Java 10Collectors.toUnmodifiableList()toUnmodifiableSet()toUnmodifiableMap()
  • Java 12Collectors.teeing()(合并两个收集器的结果)
  • Java 16Stream.toList()(简化集合转换,返回不可变列表)

五、Optional

5.1 定义与作用

Optional是一个容器类,用于包装可能为null的值,从根本上解决空指针异常(NPE)问题。

5.2 核心方法

5.2.1 创建Optional

方法 作用 注意事项
Optional.of(T value) 创建一个包含非null值的Optional 如果value为null,抛出NPE
Optional.ofNullable(T value) 创建一个可能包含null值的Optional 推荐使用
Optional.empty() 创建一个空的Optional

5.2.2 获取值

方法 作用 注意事项
get() 获取Optional中的值 如果为空,抛出NoSuchElementException
orElse(T other) 如果有值则返回,否则返回other 无论是否有值,other都会执行
orElseGet(Supplier<T> other) 如果有值则返回,否则返回other.get() 只有为空时,other才会执行
orElseThrow(Supplier<X> exceptionSupplier) 如果有值则返回,否则抛出指定异常 推荐使用

5.2.3 判断与转换

方法 作用
isPresent() 判断是否有值
ifPresent(Consumer<T> consumer) 如果有值,执行consumer
map(Function<T, R> mapper) 如果有值,执行mapper并返回新的Optional
flatMap(Function<T, Optional<R>> mapper) 与map类似,但mapper返回Optional
filter(Predicate<T> predicate) 如果有值且满足条件,返回当前Optional,否则返回空

5.3 最佳实践

推荐

// 链式调用
String name = user.getAddress()
    .flatMap(Address::getCity)
    .map(City::getName)
    .orElse("未知");

// 存在时执行操作
user.ifPresent(u -> System.out.println(u.getName()));

// 抛出指定异常
User user = userRepository.findById(id)
    .orElseThrow(() -> new UserNotFoundException("用户不存在"));

避免

// 仍然会产生NPE
Optional<User> user = Optional.ofNullable(null);
user.get().getName();

// 没有解决根本问题
if (user.isPresent()) {
   
    System.out.println(user.get().getName());
}

5.4 Java 9-21 Optional增强

  • Java 9ifPresentOrElse()or()stream()
  • Java 10orElseThrow()(无参,抛出NoSuchElementException)
  • Java 11isEmpty()(与isPresent()相反)

六、Java 9-21其他重要新特性

6.1 Java 9

  • 模块系统(JPMS)
  • 接口私有方法
  • 集合工厂方法:List.of()Set.of()Map.of()
  • 改进的try-with-resources

6.2 Java 10

  • 局部变量类型推断(var)
  • 不可变集合增强

6.3 Java 11

  • 字符串增强:isBlank()lines()strip()
  • HttpClient API正式版
  • 运行单个Java文件:java HelloWorld.java

6.4 Java 14

  • 记录类(Record)
  • 模式匹配(instanceof)
  • 文本块(预览)

6.5 Java 15

  • 文本块正式版
  • 密封类(预览)

6.6 Java 16

  • 记录类正式版
  • 模式匹配(instanceof)正式版
  • 密封类第二次预览

6.7 Java 17(LTS)

  • 密封类正式版
  • 增强的伪随机数生成器
  • 移除实验性的AOT和JIT编译器

6.8 Java 21(LTS)

  • 虚拟线程(Project Loom)
  • 模式匹配(switch)正式版
  • 记录模式
  • 字符串模板(预览)

七、面试核心考点与易错点

  1. Lambda表达式的底层原理是什么?与匿名内部类有什么区别?

    • 底层使用invokedynamic指令,不会生成匿名内部类的class文件
    • 变量捕获规则不同:Lambda要求局部变量是final或事实上的final
    • 性能更高,内存占用更少
  2. 函数式接口的定义是什么?为什么只能有一个抽象方法?

    • 只有一个抽象方法的接口
    • 因为Lambda表达式只能匹配一个抽象方法的签名
  3. Stream流的中间操作和终止操作有什么区别?

    • 中间操作返回新的流,可以链式调用,惰性求值
    • 终止操作触发计算,计算完成后流关闭,返回非流类型
  4. map和flatMap的区别是什么?

    • map:一对一映射,返回普通对象
    • flatMap:一对多映射,返回流,会"扁平化"流
  5. 并行流的底层原理是什么?使用时需要注意什么?

    • 底层使用Fork/Join框架
    • 注意线程安全,避免有状态的中间操作
    • 数据量小时不建议使用,线程切换开销大于并行收益
  6. Optional的正确使用方式是什么?

    • 不要用Optional作为方法参数
    • 不要用Optional作为类的字段
    • 不要调用get()方法,除非你确定Optional不为空
    • 优先使用orElseGet()orElseThrow()和链式调用

八、综合实战案例

// 需求:从用户列表中筛选出年龄大于18岁的男性用户,按年龄排序,取前10个,获取他们的姓名列表
List<String> names = userList.stream()
    .filter(user -> user.getAge() > 18)
    .filter(user -> "男".equals(user.getGender()))
    .sorted(Comparator.comparingInt(User::getAge))
    .limit(10)
    .map(User::getName)
    .collect(Collectors.toList());

// 需求:计算所有用户的平均年龄
double averageAge = userList.stream()
    .mapToInt(User::getAge)
    .average()
    .orElse(0.0);

// 需求:按性别分组,统计每个性别的用户数量
Map<String, Long> countByGender = userList.stream()
    .collect(Collectors.groupingBy(User::getGender, Collectors.counting()));

Java 8-21核心新特性面试问答清单(可直接背诵版)

标注说明:★★★=高频必问,★★☆=中频常问,★☆☆=低频了解;⚠️=易错点

一、整体演进与核心价值

Q1:为什么说Java 8是Java发展史上的里程碑?(★★☆)

:Java 8首次引入函数式编程范式,彻底改变了Java代码的编写风格,解决了传统面向对象代码冗长、并行计算困难、空指针异常频发等问题。后续Java 9-21版本均在Java 8基础上持续优化函数式编程能力。

核心价值

  1. 代码更简洁、可读性更高
  2. 原生支持并行计算,充分利用多核CPU
  3. 从设计层面减少空指针异常(Optional)
  4. 提供声明式编程风格,专注"做什么"而非"怎么做"

二、Lambda表达式

Q2:Lambda表达式的本质是什么?语法格式是什么?(★★★)

:Lambda表达式是可传递的匿名函数,本质是函数式接口的实例

语法格式(参数列表) -> { 函数体 }

语法简化规则

  1. 参数类型可省略,编译器自动类型推断
  2. 单个参数时,括号可省略
  3. 函数体只有一条语句时,大括号和return可同时省略

示例

// 完整写法
Comparator<Integer> c1=(Integer a, Integer b)->{
   return a.compareTo(b);};
// 简化写法
Comparator<Integer> c2=(a,b)->a.compareTo(b);

Q3:Lambda表达式的变量捕获规则是什么?(★★★)

  1. 可以访问实例变量静态变量,且可修改
  2. 可以访问外部局部变量,但该变量必须是final或事实上的final(Java 8+)
  3. Lambda内部不能修改局部变量的值

⚠️ 易错点:即使没有显式声明final,只要局部变量在Lambda之后没有被修改,就是"事实上的final";一旦修改,编译报错。

Q4:方法引用有哪几种类型?分别举个例子。(★★★)

:方法引用是Lambda表达式的简化形式,当Lambda体只调用一个方法时使用,共4种类型:

类型 语法 示例 适用场景
静态方法引用 类名::静态方法名 Integer::parseInt 调用类的静态方法
实例方法引用 对象::实例方法名 System.out::println 调用已有对象的实例方法
类名::实例方法名 类名::实例方法名 String::compareTo 第一个参数作为方法调用者
构造器引用 类名::new ArrayList::new 调用构造器创建对象

Q5:Lambda表达式与匿名内部类有什么区别?(★★★)

  1. 本质不同:Lambda是函数式接口的实例;匿名内部类是类的实例
  2. 编译方式不同:Lambda编译时生成私有静态方法,通过invokedynamic指令调用;匿名内部类生成单独的类名$1.class文件
  3. 变量捕获不同:Lambda要求局部变量是final/事实上的final;匿名内部类可以修改非final局部变量(Java 8之前)
  4. this指向不同:Lambda的this指向外部类;匿名内部类的this指向自身
  5. 性能不同:Lambda没有类加载开销,性能更高,内存占用更少

Q6:Lambda表达式的底层原理是什么?(★★☆)

  1. 编译时:编译器为Lambda表达式生成一个私有静态方法,方法体就是Lambda的代码
  2. 运行时:通过invokedynamic指令动态调用该方法,由JVM在运行时生成函数式接口的实例
  3. 优势:避免了匿名内部类的类加载和对象创建开销,性能更优

三、函数式接口

Q7:什么是函数式接口?@FunctionalInterface注解的作用是什么?(★★★)

只有一个抽象方法的接口称为函数式接口。

@FunctionalInterface注解的作用:

  1. 编译器检查:确保接口只有一个抽象方法,否则编译报错
  2. 文档说明:明确该接口是为函数式编程设计的

⚠️ 易错点:函数式接口可以有默认方法静态方法,因为它们不是抽象方法。

Q8:Java 8提供的四大核心函数式接口是什么?分别说明其作用。(★★★)

:四大核心接口位于java.util.function包,是所有函数式编程的基础:

接口 抽象方法 作用 泛型说明
Consumer<T> void accept(T t) 消费型接口:接收一个参数,无返回值 T:输入参数类型
Supplier<T> T get() 供给型接口:无参数,返回一个值 T:返回值类型
Function<T, R> R apply(T t) 函数型接口:接收一个参数,返回一个值 T:输入,R:输出
Predicate<T> boolean test(T t) 断言型接口:接收一个参数,返回布尔值 T:输入参数类型

Q9:为什么函数式接口只能有一个抽象方法?(★★☆)

:因为Lambda表达式只能匹配一个方法签名。如果接口有多个抽象方法,Lambda无法确定要实现哪个方法,编译器会报错。

Q10:什么是基本类型特化的函数式接口?为什么需要它们?(★★☆)

:为了避免自动装箱拆箱的性能损耗,Java为基本类型提供了特化的函数式接口,例如:

  • IntConsumerLongConsumerDoubleConsumer(消费型)
  • IntSupplierLongSupplierDoubleSupplier(供给型)
  • IntFunction<R>LongFunction<R>DoubleFunction<R>(函数型)

⚠️ 性能优化点:处理大量基本类型数据时,优先使用特化接口,避免频繁装箱拆箱。

四、Stream流

Q11:Stream流的定义和核心特点是什么?(★★★)

:Stream是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。

核心特点

  1. 不存储数据:只是对数据进行计算,不保存元素
  2. 不改变源数据:所有操作都会生成一个新的流
  3. 惰性求值:只有调用终止操作时,中间操作才会执行
  4. 一次性消费:流只能使用一次,使用后会自动关闭

Q12:Stream流的操作流程是什么?中间操作和终止操作有什么区别?(★★★)

:操作流程:数据源 -> 中间操作1 -> 中间操作2 -> ... -> 终止操作

区别 中间操作 终止操作
返回值 返回新的Stream流 返回非流类型(集合、数值、布尔值等)
执行时机 惰性求值,不立即执行 立即执行,触发所有中间操作
链式调用 可以链式调用多个 只能有一个,是流的最后一步
流状态 流仍然可用 流关闭,不可再用

Q13:map()flatMap()有什么区别?(★★★)

  • map()一对一映射,将流中的每个元素转换为另一个元素,返回Stream<R>
  • flatMap()一对多映射,将流中的每个元素转换为一个流,然后将所有流"扁平化"为一个流,返回Stream<R>

示例

List<String> words=Arrays.asList("hello","world");
// map:返回Stream<Stream<Character>>
Stream<Stream<Character>> stream1=words.stream().map(word->word.chars().mapToObj(c->(char)c));
// flatMap:返回Stream<Character>
Stream<Character> stream2=words.stream().flatMap(word->word.chars().mapToObj(c->(char)c));

Q14:reduce()collect()有什么区别?(★★☆)

:两者都是终止操作,用于将流中的元素聚合为一个结果:

  • reduce()不可变聚合,将流中的元素逐个累加,最终返回一个值
  • collect()可变聚合,将流中的元素收集到一个可变容器(如List、Set、Map)中

适用场景

  • reduce:适合简单的数值计算(求和、求最大值、求最小值)
  • collect:适合复杂的集合转换(分组、分区、拼接字符串)

Q15:并行流的底层原理是什么?使用时需要注意什么?(★★★)


底层原理:并行流基于Fork/Join框架实现,将大任务拆分成多个小任务,分配给多个线程并行执行,最后合并结果。

使用注意事项

  1. 线程安全:避免在并行流中修改共享变量
  2. 无状态操作:中间操作必须是无状态的,否则会导致结果不确定
  3. 数据量:数据量小时不建议使用,线程切换开销大于并行收益
  4. 避免阻塞:不要在并行流中执行阻塞操作(如IO操作)

Q16:Java 9-21对Stream流有哪些重要增强?(★★☆)

  • Java 9takeWhile()(取满足条件的元素直到不满足)、dropWhile()(跳过满足条件的元素直到不满足)、ofNullable()(创建包含单个元素或空的流)、iterate()重载方法(支持终止条件)
  • Java 10Collectors.toUnmodifiableList()/toUnmodifiableSet()/toUnmodifiableMap()(返回不可变集合)
  • Java 12Collectors.teeing()(合并两个收集器的结果)
  • Java 16Stream.toList()(简化集合转换,返回不可变列表,推荐替代Collectors.toList()

五、Optional

Q17:Optional的设计思想和作用是什么?(★★★)

:Optional是一个容器类,用于包装可能为null的值。它的设计思想是强制开发者显式处理空值情况,从根本上避免空指针异常(NPE)。

Q18:创建Optional的三种方法是什么?有什么区别?(★★★)

  1. Optional.of(T value):创建包含非null值的Optional
    • ⚠️ 如果value为null,直接抛出NPE
  2. Optional.ofNullable(T value):创建可能包含null值的Optional
    • ✅ 推荐使用,无论value是否为null都不会抛出异常
  3. Optional.empty():创建一个空的Optional

Q19:获取Optional值的四种方法是什么?有什么区别?(★★★)

方法 作用 空值处理 执行时机 推荐度
get() 获取Optional中的值 抛出NoSuchElementException - ❌ 不推荐
orElse(T other) 有值返回,否则返回other 返回默认值 无论是否有值,other都会执行 ⚠️ 谨慎使用
orElseGet(Supplier<T> other) 有值返回,否则返回other.get() 返回默认值 只有为空时才执行 ✅ 推荐
orElseThrow(Supplier<X> exception) 有值返回,否则抛出指定异常 抛出业务异常 只有为空时才执行 ✅ 强烈推荐

⚠️ 易错点orElse()即使Optional有值,也会执行括号内的代码(如创建对象、查询数据库),造成不必要的性能损耗。

Q20:Optional的map()flatMap()有什么区别?(★★☆)

  • map(Function<T, R> mapper):如果有值,执行mapper并返回Optional<R>
  • flatMap(Function<T, Optional<R>> mapper):如果有值,执行mapper并直接返回Optional<R>(不会嵌套)

示例

// map:返回Optional<Optional<String>>
Optional<Optional<String>> city1=user.map(User::getAddress).map(Address::getCity);
// flatMap:返回Optional<String>
Optional<String> city2=user.flatMap(User::getAddress).flatMap(Address::getCity);

Q21:Optional的最佳实践和常见错误是什么?(★★★)

✅ 最佳实践

  1. 使用链式调用处理多层嵌套的空值
  2. 使用ifPresent()执行存在时的操作
  3. 使用orElseThrow()抛出业务异常
  4. 使用orElseGet()获取默认值

❌ 常见错误

  1. isPresent()判断后调用get()(和直接判空没有区别)
  2. 用Optional作为方法参数类的字段
  3. 调用get()方法(除非100%确定Optional不为空)
  4. Optional.of(null)(会直接抛出NPE)

Q22:Java 9-21对Optional有哪些重要增强?(★★☆)

  • Java 9ifPresentOrElse()(有值执行第一个操作,否则执行第二个)、or()(为空时返回另一个Optional)、stream()(将Optional转换为Stream)
  • Java 10orElseThrow()(无参,空时抛出NoSuchElementException
  • Java 11isEmpty()(判断是否为空,与isPresent()相反)

六、综合高频考点

Q23:Stream和集合有什么区别?(★★☆)

  1. 存储方式:集合存储数据;Stream不存储数据,只进行计算
  2. 修改方式:集合可以添加、删除元素;Stream不改变源数据
  3. 执行方式:集合是立即执行;Stream是惰性求值
  4. 遍历次数:集合可以多次遍历;Stream只能遍历一次
  5. 并行支持:集合需要手动实现并行;Stream原生支持并行

Q24:如何避免Stream流的性能问题?(★★☆)

  1. 优先使用基本类型特化流IntStreamLongStreamDoubleStream),避免装箱拆箱
  2. 数据量小时使用串行流,数据量大时使用并行流
  3. 避免在中间操作中执行耗时操作
  4. 合理使用limit()skip()减少数据处理量
  5. 避免使用有状态的中间操作(如distinct()sorted()在并行流中性能较差)

七、易错点终极汇总

  1. Lambda表达式中不能修改局部变量的值
  2. Stream流只能使用一次,使用后会关闭
  3. orElse()无论是否有值都会执行,orElseGet()只有为空时才执行
  4. 并行流中使用有状态操作会导致结果不确定
  5. 不要用Optional.of(null),应该用Optional.ofNullable(null)
  6. 不要用isPresent()+get(),应该用链式调用
  7. 函数式接口只能有一个抽象方法,但可以有多个默认方法和静态方法
相关文章
|
20天前
|
安全 Java API
【Java基础】Java 8-21新特性:JDK21 LTS:虚拟线程、模式匹配switch、结构化并发、序列集合(附《思维导图》+《面试高频考点清单》)
本文系统梳理Java 8至21的演进脉络,聚焦JDK 21 LTS四大核心特性:虚拟线程(M:N轻量调度,百万级I/O并发)、模式匹配switch(类型+守卫+null安全)、结构化并发(父子任务生命周期绑定)、序列集合(统一有序集合操作)。兼顾版本战略、迁移实践与面试高频考点,助力高效掌握现代Java开发核心能力。
|
8天前
|
人工智能 缓存 弹性计算
阿里云服务器2核4G5M199元解析:独享型u1实例,性能、适用场景、购买和续费规则介绍
阿里云通用算力型u1实例(ecs.u1-c1m2.large)2核4G、5M带宽、80G ESSD Entry云盘,活动特惠价仅199元/年(官网价3498.36元),企业新老用户同享,续费同价至2027年3月31日,每人限购1台。该实例采用独享型架构,搭载Intel至强可扩展处理器,内网带宽1Gbit/s、收发包30万PPS、云盘IOPS 1万,性能稳定,适合企业官网、中小Web应用、轻量数据库及开发测试等场景。
|
6天前
|
SQL JSON 关系型数据库
企业级多模态分析计算引擎选型:阿里云 AnalyticDB MySQL 统一分析平台方案
阿里云AnalyticDB MySQL版是PB级云原生实时数据仓库,首创多模态统一分析引擎,单SQL原生支持SQL分析、向量检索、全文搜索与JSON分析,替代3–5套独立系统,综合成本降50%+,运维复杂度降80%,适用于AI+数据融合、多源异构统一查询等企业级场景。
139 17
企业级多模态分析计算引擎选型:阿里云 AnalyticDB MySQL 统一分析平台方案
|
20天前
|
缓存 弹性计算 应用服务中间件
高端网站搭建:Nginx 反向代理与动静分离架构配置详解
在现代企业级 Web 架构中,Nginx 凭借其极低的内存消耗和超强的高并发处理能力,成为了不可或缺的流量网关。特别是在阿里云 ECS 实例搭配 Alibaba Cloud Linux 3 的环境下,Nginx 能够充分利用操作系统的网络栈优化,实现惊人的吞吐量。 本文将详细介绍如何配置 Nginx 的反向代理与动静分离,将静态资源请求与动态接口请求完美剥离,从而大幅提升网站的整体响应速度。
|
20天前
|
安全 Java C++
【Java基础】集合框架: ConcurrentHashMap核心原理:JDK1.7 vs 1.8+ 区别、线程安全实现、分段锁 vs CAS+synchronized、扩容机制
ConcurrentHashMap是Java高并发场景下线程安全的哈希表实现,JDK1.7采用Segment分段锁(16段独立加锁),JDK1.8升级为CAS+synchronized细粒度桶锁,并引入红黑树与多线程协助扩容,显著提升性能与扩展性。
|
20天前
|
存储 安全 Java
【Java基础】集合框架: HashMap核心原理:JDK1.7 vs 1.8+ 区别、数据结构、哈希函数、扩容机制、put/get全流程、红黑树转换阈值(附《思维导图》+《面试高频考点清单》)
本文系统对比JDK1.7与1.8+中HashMap的底层原理,涵盖数据结构(数组+链表→+红黑树)、哈希函数、扩容机制、插入方式及并发问题等核心差异,助你深入理解性能优化逻辑与面试高频考点。
|
20天前
|
存储 缓存 安全
【Java基础】集合框架: ArrayList vs LinkedList 核心区别、扩容机制(附《思维导图》+《面试高频考点清单》)
本文深入解析ArrayList与LinkedList的核心差异:前者基于动态数组,支持O(1)随机访问、尾部增删高效,但中间/头部操作需移动元素;后者基于双向链表,头部/尾部增删为O(1),但随机访问O(n)且内存开销大4–5倍。重点剖析ArrayList的1.5倍扩容机制及CPU缓存优势,澄清“LinkedList更适合队列”等常见误区。
|
15天前
|
算法 NoSQL Java
Java在分布式ID生成器(雪花算法)中的实现与优化
在分布式系统中,需要全局唯一、趋势递增、高性能的ID(如订单号、消息ID)。数据库自增ID在分库分表后不再唯一;UUID无序且过长,影响索引性能。
207 1
|
9天前
|
机器学习/深度学习 数据采集 人工智能
田间杂草检测数据集分享(适用于YOLO系列深度学习分类检测任务)
本数据集含4000张真实农田图像(小麦/玉米/水稻田),YOLO格式标注杂草目标,覆盖多天气、光照与视角,适用于YOLO系列等目标检测模型训练,助力智能除草与精准农业研究。(239字)
201 16
|
20天前
|
NoSQL Java 关系型数据库
吐血整理:2026大厂后端技术岗笔面试高频100题
本文揭秘2026大厂后端面试新趋势:题库未变,但考法剧变——从死记硬背转向考察源码理解、线上排障与设计权衡三大能力。通过真实案例对比与可落地的准备方法,帮你告别无效刷题,直击面试官真实意图。