当前位置: 首页 > article >正文

Java 8 CompletableFuture:异步编程的利器与最佳实践

目录

1. 创建异步任务

1.1 使用默认线程池

1.2 使用自定义线程池

2. 异步回调处理

2.1 thenApply 和 thenApplyAsync

2.2 thenAccept 和 thenAcceptAsync

2.3 thenRun 和 thenRunAsync

3. 异常处理

3.1 whenComplete 和 whenCompleteAsync

3.2 handle 和 handleAsync

4. 多任务组合

4.1 thenCombine 和 thenCombineAsync

4.2 thenAcceptBoth 和 thenAcceptBothAsync

4.3 runAfterBoth 和 runAfterBothAsync


以下是 CompletableFuture 的不同用法示例,包括注释、使用场景以及对比图:

1. 创建异步任务

1.1 使用默认线程池

// 使用 supplyAsync 创建一个有返回值的异步任务
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {// 模拟耗时任务try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}return "Hello, CompletableFuture!";
});
System.out.println(future.join()); // 阻塞等待任务完成并获取结果

使用场景:适用于简单的异步任务,不需要自定义线程池。

1.2 使用自定义线程池

ExecutorService customExecutor = Executors.newFixedThreadPool(4);// 使用 supplyAsync 创建一个有返回值的异步任务,并指定自定义线程池
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {// 模拟耗时任务try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}return "Hello, CompletableFuture with custom executor!";
}, customExecutor);
System.out.println(future.join()); // 阻塞等待任务完成并获取结果

使用场景:适用于需要对线程池进行精细控制的场景,例如限制线程数量或使用特定的线程池策略。

2. 异步回调处理

2.1 thenApply 和 thenApplyAsync

// 使用默认线程池
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello").thenApply(s -> s + " World"); // 同步回调
System.out.println(future1.join());// 使用自定义线程池
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "Hello", customExecutor).thenApplyAsync(s -> s + " World", customExecutor); // 异步回调
System.out.println(future2.join());

使用场景:适用于对异步任务的结果进行进一步处理,并且需要返回新的结果。 对比thenApply 是同步回调,与父任务共享线程;thenApplyAsync 是异步回调,可能会启动新的线程。

2.2 thenAccept 和 thenAcceptAsync

// 使用默认线程池
CompletableFuture<Void> future1 = CompletableFuture.supplyAsync(() -> "Hello").thenAccept(s -> System.out.println(s + " World")); // 同步回调
future1.join();// 使用自定义线程池
CompletableFuture<Void> future2 = CompletableFuture.supplyAsync(() -> "Hello", customExecutor).thenAcceptAsync(s -> System.out.println(s + " World"), customExecutor); // 异步回调
future2.join();

使用场景:适用于对异步任务的结果进行处理,但不需要返回新的结果。 对比thenAccept 是同步回调,与父任务共享线程;thenAcceptAsync 是异步回调,可能会启动新的线程。

2.3 thenRun 和 thenRunAsync

// 使用默认线程池
CompletableFuture<Void> future1 = CompletableFuture.supplyAsync(() -> "Hello").thenRun(() -> System.out.println("Task completed")); // 同步回调
future1.join();// 使用自定义线程池
CompletableFuture<Void> future2 = CompletableFuture.supplyAsync(() -> "Hello", customExecutor).thenRunAsync(() -> System.out.println("Task completed"), customExecutor); // 异步回调
future2.join();

使用场景:适用于在异步任务完成后执行某些操作,但不需要访问任务的结果。 对比thenRun 是同步回调,与父任务共享线程;thenRunAsync 是异步回调,可能会启动新的线程。

3. 异常处理

3.1 whenComplete 和 whenCompleteAsync

// 使用默认线程池
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {if (new Random().nextInt(2) == 0) {throw new RuntimeException("Error occurred");}return "Hello";
}).whenComplete((result, exception) -> {if (exception != null) {System.out.println("Exception: " + exception.getMessage());} else {System.out.println("Result: " + result);}
});
future1.join();// 使用自定义线程池
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {if (new Random().nextInt(2) == 0) {throw new RuntimeException("Error occurred");}return "Hello";
}, customExecutor).whenCompleteAsync((result, exception) -> {if (exception != null) {System.out.println("Exception: " + exception.getMessage());} else {System.out.println("Result: " + result);}
}, customExecutor);
future2.join();

