告别冗长代码:Java Lambda 表达式如何简化你的编程
在现代软件开发中,高效和简洁的代码变得越来越重要。Java作为一门成熟而广泛使用的编程语言,一直在不断进化,以满足开发者的需求。Java 8的推出标志着一次重要的飞跃,其中最引人注目的特性之一便是Lambda表达式。
Lambda表达式为Java带来了函数式编程的灵活性,使得代码不仅更加简洁,还大大提升了可读性和维护性。不再需要冗长的匿名类,开发者可以用更少的代码完成更多的功能。对于那些致力于编写高效、简洁代码的开发者来说,掌握Lambda表达式是不可或缺的技能。
在本篇文章中,我们将深入探讨Java的Lambda表达式,揭示它的强大功能和应用场景。无论你是Java的初学者,还是有多年经验的老手,这篇文章都将带你领略Lambda表达式的魅力,帮助你在编程之旅中迈上新的台阶。
文章目录
- 1、Lambda表达式概述
- 1.1、Lambda表达式的简介
- 1.2、Lambda 表达式的基本语法
- 1.3、Lambda 表达式的基础示例
- 1.4、Lambda表达式的要求
- 2、函数式接口
- 2.1、什么是函数式接口
- 2.2、函数式接口的定义
- 2.3、主要的函数式接口
- 2.3.1、接口 `Predicate<T>`
- 2.3.2、接口 `Consumer<T>`
- 2.3.3、接口 `Function<T, R>`
- 2.3.4、接口 `Supplier<T>`
- 2.3.5、接口 `BiConsumer<T, U>`
- 2.3.6、接口 `BiFunction<T, U, R>`
- 2.3.7、接口 `UnaryOperator<T>`:
- 2.3.8、接口 `BinaryOperator<T>`:
- 3、Lambda 方法引用
- 3.1、Lambda 方法引用的介绍
- 3.2、静态方法引用
- 3.3、实例方法引用
- 3.4、特定类型的任意对象的实例方法引用
- 3.5、构造器引用
- 4、Lambda 变量捕获
- 4.1、变量捕获的类型
- 4.2、什么是 Effectively Final?
- 4.3、示例:捕获局部变量
- 4.4、不可以捕获的情况
- 4.5、捕获实例变量
- 5、Lambda 在集合当中的使用
- 5.1、`Collection` 新增接口
- 5.2、`List` 新增接口
- 5.3、`Set` 新增接口
- 5.4、`Map` 新增接口
1、Lambda表达式概述
1.1、Lambda表达式的简介
Java(SE)8 于 2014 年 3 月发布,引入了多个改进特性,其中 Lambda 表达式(Lambda expression,也可称为闭包(Closure))是最受欢迎的新特性之一。
Lambda 表达式允允许把函数作为一个方法的参数,允许在方法中传递代码块,从而实现更加灵活的编程方式。Lambda 表达式可以简化代码,减少样板代码的出现,并且使代码更加易读和易于维护。
Lambda 表达式允许我们通过表达式来代替功能接口。Lambda 表达式就和方法一样,它提供了一个正常的参数列表和一个使用这些参数的主体(body,可以是一个表达式或一个代码块)。
Lambda 表达式为 Java 添加了函数式编程的能力,简化了代码,使得编写简洁的代码成为可能。这一特性特别适用于对集合进行操作的场景。
1.2、Lambda 表达式的基本语法
Lambda 表达式基本上是一个简洁的表示匿名函数的方法,它不需要像匿名类那样繁琐。Lambda 表达式的语法如下:
code(parameters) -> expression 或 (parameters) -> { statements; }
其中 Lambda 表达式的三个组成部分:
- 参数列表(
parameters
):类似方法中的形参列表,这里的参数是函数式接口里的参数。这里的参数类型可以明确的声明,也可不声明而由 JVM 隐含的推断。另外如果只有一个参数,圆括号也可以省略; - 箭头(->):连接参数列表和 Lambda 主体,可理解为 “被用于” 的意思;
- Lambda 主体(
expression
或 {statements;
}):可以是表达式也可以代码块,是函数式接口里方法的实现。①、expression
:表达式,当 Lambda 体只有一条语句时可以是一个表达式或一个单独的语句;②、statements
:代码块,如果 Lambda 体包含多条语句,需要用花括号括起来。③、无论是表达式还是代码块,都可以返回一个值或者什么都不反回。
1.3、Lambda 表达式的基础示例
假设我们有一个字符串列表,我们想要对其排序。使用 Lambda 表达式前后的代码对比如下:
使用传统方法(匿名内部类):
List<String> names = Arrays.asList("Peter", "Anna", "Mike", "Xenia");Collections.sort(names, new Comparator<String>() {public int compare(String a, String b) {return a.compareTo(b);}
});
匿名内部类: 这里 new Comparator<String>() {...}
创建了一个 Comparator<String>
的匿名实现类。匿名内部类是没有类名的类,直接用其父类或要实现的接口作为其类型。
使用 Lambda 表达式:
List<String> names = Arrays.asList("Peter", "Anna", "Mike", "Xenia");Collections.sort(names, (String a, String b) -> {return a.compareTo(b);
});--- 或者更简洁Collections.sort(names, (a, b) -> a.compareTo(b));
1.4、Lambda表达式的要求
虽然说,Lambda 表达式可以在⼀定程度上简化接口的实现。但是,并不是所有的接口都可以使用 Lambda 表达式来简洁实现的。
Lambda 表达式毕竟只是⼀个匿名方法。当实现的接口中的方法过多或者多少的时候,Lambda 表达式都是不适用的。
Lambda 表达式,只能实现函数式接口。
2、函数式接口
2.1、什么是函数式接口
在 Java 中,函数式接口(Functional Interface)是指具有单一抽象方法的接口,但它可以有多个默认(default)或静态(static)方法。Java 8 引入了这个概念,主要是为了支持 Lambda 表达式,同时保持对老代码的兼容性。
函数式接口的特性:
- 单一抽象方法:这是函数式接口的核心特征,它意味着该接口中只有一个没有实现的方法;
- 默认方法:Java 8 允许在接口中实现方法,这些方法被称为默认方法。默认方法不影响接口的"函数式接口"状态,因为它们不是抽象的;
- 静态方法:接口还可以包含静态方法。这些方法同样不影响接口的函数式接口状态,因为静态方法也是具体实现的。
函数式接口提供了一种将功能逻辑作为数据传递的方式,极大地增强了 Java 在编写高效且简洁代码方面的能力。随着 Java 版本的迭代,函数式编程已成为开发中不可或缺的工具。
2.2、函数式接口的定义
在 Java 中,函数式接口通常通过 @FunctionalInterface
注解来表示。这个注解不是必需的,但它可以帮助编译器检查所标注的接口是否满足函数式接口的条件。标准的定义如下:
@FunctionalInterface
public interface MyFunctionalInterface {void execute();
}
2.3、主要的函数式接口
Java 8 引入了 java.util.function
包,这个包中定义了一系列的内建函数式接口,极大地方便了函数式编程的实践,特别是与 Lambda 表达式的结合使用。
2.3.1、接口 Predicate<T>
用途:Predicate<T>
接口定义一个参数的方法,返回布尔值。这通常用于判断或过滤数据。
方法签名:boolean test(T t);
示例:使用 Predicate<T>
过滤一个 List<String>
,移除不符合条件的元素。
List<String> names = Arrays.asList("Peter", "Anna", "Mike", "Xenia");
// 移除以"M"开头的名字
names.removeIf(name -> name.startsWith("M"));
2.3.2、接口 Consumer<T>
用途:Consumer<T>
接口定义单一输入参数的 accept 方法,不返回任何结果(void
返回类型),常用于在对象上执行某些操作,如打印数据。
方法签名:void accept(T t);
示例:使用 Consumer<T>
打印 List
中的每个元素。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
numbers.forEach(number -> System.out.println(number));
2.3.3、接口 Function<T, R>
用途:Function<T, R>
接口定义一个接受一个参数并产生结果的方法,常用于映射或转换数据。
方法签名:R apply(T t);
示例:将字符串转换为其长度。
List<String> names = Arrays.asList("Peter", "Anna", "Mike", "Xenia");
List<Integer> nameLengths = names.stream().map(name -> name.length()).collect(Collectors.toList());
2.3.4、接口 Supplier<T>
用途:Supplier<T>
不接受任何参数但返回一个值,并且这个值的类型是泛型 T
。它常用于延迟生成或提供值的场景。
方法签名:T get();
示例:提供当前时间的字符串格式。
Supplier<String> currentTime = () -> new SimpleDateFormat("HH:mm:ss").format(new Date());
System.out.println("Current Time: " + currentTime.get());
2.3.5、接口 BiConsumer<T, U>
用途:接受两个输入参数,无返回结果,用于两元素的操作。
方法签名:void accept(T t, U u);
示例:打印两个参数的和。
BiConsumer<Integer, Integer> add = (a, b) -> System.out.println("Sum: " + (a + b));
// 输出 Sum: 8
add.accept(5, 3);
2.3.6、接口 BiFunction<T, U, R>
用途:接受两个输入参数,返回一个结果,用于两元素的操作。
方法签名:R apply(T t, U u);
示例:计算两个参数的和。
BiFunction<Integer, Integer, Integer> add = (a, b) -> a + b;
// 计算 1+2 的结果
Integer sum = add.apply(1, 2);
2.3.7、接口 UnaryOperator<T>
:
用途:一种特殊类型的 Function
,输入参数类型和返回类型相同。
方法:T apply(T t);
示例:计算参数的平方并返回。
UnaryOperator<Integer> square = x -> x * x;
Integer result = square.apply(5);
2.3.8、接口 BinaryOperator<T>
:
用途:一种特殊类型的 BiFunction
,其中两个输入参数和返回类型都相同。
方法:T apply(T t1, T t2);
示例:计算两个参数的积并返回。
BinaryOperator<Integer> multiply = (a, b) -> a * b;
Integer product = multiply.apply(5, 3);
3、Lambda 方法引用
3.1、Lambda 方法引用的介绍
在 Java 中,方法引用是一种简化 lambda 表达式的写法,特别是当 lambda 表达式只是直接调用一个已存在的方法时。方法引用提供了一种更清晰、更简洁的方式来引用直接已存在的方法或构造器。
方法引用有四种主要的类型:
- 静态方法引用(ClassName::methodName);
- 实例方法引用(instance::methodName);
- 特定类型的任意对象的实例方法引用(ClassName::methodName);
- 构造器引用(ClassName::new)
3.2、静态方法引用
如果函数式接口的实现通过调用一个静态方法来完成,可以使用静态方法引用。
示例:
假设我们有以下静态方法:
public class MathOperations {public static int multiplyByTwo(int i) {return i * 2;}
}
我们可以这样使用方法引用替代相应的 lambda 表达式:
Function<Integer, Integer> timesTwo = MathOperations::multiplyByTwo;
// 输出 10
System.out.println(timesTwo.apply(5));
3.3、实例方法引用
当目标引用是一个实例的方法时,可以使用实例方法引用。
示例:
假设有一个非静态方法:
public class Printer {public void printUpperCase(String s) {System.out.println(s.toUpperCase());}
}
使用实例方法引用:
Printer printer = new Printer();
Consumer<String> printUpper = printer::printUpperCase;
// 输出 HELLO
printUpper.accept("hello");
3.4、特定类型的任意对象的实例方法引用
如果方法引用是针对特定类型的任意对象,可以使用 ClassName::methodName。
示例:
Function<String, String> upperFunct = String::toUpperCase;
// 输出 HELLO
System.out.println(upperFunct.apply("hello"));
这里,我们引用了 String
类的 toUpperCase
方法。
3.5、构造器引用
构造器引用与方法引用类似,但它调用的是类的构造器。
示例:
假设我们有以下类:
public class Person {private String name;public Person(String name) {this.name = name;}@Overridepublic String toString() {return "Person{name='" + name + "'}";}
}
使用构造器引用:
Function<String, Person> personCreator = Person::new;
Person p = personCreator.apply("John Doe");// 输出 Person{name='John Doe'}
System.out.println(p);
4、Lambda 变量捕获
Lambda 表达式与匿名内部类相似,它们都可以访问"外围"作用域中的变量。这种访问外围变量的行为称为"变量捕获"。
4.1、变量捕获的类型
在 Lambda 表达式中,可以捕获两种类型的变量:
-
实例变量和静态变量:Lambda 表达式内部可以自由使用实例变量和静态变量而不受任何限制,这些变量可以自由地被读取或修改;
-
局部变量:可以捕获外围方法的局部变量,但这些局部变量必须是事实上的最终变量(effectively final),即这些变量在初始化后不会再为它们赋新值。
4.2、什么是 Effectively Final?
一个变量如果被声明为 final
,那么它就是最终变量。即使变量没有被声明为 final
,但在初始化后从未改变过,那么这个变量也是事实上的最终变量。从 Java 8 开始,这样的未声明为 final
的变量也可以在 Lambda 表达式中被捕获。
4.3、示例:捕获局部变量
public class LambdaCaptureExample {public static void main(String[] args) {int num = 10;// Effectively final variableRunnable r = () -> System.out.println(num);// 输出 10r.run();}
}
在这个例子中,变量 num
虽然没有被声明为 final
,但在初始化之后没有再改变,所以它是事实上的最终变量,可以在 Lambda 表达式中被安全捕获。
4.4、不可以捕获的情况
如果尝试在 Lambda 表达式中捕获一个不是事实上的最终变量,编译器将会报错:
public class LambdaCaptureExample {public static void main(String[] args) {int num = 10;num = 20; // 修改变量,使其不再是 effectively finalRunnable r = () -> System.out.println(num); // 编译错误r.run();}
}
因为 num
在初始化后被修改,它不是一个事实上的最终变量,因此不能被 Lambda 表达式捕获。
4.5、捕获实例变量
实例变量与静态变量不需要是事实上的最终变量,它们可以在 Lambda 表达式内部被修改:
public class LambdaCaptureExample {private static int staticNum = 5;private int instanceNum = 5;public void test() {Runnable r = () -> {// 直接修改静态变量staticNum++; // 直接修改实例变量instanceNum++;// 输出 12System.out.println(staticNum + instanceNum); };r.run();}public static void main(String[] args) {new LambdaCaptureExample().test();}
}
5、Lambda 在集合当中的使用
Java 8 在 Collection
、List
、Set
、和 Map
接口中引入了多种新方法,这些方法大都利用 Lambda 表达式来提高编程效率和简化代码。
下面是这些接口中新增方法的详细介绍:
5.1、Collection
新增接口
Collection
接口是 List
和 Set
接口的父接口,因此在 Collection
中添加的方法也会影响到这两个接口。以下是新增的几个重要方法:
①、forEach(Consumer<? super T> action)
对每个元素执行指定的动作。这是内部迭代的一种形式,可以替代外部迭代(即使用 for-each 循环)
collection.forEach(System.out::println);
②、stream()
返回集合的顺序 Stream 表达形式,可以进行更复杂的聚合操作
collection.stream().filter(e -> e.startsWith("A")).forEach(System.out::println);
③、parallelStream()
返回集合的并行 Stream 表达形式,用于并行处理集合元素,适用于数据量大时的场景
collection.parallelStream().filter(e -> e.startsWith("A")).forEach(System.out::println);
④、removeIf(Predicate<? super E> filter)
根据指定的条件(Predicate 表达式)删除元素
// 删除所有空元素
collection.removeIf(e -> e.isEmpty());
⑤、spliterator()
提供了一种创建可分割迭代器(Spliterator)的方法,适用于 Stream 的并行分解
Spliterator<T> spliterator = collection.spliterator();
5.2、List
新增接口
除了继承自 Collection
接口的方法外,List
接口特有的新增方法主要包括:
①、sort(Comparator<? super E> c)
根据指定的比较器对列表进行排序,此方法直接修改原列表
list.sort(Comparator.naturalOrder());
②、replaceAll(UnaryOperator<E> operator)
根据指定的函数应用运算,替换每个元素
// 将所有字符串元素转换为大写
list.replaceAll(String::toUpperCase);
5.3、Set
新增接口
Set
接口没有特别的新增方法,它继承了 Collection
接口的所有新增方法,这包括 forEach
, stream
, parallelStream
, removeIf
, 和 spliterator
。
5.4、Map
新增接口
Map
接口在 Java 8 中增加了一系列非常有用的方法来简化常见的任务:
①、forEach(BiConsumer<? super K, ? super V> action)
对每个键值对执行指定的操作
map.forEach((key, value) -> System.out.println(key + ": " + value));
②、replaceAll(BiFunction<? super K, ? super V, ? extends V> function)
将每个元素替换为函数的结果
map.replaceAll((key, value) -> value.toUpperCase());
③、computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction)
如果键对应的值为 null
,则尝试计算新的映射,并插入到 Map
中
map.computeIfAbsent("key", k -> "New " + k);
④、computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)
如果键存在,则使用给定的重新映射函数计算其值
map.computeIfPresent("key", (k, v) -> v + " Updated");
⑤、compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)
对键进行重新计算,无论原来是否存在
map.compute("key", (k, v) -> (v == null) ? "New Value" : v + " Computed");
⑥、merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction)
将键映射到给定值和当前值(如果已存在)的重新映射结果
map.merge("key", "New Value", (v1, v2) -> v1 + ", " + v2);
这些方法使得对集合进行操作更加灵活和强大,特别是在需要对集合进行批量操作、计算或条件更新时。通过这些工具,Java的集合库更加贴近现代编程需求,使得代码不仅更简洁,而且性能也有所提升。
相关文章:

