Java8的新特性——Stream与completableFuture详解

发布于:2024-11-02 ⋅ 阅读:(18) ⋅ 点赞:(0)

1.Stream

第一部分:Stream 综述

        什么是 Stream: Stream 是 Java 8 引入的用于处理集合的一种抽象工具,它允许我们以更简洁的方式进行数据操作。Stream 本身并不存储数据,而是用于对数据源(如集合、数组等)进行操作的管道。

适用场景: Stream 适用于需要对集合进行复杂数据处理的场景,如过滤、映射、排序、聚合等。它特别适合于处理大量数据时,可以简化代码并提高可读性。

好处

  1. 简洁性:通过声明式的 API,可以减少样板代码。
  2. 可读性:链式调用使得代码逻辑更加清晰。
  3. 性能优化:通过惰性求值和短路操作,可以避免不必要的计算。

第二部分:好处的示例代码对比

示例 1:命令式 vs 声明式

命令式方式

List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
List<String> result = new ArrayList<>();
for (String name : names) {
    if (name.length() > 3) {
        result.add(name);
    }
}
System.out.println(result); // 输出: [Alice, Charlie]

声明式方式

List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
List<String> result = names.stream()
    .filter(name -> name.length() > 3)
    .collect(Collectors.toList());
System.out.println(result); // 输出: [Alice, Charlie]

在这个对比中,声明式方式更加简洁,逻辑一目了然。

示例 2:使用 map 和 collect

命令式方式

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
List<String> uppercasedNames = new ArrayList<>();
for (String name : names) {
    uppercasedNames.add(name.toUpperCase());
}
System.out.println(uppercasedNames); // 输出: [ALICE, BOB, CHARLIE]

声明式方式

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
List<String> uppercasedNames = names.stream()
    .map(String::toUpperCase)
    .collect(Collectors.toList());
System.out.println(uppercasedNames); // 输出: [ALICE, BOB, CHARLIE]

第三部分:Stream 的并行 API

并行流: Java 8 提供的并行流使得我们可以通过简单的 API 使用多核处理器来提高性能。通过调用 parallelStream() 方法,可以轻松实现并行处理。

示例:使用并行流

List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");

List<String> filteredNames = names.parallelStream()
    .filter(name -> name.startsWith("A"))
    .collect(Collectors.toList());

System.out.println(filteredNames); // 输出: [Alice]

Fork/Join 框架: 并行流背后使用了 Fork/Join 框架,它通过将任务分解成多个子任务,利用多核 CPU 的优势来并行处理。具体来说,Fork/Join 框架使用了一个工作窃取算法,当某个线程完成任务时,它可以“窃取”其他线程的任务来处理。

  • Fork:将任务分解成更小的子任务。
  • Join:合并子任务的结果。

通过这些特性,Java 的并行流能够有效地利用系统资源,提高数据处理的效率。

总结

Stream API 通过简化数据处理过程,提高了代码的可读性和可维护性。而并行 API 则使得在多核处理器上进行高效的数据处理成为可能,进一步提升了性能。

2.completableFuture

第一部分:Future 的介绍

Future 是什么Future 是 Java 提供的一个接口,用于表示异步计算的结果。它提供了一种机制来在未来的某个时间点获取任务的执行结果。

异步: 异步编程指的是程序在执行某个操作时不需要等待该操作完成,而是可以继续执行其他操作。对于 Future 来说,提交的任务在一个独立的线程中执行,主线程可以继续工作,而不是被阻塞。

阻塞和轮询: 使用 Future 获取结果时,通常需要调用 get() 方法,这个方法会阻塞当前线程,直到任务完成。如果任务尚未完成,调用 get() 会导致线程进入等待状态,直到结果可用。这种阻塞操作可能导致性能问题。

不支持回调Future 本身不支持回调。当任务完成时,无法直接通知主线程,这会导致回调地狱的问题。如果需要在任务完成后执行某些操作,通常需要在主线程中进行轮询,检查任务是否完成,这种方法繁琐且不优雅。

第二部分:CompletableFuture 的拓展

CompletableFuture 是什么CompletableFutureFuture 的一个扩展,提供了更强大的功能,允许我们以非阻塞的方式处理异步计算结果。

回调方法CompletableFuture 提供了一系列回调方法,如 thenApply()thenAccept()thenRun(),允许我们在任务完成时定义要执行的操作。这使得编写异步代码变得更加简单和可读。

示例:传统的 Future 和 CompletableFuture 的对比

使用 Future

ExecutorService executor = Executors.newFixedThreadPool(1);
Future<Integer> future = executor.submit(() -> {
    Thread.sleep(1000); // 模拟长时间计算
    return 42;
});

// 阻塞获取结果
try {
    Integer result = future.get(); // 这里会阻塞
    System.out.println("Result: " + result);
} catch (InterruptedException | ExecutionException e) {
    e.printStackTrace();
}

使用 CompletableFuture

CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
    try {
        Thread.sleep(1000); // 模拟长时间计算
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return 42;
});

// 非阻塞获取结果,并定义回调
completableFuture.thenAccept(result -> System.out.println("Result: " + result));

回调地狱的改善: 传统的回调实现往往导致“回调地狱”,即代码层层嵌套,难以维护。CompletableFuture 通过链式调用的方式改善了这一问题,使得代码更清晰。

示例:使用 CompletableFuture 的链式调用

CompletableFuture.supplyAsync(() -> {
    // 计算过程
    return 42;
}).thenApply(result -> {
    // 处理结果
    return result * 2;
}).thenAccept(finalResult -> {
    // 最终处理
    System.out.println("Final Result: " + finalResult);
});

改善的原因CompletableFuture 能够改善回调地狱的原因在于它实现了两个接口:

  1. CompletionStage 接口

    • 提供了一系列的组合方法,可以实现非阻塞的回调。
    • 支持链式调用,减少嵌套。
  2. Future 接口

    • 保留了 Future 的所有特性,可以异步获取结果。

第三部分:总结

  CompletableFuture 是 Java 8 引入的重要特性,它在处理异步编程时提供了强大的功能,显著改善了传统 Future 的不足。通过回调方法和链式调用,CompletableFuture 使得异步编程更为简单和可读,有效避免了回调地狱的问题。

        在使用 CompletableFuture 时,我们可以轻松定义任务完成后的操作,而无需阻塞当前线程,提升了代码的效率和可维护性。


网站公告

今日签到

点亮在社区的每一天
去签到