使用场景:适用于需要在任务完成时(无论是正常完成还是异常完成)执行某些操作。 对比whenComplete 是同步回调,与父任务共享线程;whenCompleteAsync 是异步回调,可能会启动新的线程。

3.2 handle 和 handleAsync

// 使用默认线程池
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {if (new Random().nextInt(2) == 0) {throw new RuntimeException("Error occurred");}return "Hello";
}).handle((result, exception) -> {if (exception != null) {return "Default Value";}return result + " World";
});
System.out.println(future1.join());// 使用自定义线程池
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {if (new Random().nextInt(2) == 0) {throw new RuntimeException("Error occurred");}return "Hello";
}, customExecutor).handleAsync((result, exception) -> {if (exception != null) {return "Default Value";}return result + " World";
}, customExecutor);
System.out.println(future2.join());

使用场景:适用于需要对任务的结果或异常进行处理,并返回一个新的结果。 对比handle 是同步回调,与父任务共享线程;handleAsync 是异步回调,可能会启动新的线程。

4. 多任务组合

4.1 thenCombine 和 thenCombineAsync

// 使用默认线程池
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello").thenCombine(CompletableFuture.supplyAsync(() -> " World"), (s1, s2) -> s1 + s2);
System.out.println(future1.join());// 使用自定义线程池
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "Hello", customExecutor).thenCombineAsync(CompletableFuture.supplyAsync(() -> " World", customExecutor), (s1, s2) -> s1 + s2, customExecutor);
System.out.println(future2.join());

使用场景:适用于需要将两个异步任务的结果组合成一个新的结果。 对比thenCombine 是同步回调,与父任务共享线程;thenCombineAsync 是异步回调,可能会启动新的线程。

4.2 thenAcceptBoth 和 thenAcceptBothAsync

// 使用默认线程池
CompletableFuture<Void> future1 = CompletableFuture.supplyAsync(() -> "Hello").thenAcceptBoth(CompletableFuture.supplyAsync(() -> " World"), (s1, s2) -> System.out.println(s1 + s2));
future1.join();// 使用自定义线程池
CompletableFuture<Void> future2 = CompletableFuture.supplyAsync(() -> "Hello", customExecutor).thenAcceptBothAsync(CompletableFuture.supplyAsync(() -> " World", customExecutor), (s1, s2) -> System.out.println(s1 + s2), customExecutor);
future2.join();

使用场景:适用于需要对两个异步任务的结果进行处理,但不需要返回新的结果。 对比thenAcceptBoth 是同步回调,与父任务共享线程;thenAcceptBothAsync 是异步回调,可能会启动新的线程。

4.3 runAfterBoth 和 runAfterBothAsync

// 使用默认线程池
CompletableFuture<Void> future1 = CompletableFuture.supplyAsync(() -> "Hello").runAfterBoth(CompletableFuture.supplyAsync(() -> " World"), () -> System.out.println("Both tasks completed"));
future1.join();// 使用自定义线程池
CompletableFuture<Void> future2 = CompletableFuture.supplyAsync(() -> "Hello", customExecutor).runAfterBothAsync(CompletableFuture.supplyAsync(() -> " World", customExecutor), () -> System.out.println("Both tasks completed"), customExecutor);
future2.join();

使用场景:适用于在两个异步任务都完成后执行某些操作,但不需要访问任务的结果。 对比runAfterBoth 是同步回调,与父任务共享线程;runAfterBothAsync 是异步回调,可能会启动新的线程。

 5.等待多个任务完成执行某个操作

CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {  // 第一个异步操作  
});  CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> {  // 第二个异步操作  
});  
CompletableFuture<Void> allFutures = CompletableFuture.allOf(future1, future2);  
allFutures.join(); // 阻塞直到所有异步操作完成  
// 或者使用 thenRun 来在所有操作完成后执行某些操作  
allFutures.thenRun(() -> System.out.println("All operations completed!"));
// 多线程分块处理
List<CompletableFuture<List<FtbCultivatePositionOrgStatisticesVO>>> futures = new ArrayList<>();
// 使用CompletableFuture.allOf等待所有任务完成
CompletableFuture<Void> allTasks = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
// 等待所有任务完成
allTasks.join();
// 收集所有任务的结果
List<FtbCultivatePositionOrgStatisticesVO> results = futures.stream().map(CompletableFuture::join).flatMap(Collection::stream).collect(Collectors.toList());
方法描述是否异步是否需要线程池返回值类型使用场景
supplyAsync创建一个有返回值的异步任务可选CompletableFuture<U>需要异步执行并返回结果的任务,如查询数据库。
runAsync创建一个无返回值的异步任务可选CompletableFuture<Void>需要异步执行但不需要返回结果的任务,如日志记录。
thenApply对任务结果进行处理,有返回值CompletableFuture<U>需要对任务结果进行转换或处理的场景,如数据格式转换。
thenApplyAsync对任务结果进行异步处理,有返回值可选CompletableFuture<U>需要对任务结果进行复杂处理且不想阻塞当前线程的场景。
thenAccept对任务结果进行处理,无返回值CompletableFuture<Void>需要对任务结果进行处理但不需要返回值的场景,如打印日志。
thenAcceptAsync对任务结果进行异步处理,无返回值可选CompletableFuture<Void>需要对任务结果进行处理但不需要返回值,且不想阻塞当前线程的场景。
thenRun任务完成后执行的操作,无入参,无返回值CompletableFuture<Void>任务完成后需要执行某些操作但不需要访问任务结果的场景。
thenRunAsync任务完成后异步执行的操作,无入参,无返回值可选CompletableFuture<Void>任务完成后需要执行某些操作但不需要访问任务结果,且不想阻塞当前线程的场景。
whenComplete任务完成后执行的操作,可以访问任务结果或异常CompletableFuture<T>需要在任务完成后执行某些操作,无论任务是否成功。
whenCompleteAsync任务完成后异步执行的操作,可以访问任务结果或异常可选CompletableFuture<T>需要在任务完成后执行某些操作,且不想阻塞当前线程。
handle任务完成后执行的操作,可以访问任务结果或异常,有返回值CompletableFuture<U>需要在任务完成后根据结果或异常返回新的值。
handleAsync任务完成后异步执行的操作,可以访问任务结果或异常,有返回值可选CompletableFuture<U>需要在任务完成后根据结果或异常返回新的值,且不想阻塞当前线程。
thenCombine组合两个任务的结果,两个任务都完成后执行的操作,有返回值CompletableFuture<U>需要组合两个任务的结果并返回新的值。
thenCombineAsync组合两个任务的结果,两个任务都完成后异步执行的操作,有返回值可选CompletableFuture<U>需要组合两个任务的结果并返回新的值,且不想阻塞当前线程。
thenAcceptBoth组合两个任务的结果,两个任务都完成后执行的操作,无返回值CompletableFuture<Void>需要组合两个任务的结果但不需要返回值。
thenAcceptBothAsync组合两个任务的结果,两个任务都完成后异步执行的操作,无返回值可选CompletableFuture<Void>需要组合两个任务的结果但不需要返回值,且不想阻塞当前线程。
runAfterBoth两个任务都完成后执行的操作,无入参,无返回值CompletableFuture<Void>两个任务完成后需要执行某些操作但不需要访问任务结果。
runAfterBothAsync两个任务都完成后异步执行的操作,无入参,无返回值可选CompletableFuture<Void>两个任务完成后需要执行某些操作但不需要访问任务结果,且不想阻塞当前线程。
applyToEither两个任务中任意一个完成后执行的操作,有返回值CompletableFuture<U>两个任务中任意一个完成后需要根据结果返回新的值。
applyToEitherAsync两个任务中任意一个完成后异步执行的操作,有返回值可选CompletableFuture<U>两个任务中任意一个完成后需要根据结果返回新的值,且不想阻塞当前线程。
acceptEither两个任务中任意一个完成后执行的操作,无返回值CompletableFuture<Void>两个任务中任意一个完成后需要执行某些操作但不需要返回值。
acceptEitherAsync两个任务中任意一个完成后异步执行的操作,无返回值可选CompletableFuture<Void>两个任务中任意一个完成后需要执行某些操作但不需要返回值,且不想阻塞当前线程。
runAfterEither两个任务中任意一个完成后执行的操作,无入参,无返回值CompletableFuture<Void>两个任务中任意一个完成后需要执行某些操作但不需要访问任务结果。
runAfterEitherAsync两个任务中任意一个完成后异步执行的操作,无入参,无返回值可选CompletableFuture<Void>两个任务中任意一个完成后需要执行某些操作但不需要访问任务结果,且不想阻塞当前线程。
allOf等待多个任务都完成,无返回值CompletableFuture<Void>需要等待多个任务都完成后才继续执行。
anyOf等待多个任务中任意一个完成,有返回值CompletableFuture<Object>多个任务中任意一个完成后需要根据结果返回新的值。