告别冗长代码:Java Lambda 表达式如何简化你的编程
在现代软件开发中,高效和简洁的代码变得越来越重要。Java作为一门成熟而广泛使用的编程语言,一直在不断进化,以满足开发者的需求。Java 8的推出标志着一次重要的飞跃,其中最引人注目的特性之一便是Lambda表达式。 Lambda表达式为J…...
不同生成式AI模型的优缺点(GAN,VAE,FLOW)
不同生成式人工智能模型的优缺点 近年来,生成式 AI 模型因其能够创建新的原创内容而备受关注。这些模型旨在生成类似于给定训练数据集的数据,从而产生逼真且富有创意的输出。了解不同类型的生成式 AI 模型及其优缺点对于研究人员、开发人员和用户做出明…...

VMware ESXi 8.0U2c macOS Unlocker OEM BIOS 集成网卡驱动 Marvell AQC 网卡定制版
VMware ESXi 8.0U2c macOS Unlocker & OEM BIOS 集成网卡驱动 Marvell AQC 网卡定制版 VMware ESXi 8.0U2c macOS Unlocker & OEM BIOS 集成网卡驱动和 NVMe 驱动 (集成驱动版) 发布 ESXi 8.0U2 集成驱动版,在个人电脑上运行企业级工作负载 请访问原文链…...

SpringCloud Consul基础入门与使用实践总结
【1】Consul简介 官网地址:https://www.consul.io/intro/index.html 下载地址:https://www.consul.io/downloads.html 中文文档:https://www.springcloud.cc/spring-cloud-consul.html ① 基础概念 Consul 是一套开源的分布式服务发现和…...

pdf拆分成有图和无图的pdf(方便打印)
pdf拆分成有图和无图的pdf(方便打印) 原因 打印图片要彩印,每次都要手动弄,打印的时候很麻烦; 随着打印次数的增加,时间就越来越多 为解决此问题,使用python写一个exe解决这个问题 历程 找一个python的GUI界面找到 t…...

通用树查找算法
想要一个树形控件来显示数据,却发现Racket的GUI库竟然没有提供这个控件。既然没有,那就自己手搓一个吧。没想到,在做这个控件中竟然有了新发现! 树形控件有一个功能是查找树中指定的节点。这就是接下来的故事的起点。 1 找外援 不…...
Flutter 中的 TableCell 小部件:全面指南
Flutter 中的 TableCell 小部件:全面指南 Flutter 是一个功能强大的 UI 框架,由 Google 开发,允许开发者使用 Dart 语言构建跨平台的移动、Web 和桌面应用。在 Flutter 的丰富组件库中,TableCell 是一个用于创建表格单元格的组件…...