相关文章:

Java 8 CompletableFuture:异步编程的利器与最佳实践

目录 1. 创建异步任务 1.1 使用默认线程池 1.2 使用自定义线程池 2. 异步回调处理 2.1 thenApply 和 thenApplyAsync 2.2 thenAccept 和 thenAcceptAsync 2.3 thenRun 和 thenRunAsync 3. 异常处理 3.1 whenComplete 和 whenCompleteAsync 3.2 handle 和 handleAsync…...

Podman与行业趋势分析 ——兼论与Docker的对比及未来发展方向

1. Podman核心概念与架构解析 1.1 定义与定位 Podman&#xff08;Pod Manager&#xff09;是由Red Hat主导开发的开源容器引擎&#xff0c;遵循OCI&#xff08;Open Container Initiative&#xff09;标准&#xff0c;专注于提供无守护进程&#xff08;Daemonless&#xff09…...

摄影测量——单像空间后方交会

空间后方交会的求解是一个非线性问题&#xff0c;通常采用最小二乘法进行迭代解算。下面我将详细介绍具体的求解步骤&#xff1a; 1. 基本公式&#xff08;共线条件方程&#xff09; 共线条件方程是后方交会的基础&#xff1a; 复制 x - x₀ -f * [m₁₁(X-Xₛ) m₁₂(Y-…...

ros2_01

note01 ROS2和ROS最大的区别中间件 中间件&#xff1a; 介于某两个或者多个节点中间的组件&#xff1b;提供多个节点中间通信&#xff1b; ROS1&#xff1a;中间件是ROS组织自己基于TCP机制建立的&#xff0c;随着现在传感器的升级&#xff0c;数据量越来越大&#xff0c;原…...

C++中的高阶函数

C中的高阶函数 高阶函数是指可以接受其他函数作为参数或返回函数作为结果的函数。在C中&#xff0c;有几种方式可以实现高阶函数的功能&#xff1a; 1. 函数指针 #include <iostream>int add(int a, int b) { return a b; } int subtract(int a, int b) { return a -…...

计算机视觉与深度学习 | 钢筋捆数识别

===================================================== github:https://github.com/MichaelBeechan CSDN:https://blog.csdn.net/u011344545 ===================================================== 钢筋捆数 1、初始结果2、处理效果不佳时的改进方法‌1、预处理增强2、后…...

L3-027 可怜的复杂度(纯暴力)

暴力解答&#xff0c;肯定超时&#xff0c;因为我刚开始把所有答案&#xff0c;存到了ans这个vector里面了&#xff0c;然后进行枚举情况&#xff0c;后面发现因为这个阶数很高的时候&#xff0c;就会直接炸内存&#xff0c;所以我直接选择了在dfs里面进行统计答案&#xff0c;…...

基于RV1126开发板的人脸姿态估计算法开发

1. 人脸姿态估计简介 人脸姿态估计是通过对一张人脸图像进行分析&#xff0c;获得脸部朝向的角度信息。姿态估计是多姿态问题中较为关键的步骤。一般可以用旋转矩阵、旋转向量、四元数或欧拉角表示。人脸的姿态变化通常包括上下俯仰(pitch)、左右旋转(yaw)以及平面内角度旋转(r…...

鲲鹏+昇腾部署集群管理软件GPUStack,两台服务器搭建双节点集群【实战详细踩坑篇】

前期说明 配置&#xff1a;2台鲲鹏32C2 2Atlas300I duo&#xff0c;之前看网上文档&#xff0c;目前GPUstack只支持910B芯片&#xff0c;想尝试一下能不能310P也部署试试&#xff0c;毕竟华为的集群软件要收费。 系统&#xff1a;openEuler22.03-LTS 驱动&#xff1a;24.1.rc…...

【C#】CAN通信的使用