clickhouse学习笔记(一)入门与安装
目录 一 、入门 简介 核心特性包括 1.1 列式存储 1.2 原生压缩 1.3 向量化执行引擎 1.4 DBMS 功能 1.5 分布式处理 1.6 高吞吐写入能力 1.7 实时分析 1.8 SQL支持 1.9 高度可扩展 1.10 数据分区与线程级并行 1.11 应用场景 1.12 不适用场景 二、ClickHouse单机版…...

【JavaEE精炼宝库】多线程(4)深度理解死锁、内存可见性、volatile关键字、wait、notify
目录 一、死锁 1.1 出现死锁的常见场景: 1.2 产生死锁的后果: 1.3 如何避免死锁: 二、内存可见性 2.1 由内存可见性产生的经典案例: 2.2 volatile 关键字: 2.2.1 volatile 用法: 2.2.2 volatile 不…...

使用Ollama+OpenWebUI部署和使用Phi-3微软AI大模型完整指南
🏡作者主页: 点击! 🤖AI大模型部署与应用专栏:点击! ⏰️创作时间:2024年6月6日23点50分 🀄️文章质量:96分 欢迎来到Phi-3模型的奇妙世界!Phi-3是由微软…...

k8s的ci/cd实践之旅
书接上回k8s集群搭建完毕,来使用它强大的扩缩容能力帮我们进行应用的持续集成和持续部署,整体的机器规划如下: 1.192.168.8.156 搭建gitlab私服 docker pull gitlab/gitlab-ce:latest docker run --detach --hostname 192.168.8.156 --publ…...

笔记96:前馈控制 + 航向误差
1. 回顾 对于一个 系统而言,结构可以画作: 如果采用 这样的控制策略,结构可以画作:(这就是LQR控制) 使用LQR控制器,可以通过公式 和 构建一个完美的负反馈系统; a a 但是有上…...
延时任务工具类
自定义工具类 package com.sxfoundation.task;import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.task.TaskRejectedException; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.spri…...

springboot下载grpc编译文件,报错缺少protoc-gen-grpc-java:1.34.1:exe不存在
报错如图所示 [ERROR] Then, install it using the command: [ERROR] mvn install:install-file -DgroupIdio.grpc -DartifactIdprotoc-gen-grpc-java -Dversion1.34.1 -Dclassifierwindows-x86_64 -Dpackagingexe -Dfile/path/to/file [ERROR] [ERROR] Alternatively, if yo…...

【面试干货】 非关系型数据库(NoSQL)与 关系型数据库(RDBMS)的比较
【面试干货】 非关系型数据库(NoSQL)与 关系型数据库(RDBMS)的比较 一、引言二、非关系型数据库(NoSQL)2.1 优势 三、关系型数据库(RDBMS)3.1 优势 四、结论 💖The Begin…...
JAVA学习-练习试用Java实现“简化路径”
问题: 给定一个字符串 path ,表示指向某一文件或目录的 Unix 风格 绝对路径 (以 / 开头),请将其转化为更加简洁的规范路径。 在 Unix 风格的文件系统中,一个点(.)表示当前目录本身…...