在C#中实现CAN通信通常需要借助第三方库或硬件设备的驱动程序&#xff0c;因为C#本身并没有直接内置支持CAN通信的功能。以下是一个关于如何使用C#实现CAN通信的基本指南&#xff0c;包括所需的步骤和常用工具。 1. 硬件准备 要进行CAN通信&#xff0c;首先需要一个支持CAN协…...

火山引擎旗下的产品

用户问的是火山引擎旗下的产品&#xff0c;我需要详细列出各个类别下的产品。首先&#xff0c;我得确认火山引擎有哪些主要业务领域&#xff0c;比如云计算、大数据、人工智能这些。然后&#xff0c;每个领域下具体有哪些产品呢&#xff1f;比如云计算方面可能有云服务器、容器…...

Elasticsearch 故障转移及水平扩容

一、故障转移 Elasticsearch 的故障转移&#xff08;Failover&#xff09;机制是其高可用性的核心&#xff0c;通过分布式设计、自动检测和恢复策略确保集群在节点故障时持续服务。 1.1 故障转移的核心组件 组件作用Master 节点管理集群状态&#xff08;分片分配、索引创建&…...

机器学习中 提到的张量是什么?

在机器学习中, 张量(Tensor) 是一个核心数学概念,用于表示和操作多维数据。以下是关于张量的详细解析: 一、数学定义与本质 张量在数学和物理学中的定义具有多重视角: 多维数组视角 传统数学和物理学中,张量被定义为多维数组,其分量在坐标变换时遵循协变或逆变规则。例…...

edge 更新到135后,Clash 打开后,正常网页也会自动跳转

发现了一个有意思的问题&#xff1a;edge 更新135后&#xff0c;以前正常使用的clash出现了打开deepseek也会自动跳转&#xff1a; Search Resultshttps://zurefy.com/zu1.php#gsc.tab0&gsc.qdeepseek &#xff0c;也就是不需要梯子的网站打不开了&#xff0c;需要的一直正…...

prime 1 靶场笔记(渗透测试)

环境说明&#xff1a; 靶机prime1和kali都使用的是NAT模式&#xff0c;网段在192.168.144.0/24。 Download (Mirror): https://download.vulnhub.com/prime/Prime_Series_Level-1.rar 一.信息收集 1.主机探测&#xff1a; 使用nmap进行全面扫描扫描&#xff0c;找到目标地址及…...

实验一 字符串匹配实验

一、实验目的 1&#xff0e;熟悉汇编语言编程环境和DEBUG调试程序的使用。 2&#xff0e;掌握键盘输入字符串的方法和分支程序的设计。 二、实验内容 编程实现&#xff1a;从键盘分别输入两个字符串&#xff0c;然后进行比较&#xff0c;若两个字符串的长度…...

跨境电商中的几种支付方式——T/T、L/C、D/P、D/A、O/A

在进行跨境电商的B端系统设计时&#xff0c;需要考虑的关键方面之一是支付流程。它为交易的成功奠定了基础&#xff0c;并确保涉及的双方都受到保护。 在本文中&#xff0c;我们将深入探讨各种常见支付方式的复杂性&#xff0c;包括电汇 (T/T)、信用证 (L/C)、付款交单 (D/P)、…...

第16届蓝桥杯单片机模拟试题Ⅲ

试题 代码 sys.h #ifndef __SYS_H__ #define __SYS_H__#include <STC15F2K60S2.H> //sys.c extern unsigned char UI; //界面标志(0湿度界面、1参数界面、2时间界面) extern unsigned char time; //时间间隔(1s~10S) extern bit ssflag; //启动/停止标志…...

打造现代数据基础架构:MinIO对象存储完全指南

目录 打造现代数据基础架构&#xff1a;MinIO对象存储完全指南1. MinIO介绍1.1 什么是对象存储&#xff1f;1.2 MinIO核心特点1.3 MinIO使用场景 2. MinIO部署方案对比2.1 单节点单驱动器(SNSD/Standalone)2.2 单节点多驱动器(SNMD/Standalone Multi-Drive)2.3 多节点多驱动器(…...

OOM问题排查和解决

问题 java.lang.OutOfMemoryError: Java heap space 排查 排查手段 jmap命令 jmap -dump,formatb,file<file-path> <pid> 比如 jmap -dump:formatb,file./heap.hprof 44532 使用JVisualVM工具&#xff1a; JVisualVM是一个图形界面工具&#xff0c;它可以帮…...