STM32——ADC篇(ADC的使用)
一、ADC的介绍 1.1什么是ADC ADC(Analogto-Digital Converter)模拟数字转换器,是将模拟信号转换成数字信号的一种外设。比如某一个电阻两端的是一个模拟信号,单片机无法直接采集,此时需要ADC先将短租两端的电…...

(文章复现)基于主从博弈的售电商多元零售套餐设计与多级市场购电策略
参考文献: [1]潘虹锦,高红均,杨艳红,等.基于主从博弈的售电商多元零售套餐设计与多级市场购电策略[J].中国电机工程学报,2022,42(13):4785-4800. 1.摘要 随着电力市场改革的发展,如何制定吸引用户选择的多类型零售套餐成为提升售电商利润的研究重点。为…...
深度评价GPT-4o:探索人工智能的新里程碑
在人工智能领域,OpenAI的GPT系列自推出以来就备受瞩目。GPT-4o作为该系列的最新版本,无疑是迄今为止最为强大的一代。它不仅在技术性能上有了质的飞跃,而且在应用的广泛性和深度上都展现出了惊人的潜力。本文将从版本对比、技术能力、使用体验…...

Linux命令篇(六):vi/vim专项
💝💝💝首先,欢迎各位来到我的博客,很高兴能够在这里和您见面!希望您在这里不仅可以有所收获,同时也能感受到一份轻松欢乐的氛围,祝您生活愉快! 文章目录 一、什么是vim二…...
React 第五十五节 Router 中 useAsyncError的使用详解
前言 useAsyncError 是 React Router v6.4 引入的一个钩子,用于处理异步操作(如数据加载)中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误:捕获在 loader 或 action 中发生的异步错误替…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...

C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...

SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...

C++:多态机制详解
目录 一. 多态的概念 1.静态多态(编译时多态) 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1).协变 2).析构函数的重写 5.override 和 final关键字 1&#…...

【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...

通过MicroSip配置自己的freeswitch服务器进行调试记录
之前用docker安装的freeswitch的,启动是正常的, 但用下面的Microsip连接不上 主要原因有可能一下几个 1、通过下面命令可以看 [rootlocalhost default]# docker exec -it freeswitch fs_cli -x "sofia status profile internal"Name …...

五子棋测试用例
一.项目背景 1.1 项目简介 传统棋类文化的推广 五子棋是一种古老的棋类游戏,有着深厚的文化底蕴。通过将五子棋制作成网页游戏,可以让更多的人了解和接触到这一传统棋类文化。无论是国内还是国外的玩家,都可以通过网页五子棋感受到东方棋类…...
Python 高级应用10:在python 大型项目中 FastAPI 和 Django 的相互配合
无论是python,或者java 的大型项目中,都会涉及到 自身平台微服务之间的相互调用,以及和第三发平台的 接口对接,那在python 中是怎么实现的呢? 在 Python Web 开发中,FastAPI 和 Django 是两个重要但定位不…...