OSI 七层模型与 TCP/IP 协议栈详解

OSI 七层模型与 TCP/IP 协议栈详解 网络协议模型是理解计算机网络和通信的基础&#xff0c;而 OSI 七层模型和 TCP/IP 协议栈是最常见的两种网络通信模型。虽然这两者有些不同&#xff0c;但它们都提供了一种分层的结构&#xff0c;帮助我们理解和设计网络通信。本文将详细介绍…...

「出海匠」借助CloudPilot AI实现AWS降本60%,支撑AI电商高速增长

&#x1f50e;公司简介 「出海匠」&#xff08;chuhaijiang.com&#xff09;是「数绘星云」公司打造的社交内容电商服务平台&#xff0c;专注于为跨境生态参与者提供数据支持与智能化工作流。平台基于大数据与 AI 技术&#xff0c;帮助商家精准分析市场趋势、优化运营策略&…...

LeetCode[541]反转字符串Ⅱ

思路&#xff1a; 题目给我们加了几个规则&#xff0c;剩余长度小于2k&#xff0c;大于等于k就反转k个&#xff0c;小于k就全部反转&#xff0c;我们按照这个逻辑来就行。 第一就是大于等于k就反转k个&#xff0c;我们for循环肯定是i2k了&#xff0c;接下来就是判断是否大于等于…...

队列的各种操作实现(数据结构C语言多文件编写)

1.先创建queue.h声明文件(Linux命令&#xff1a;touch queue.h)。编写函数声明如下(打开文件 Linux 操作命令&#xff1a;vim queue.h): //头文件 #ifndef __QUEUE_H__ #define __QUEUE_H__ //队列 typedef struct queue{int* arr;int in;int out;int cap;int size; }queue_t;…...

# Unity动画控制核心:Animator状态机与C#脚本实战指南 (Day 29)

Langchain系列文章目录 01-玩转LangChain&#xff1a;从模型调用到Prompt模板与输出解析的完整指南 02-玩转 LangChain Memory 模块&#xff1a;四种记忆类型详解及应用场景全覆盖 03-全面掌握 LangChain&#xff1a;从核心链条构建到动态任务分配的实战指南 04-玩转 LangChai…...

C++中extern关键字

C中extern关键字的完整用法总结 extern是C中管理链接性&#xff08;linkage&#xff09;的重要关键字&#xff0c;主要用于声明外部定义的变量或函数。以下是详细的用法分类和完整示例&#xff1a; 一、基本用法 1. 声明外部全局变量 // globals.cpp int g_globalVar 42; …...

【Python爬虫】简单案例介绍3

本文继续接着我的上一篇博客【Python爬虫】简单案例介绍2-CSDN博客 目录 3.3 代码开发 3.3 代码开发 编写代码的步骤&#xff1a; request请求科普中国网站地址url&#xff0c;解析得到类名为"list-block"的div标签。 for循环遍历这个div列表里的每个div&#xff0…...

计算机视觉与深度学习 | 视觉里程计(Visual Odometry, VO)学习思路总结

视觉里程计(Visual Odometry, VO)学习思路总结 视觉里程计(VO)是通过摄像头捕获的图像序列估计相机运动轨迹的技术,广泛应用于机器人、自动驾驶和增强现实等领域。以下是一个系统的学习路径,涵盖基础理论、核心算法、工具及实践建议:一、基础理论与数学准备 核心数学工具…...

android面试情景题详解:android如何处理断网、网络切换或低速网络情况下的业务连续性

在移动互联网时代&#xff0c;Android应用已经成为人们日常生活中不可或缺的一部分。从社交媒体到在线购物&#xff0c;从移动办公到娱乐消费&#xff0c;几乎所有的服务都依赖于网络连接。然而&#xff0c;网络环境并非总是稳定可靠。断网、网络切换&#xff08;如从Wi-Fi切换…...

swift菜鸟教程6-10(运算符,条件,循环,字符串,字符)

一个朴实无华的目录 今日学习内容&#xff1a;1.Swift 运算符算术运算符比较运算符逻辑运算符位运算符赋值运算区间运算符其他运算符 2.Swift 条件语句3.Swift 循环4.Swift 字符串字符串属性 isEmpty字符串常量let 变量var字符串中插入值字符串连接字符串长度 String.count使用…...