原来Lambda表达式是这样写的
原来Lambda表达式是这样写的
lambda 是一个匿名函数,我们可以把 lambda 表达式理解为是一段可以传递的代码。
lambda 简明地将代码或方法作为参数传递进去执行。
函数式编程:核心是把函数作为值。
函数式接口 :只有一个抽象方法的接口称之为函数式接口。
函数式接口可以使用@FunctionalInterface
进行注解。
lambda表达式拆分为两部分:
-
左侧:lambda 表达式的参数列表
-
右侧:lambda 表达式中所需要执行的功能,即 lambda 体
Lambda 表达式非常方便,在项目中一般在 stream 编程中用的比较多。
package com.lambda;import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;public class Test1 {public static void main(String[] args) {List<Student> studentList = new ArrayList<>();studentList.add(new Student(1, "tom"));studentList.add(new Student(2, "marry"));// Collectors.toMap的用法有很多Map<Integer, String> map = studentList.stream().collect(Collectors.toMap(Student::getId, Student::getName));// {1=tom, 2=marry}System.out.println(map);}}class Student {private int id;private String name;public Student() {}public Student(int id, String name) {this.id = id;this.name = name;}public int getId() {return id;}public String getName() {return name;}public void setId(int id) {this.id = id;}public void setName(String name) {this.name = name;}
}
理解一个 Lambda 表达式就三步:
1、确认 Lambda 表达式的类型
2、找到要实现的方法
3、实现这个方法
就这三步,没其他的了。
1、确认 Lambda 表达式的类型
能用 Lambda 表达式来表示的类型,必须是一个函数式接口,而函数式接口,就是只有一个抽象方法的接口。
例如 JDK 中 Runnable 接口:
@FunctionalInterface
public interface Runnable {public abstract void run();
}
这就是一个标准的函数式接口,因为只有一个抽象方法
,而且这个接口上有个注解 @FunctionalInterface
。
这个仅仅是在编译期帮你检查你这个接口是否符合函数式接口的条件,比如你没有任何抽象方法,或者有多个抽象
方法,编译是无法通过的。
再稍稍复杂一点,Java 8 之后接口中是允许使用默认方法
和静态方法
的,而这些都不算抽象方法,所以也可以加在
函数式接口里。看看你可能不太熟悉又有点似曾相识的一个接口。
@FunctionalInterface
public interface Consumer<T> {void accept(T t);default Consumer<T> andThen(Consumer<? super T> after) {}
}
只有一个抽象方法,还有一个默认方法(方法体的代码省略了),这个也不影响它是个函数式接口。再看一个更复杂
的,多了静态方法,这同样也是个函数式接口,因为它仍然只有一个抽象方法。
@FunctionalInterface
public interface Predicate<T> {boolean test(T t);default Predicate<T> and(Predicate<? super T> other) {...}default Predicate<T> negate() {...}default Predicate<T> or(Predicate<? super T> other) {...}static <T> Predicate<T> isEqual(Object targetRef) {...}static <T> Predicate<T> not(Predicate<? super T> target) {...}
}
先不用管这些方法都是干嘛的,这些类在 Stream 设计的方法中比比皆是,我们就先记住这么一句话,Lambda表
达式需要的类型为函数式接口,函数式接口里只有一个抽象方法,就够了,以上三个例子都属于函数式接口。
2、找到要实现的方法
Lambda 表达式就是实现一个方法,什么方法呢?就是刚刚那些函数式接口中的抽象方法。
那就太简单了,因为函数式接口有且只有一个抽象方法,找到它就行了。我们尝试把刚刚那几个函数式接口的抽象
方法找到。
@FunctionalInterface
public interface Runnable {public abstract void run();
}@FunctionalInterface
public interface Consumer<T> {void accept(T t);default Consumer<T> andThen(Consumer<? super T> after) {...}
}@FunctionalInterface
public interface Predicate<T> {boolean test(T t);default Predicate<T> and(Predicate<? super T> other) {...}default Predicate<T> negate() {...}default Predicate<T> or(Predicate<? super T> other) {...}static <T> Predicate<T> isEqual(Object targetRef) {...}static <T> Predicate<T> not(Predicate<? super T> target) {...}
}
3、实现这个方法
Lambda 表达式就是要实现这个抽象方法,如果不用 Lambda 表达式,你一定知道用匿名类如何去实现吧?比如
我们实现刚刚 Predicate 接口的匿名类。
Predicate<String> predicate = new Predicate<String>() {@Overridepublic boolean test(String s) {return s.length() != 0;}
};
3.1 单个入参
那如果换成 Lambda 表达式呢?就像这样。
Predicate<String> predicate = (String s) -> {return s.length() != 0;
};
看出来了么?这个 Lambda 语法由三部分组成:
1、参数块:就是前面的 (String s),就是简单地把要实现的抽象方法的参数原封不动写在这。
2、小箭头:就是 -> 这个符号。
3、代码块:就是要实现的方法原封不动写在这。
首先看参数快部分,(String s) 里面的类型信息是多余的,因为完全可以由编译器推导,去掉它。
注意:lambda 表达式的参数类型可以省略不写,因为 jvm 编译器可以从上下文推断出数据类型。
即“类型推断”如果要在参数里面写数据类型,都要写上。
Predicate<String> predicate = (s) -> {return s.length() != 0;
};
当只有一个参数时,括号也可以去掉。
Predicate<String> predicate = s -> {return s.length() !=0;
};
再看代码块部分,方法体中只有一行代码,可以把花括号和 return 关键字都去掉。
Predicate<String> p = s -> s.length() != 0;
3.2 无入参
来,再让我们实现一个 Runnable 接口。
@FunctionalInterface
public interface Runnable {public abstract void run();
}
Runnable r = () -> System.out.println("I am running");
你看,这个方法没有入参,所以前面括号里的参数就没有了,这种情况下括号就不能省略。
通常我们快速新建一个线程并启动时,是不是像如下的写法,熟悉吧?
new Thread(() -> System.out.println("I am running")).start();
3.3 多个入参
之前我们只尝试了一个入参,接下来我们看看多个入参的。
@FunctionalInterface
public interface BiConsumer<T, U> {void accept(T t, U u);
}
然后看看一个用法,是不是一目了然。
BiConsumer<Random, Integer> randomNumberPrinter = (random, number) -> {for (int i = 0; i < number; i++) {System.out.println("next random = " + random.nextInt());}
};
randomNumberPrinter.accept(new Random(314L), 5);
3.4 带返回值
刚刚只是多个入参,那我们再加个返回值:
@FunctionalInterface
public interface BiFunction<T, U, R> {R apply(T t, U u);
}
BiFunction<String, String, Integer> findWordInSentence =(word, sentence) -> sentence.indexOf(word);
Integer result = findWordInSentence.apply("e","hello");
// 1
System.out.println(result);
4、四大核心函数式接口
其实函数式接口里那个抽象方法,无非就是入参的个数,以及返回值的类型。入参的个数可以是一个或者两个,返
回值可以是 void,或者 boolean,或者一个类型。那这些种情况的排列组合,就是 JDK 给我们提供的
java.util.function
包下的类。
别看晕了,我们分分类就好了。可以注意到很多类前缀是 Int,Long,Double 之类的,这其实是指定了入参的特
定类型,而不再是一个可以由用户自定义的泛型,比如说 DoubleFunction。
@FunctionalInterface
public interface DoubleFunction<R> {R apply(double value);
}
这完全可以由更自由的函数式接口 Function 来实现。
@FunctionalInterface
public interface Function<T, R> {R apply(T t);
}
函数式接口几个简单分类就是:
supplier: 没有入参,有返回值。
function: 有入参,有返回值。
consumer: 有入参,无返回值。
predicate: 有入参,返回 boolean 值。
Consumer: 消费性接口,void accept(T t)。
Supplier: 共给性接口,T get()。
Function<T,R>: 函数性接口,T代表参数,R代表返回值,R apply(T t)。
Predicate: 断言性接口,boolean test(T t)。
其实就是给我们提供了一个函数的模板,区别仅仅是入参返参个数的排列组合。
package com.lambda;import java.util.function.Consumer;public class Test2 {public static void main(String[] args) {happy(10000, (money) -> System.out.println("happy消费" + money + "元"));}public static void happy(double money, Consumer<Double> con) {con.accept(money);}
}
5、Stream编程
下面这段代码如果你项目中有用 stream 编程那肯定很熟悉,有一个 Student 的 list,你想把它转换成一个 map,
key 是 student 对象的 id,value 就是 student 对象本身。
package com.lambda;import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;public class Test3 {public static void main(String[] args) {List<Student> studentList = new ArrayList<>();studentList.add(new Student(1, "tom"));studentList.add(new Student(2, "marry"));// Collectors.toMap的用法有很多Map<Integer, Student> map = studentList.stream().collect(Collectors.toMap(Student::getId, a -> a, (a, b) -> a));// {1=com.lambda.Student@2f4d3709, 2=com.lambda.Student@4e50df2e}System.out.println(map);}
}
把 Lambda 表达式的部分提取出来。
Collectors.toMap(Student::getId, a -> a, (a, b) -> a)
由于我们还没见过 ::
这种形式,先打回原样,这里只是让你预热一下。
Collectors.toMap(a -> a.getId(), a -> a, (a, b) -> a)
为什么它被写成这个样子呢?我们看下 Collectors.toMap 这个方法的定义就明白了。
public static <T, K, U>
Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,Function<? super T, ? extends U> valueMapper,BinaryOperator<U> mergeFunction) {return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new);
}
看,入参有三个,分别是 Function,Function,BinaryOperator,其中 BinaryOperator 只是继承了 BiFunction
并扩展了几个方法,我们没有用到,所以不妨就把它当做 BiFunction。还记得 Function 和 BiFunction 吧?
Function R apply(T t)
BiFunction R apply(T t, U u)
第一个参数 a -> a.getId()
就是 R apply(T t) 的实现,入参是 Student 类型的对象 a,返回 a.getId()。
第二个参数 a -> a
也是 R apply(T t) 的实现,入参是 Student 类型的 a,返回 a 本身。
第三个参数 (a, b) -> a
是 R apply(T t, U u) 的实现,入参是Student 类型的 a 和 b,返回是第一个入参 a,
Stream 里把它用作当两个对象 ,a 和 b 的 key 相同时,value 就取第一个元素 a,其中第二个参数 a -> a 在
Stream 里表示从 list 转为 map 时的 value 值,就用原来的对象自己,你肯定还见过这样的写法。
Collectors.toMap(a -> a.getId(), Function.identity(), (a, b) -> a)
为什么可以这样写,给你看 Function 类的全貌你就明白了。
@FunctionalInterface
public interface Function<T, R> {R apply(T t);default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {Objects.requireNonNull(before);return (V v) -> apply(before.apply(v));}default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {Objects.requireNonNull(after);return (T t) -> after.apply(apply(t));}static <T> Function<T, T> identity() {return t -> t;}
}
看到了吧,identity 这个方法,就是帮我们把表达式给实现了,就不用我们自己写了,其实就是包了个方法。这回
知道一个函数式接口,为什么有好多还要包含一堆默认方法和静态方法了吧?就是干这个事用的。
我们再来试一个,Predicate 里面有这样一个默认方法 and。
@FunctionalInterface
public interface Predicate<T> {boolean test(T t);default Predicate<T> and(Predicate<? super T> other) {Objects.requireNonNull(other);return (t) -> test(t) && other.test(t);}default Predicate<T> negate() {return (t) -> !test(t);}default Predicate<T> or(Predicate<? super T> other) {Objects.requireNonNull(other);return (t) -> test(t) || other.test(t);}static <T> Predicate<T> isEqual(Object targetRef) {return (null == targetRef)? Objects::isNull: object -> targetRef.equals(object);}
}
它能干嘛用呢?我来告诉你,如果没有这个方法,有一段代码你可能会这样写。
Predicate<String> p = s -> (s != null) && !s.isEmpty() && s.length() < 5;
如果利用上这个方法,就可以变成如下这种优雅形式。
Predicate<String> nonNull = s -> s != null;
Predicate<String> nonEmpty = s -> s.isEmpty();
Predicate<String> shorterThan5 = s -> s.length() < 5;
Predicate<String> p = nonNull.and(nonEmpty).and(shorterThan5);
6、Lambda方法引用
主要有三种语法格式:
对象::实例方法名
类::静态方法名
类::实例方法名
那我们回过头再看刚刚的 Student::getId
这种写法。当方法体中只有一个方法调用时,就可以作这样的简化。
比如这个 a -> a.getId() 就只是对 Student 对象上 getId() 这个方法的调用,那么就可以写成 Student::getId 这种形
式。
package com.lambda;import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;public class Test9 {public static void main(String[] args) {// 类::实例方法名Function<User, String> n = User::getName;Function<User, Integer> a = User::getAge;// 类::静态方法名Function<String, String> func1 = User::concat2;Supplier<String> func2 = User::getAddress;// 对象::实例方法名User user = new User();Function<String, String> func3 = user::concat1;Supplier<String> func4 = user::getSchool;// 无参构造方法引用Supplier<Student> supplier = Student::new;Student student = supplier.get();student.setName("tom");student.setId(10);// com.lambda.Student@5b480cf9System.out.println(student);Supplier<Student> supplier2 = () -> (new Student());Student student2 = supplier2.get();student2.setName("tom");student2.setId(10);// com.lambda.Student@723279cfSystem.out.println(student2);// 有参构造方法引用BiFunction<Integer, String, Student> biFunction = Student::new;Student stu = biFunction.apply(11, "marry");// com.lambda.Student@b4c966aSystem.out.println(stu);BiFunction<Integer, String, Student> bf = (id, name) -> new Student(id, name);Student s = bf.apply(12, "john");// com.lambda.Student@4e50df2eSystem.out.println(s);// 自定义有参构造函数StudentBuilder sb1 = ((id, name) -> new Student(id, name));Student s1 = sb1.build(13, "xm");// com.lambda.Student@7cc355beSystem.out.println(s1);StudentBuilder sb2 = Student::new;Student s2 = sb2.build(14, "xh");// com.lambda.Student@12edcd21System.out.println(s2);// 自定义无参构造函数StudentBuilderNoArgs sb3 = Student::new;Student s3 = sb3.build();// com.lambda.Student@5b6f7412System.out.println(s3);StudentBuilderNoArgs sb4 = () -> (new Student());Student s4 = sb4.build();// com.lambda.Student@312b1daeSystem.out.println(s4);}
}class User {private static int id;private String name;public static int getId() {return id;}public static void setId(int id) {User.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String concat1(String str) {return str + "!";}public static String concat2(String str) {return str + "!";}public int getAge() {return 12;}public static String getAddress() {return "天津";}public String getSchool() {return "小学";}
}interface StudentBuilder {Student build(int id, String name);
}interface StudentBuilderNoArgs {Student build();
}
再看几个例子:
Function<String, Integer> toLength1 = s -> s.length();
Function<String, Integer> toLength2 = String::length;
Function<User, String> getName = user -> user.getName();
Function<User, String> toLength = User::getName;
如果是构造方法的话,也可以简化。
Supplier<List<String>> newListOfStrings1 = () -> new ArrayList<>();
Supplier<List<String>> newListOfStrings2 = ArrayList::new;
// ClassName::new
Supplier<String> sup = () -> new String();
Supplier<String> sup2 = String::new;
String str = sup.get();
String str2 = sup2.get();
// false
System.out.println(str == str2);
// 对象::实例方法名
Consumer<String> con = (x) -> System.out.println(x);
con.accept("hello");
Consumer<String> con2 = System.out::println;
con2.accept("world");
// 类::静态方法名
Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
Comparator<Integer> com2 = Integer::compare;
System.out.println(com.compare(1, 2));
System.out.println(com2.compare(1, 2));
// 类::实例方法名
BiPredicate<String, String> bp = (x, y) -> x.equals(y);
System.out.println(bp.test("a", "a"));
BiPredicate<String, String> bp2 = String::equals;
System.out.println(bp2.test("a", "a"));
7、Lambda例子
实例1:
package com.lambda;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;public class Test6 {public static List<Employee> list = Arrays.asList(new Employee("张三", 10, 1), new Employee("里斯", 20, 1), new Employee("王五", 16, 1), new Employee("二三", 30, 1));public static List<Employee> filterEmployee(List<Employee> list, MyPredicate<Employee> mp) {List<Employee> emps = new ArrayList<>();for (Employee employee : list) {if (mp.test(employee)) {emps.add(employee);}}return emps;}public static void main(String[] args) {test1();test2();}public static void test1() {//需要使用自定义的方法List<Employee> list2 = filterEmployee(list, (e) -> e.getAge() >= 15);list2.stream().map(Employee::getName).forEach(System.out::println);}public static void test2() {//可以使用stream进行list集合的过滤 不使用自定义接口List<Employee> list2 = list.stream().filter((e) -> e.getAge() >= 15).collect(Collectors.toList());list2.stream().map(Employee::getName).forEach(System.out::println);}
}class Employee {private String name;private int age;private double salary;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public double getSalary() {return salary;}public void setSalary(double salary) {this.salary = salary;}public Employee(String name, int age, double salary) {this.name = name;this.age = age;this.salary = salary;}
}interface MyPredicate<T> {boolean test(T t);
}
# 程序输出
里斯
王五
二三
里斯
王五
二三
实例2:
创建一个MyFun接口使用@FunctionalInterface注解,并创建一个抽象方法Integer getValue(Integer num);在
Test类对变量进行某种操作。
package com.lambda;@FunctionalInterface
interface MyFun {Integer getValue(Integer num);
}public class Test7 {public static void test() {int a = 10;System.out.println(a);a = operation(a, num -> ++num);System.out.println(a);}public static void main(String[] args) {test();}/*** param1 num : 传入的整形数* param2 mf : 实现某种方式对 整形数 进行操作。**/public static Integer operation(Integer num, MyFun mf) {return mf.getValue(num);}
}
# 程序输出
10
11
package com.lambda;import java.util.Arrays;
import java.util.Collections;
import java.util.List;public class Test8 {public static List<Employee> list = Arrays.asList(new Employee("张三", 10, 1),new Employee("里斯", 20, 1),new Employee("王五", 16, 1),new Employee("二三", 30, 1));public static void test() {Collections.sort(list, (e1, e2) -> {if (e1.getAge() == e2.getAge()) {return e1.getName().compareTo(e2.getName());} else {//比较年龄大小return Integer.compare(e1.getAge(), e2.getAge());}});for (Employee e : list) {System.out.println(e);}}public static void main(String[] args) {test();}
}
# 程序输出
com.lambda.Employee@404b9385
com.lambda.Employee@6d311334
com.lambda.Employee@682a0b20
com.lambda.Employee@3d075dc0
相关文章:
原来Lambda表达式是这样写的
原来Lambda表达式是这样写的 lambda 是一个匿名函数,我们可以把 lambda 表达式理解为是一段可以传递的代码。 lambda 简明地将代码或方法作为参数传递进去执行。 函数式编程:核心是把函数作为值。 函数式接口 :只有一个抽象方法的接口称之…...

smartsofthelp 5.0 最专业的数据库优化工具,数据库配置优化,数据库高并发优化,SQL 语句优化...
下载地址:百度网盘 请输入提取码 SQL操作返回历史记录: 2023-08-21 20:42:08:220 输入:select version as 版本号 2023-08-21 20:42:08:223 输出:当前数据库实例版本号:Microsoft SQL Server 2012 - 11.0.2100.60 (X64) …...

智影 R100:首款三维Mesh建模的SLAM激光扫描仪
近年来,激光SLAM系统凭借其更加快速且准确获取更丰富信息的优势,迅速风靡测绘领域,让原本耗时耗力的外业测量变得更加高效。手持激光扫描仪作为基于激光SLAM技术衍生的众多产品之一,相较于架站式激光扫描仪更加轻巧便利࿰…...

Next.js - Loading UI and Streaming
特殊文件 loading.js 可帮助您使用 React Suspense 创建有意义的加载用户界面。使用此约定,您可以在加载路由段内容时显示来自服务器的即时加载状态。渲染完成后,新的内容会自动切换进来。 即时加载状态 即时加载状态是在导航时立即显示的后备用户界面…...

快速解决Ubuntu 中 wine 程序 中文显示为方块/显示错误/无法显示中文(2023)
解决办法就是在创建prefix的命令行里加上LANG“zh_CN.UTF8” 或 LC_ALL“zh_CN.UTF8”,并安装cjkfonts,即可。 1、生成prefix、安装cjk字体 以下是基本流程: 现在假定wine和winetricks已经装好, // 先创建一个prefix࿰…...

漏洞指北-VulFocus靶场专栏-中级02
漏洞指北-VulFocus靶场专栏-中级02 中级005 🌸thinkphp lang 命令执行(thinkphp:6.0.12)🌸step1:burp suite 抓包 修改请求头step2 修改成功,访问shell.php 中级006 🌸Metabase geojson任意文件…...
【开源三方库】bignumber.js:一个大数数学库
OpenHarmony(OpenAtom OpenHarmony简称“OpenHarmony”)三方库,是经过验证可在OpenHarmony系统上可重复使用的软件组件,可帮助开发者快速开发OpenHarmony应用。如果是发布到开源社区,称为开源三方库,开发者…...

【C++】iota函数 + sort函数实现基于一个数组的多数组对应下标绑定排序
目录 一、iota函数 1. 函数解析 ① 迭代器类型(补充) ② 头文件 ③ 参数 2. 函数用途与实例 二、sort函数 1、 函数解读 2、实现倒序排列 2.1 greater 与 less 模板参数 2.2 lambda表达式 三、下标绑定排序(zip) --- 833.字符串中的查找与替换 一、…...
C# window forms 进度条实现
在 C# Windows Forms 应用程序中,如果在后台执行长时间运行的任务,并希望同时更新进度条,可以使用多线程来实现。这将确保进度条的更新不会阻塞主线程,从而保持界面的响应性。以下是一个示例,演示了如何在后台执行任务…...

ListNode相关
目录 2. 链表相关题目 2.1 合并两个有序链表(简单):递归 2.2 删除排序链表中的重复元素(简单):一次遍历 2.3 两链表相加(中等):递归 2.4 删除链表倒数第N个节点&…...

docker的资源控制及docker数据管理
目录 一.docker的资源控制 1.CPU 资源控制 1.1 资源控制工具 1.2 cgroups有四大功能 1.3 设置CPU使用率上限 1.4 进行CPU压力测试 1.5 设置50%的比例分配CPU使用时间上限 1.6 设置CPU资源占用比(设置多个容器时才有效) 1.6.1 两个容器测试cpu 2&…...

通过请求头传数据向后端发请求
axios (get post请求、头部参数添加)傻瓜式入门axios_axiospost请求参数_web_blog的博客-CSDN博客...

产品流程图是什么?怎么做?
产品流程图是什么? 产品流程图是一种图形化的表达方式,用于描述产品开发、制造、销售、使用等各个阶段中涉及的流程、步骤和关系。它通过图形符号、箭头、文本等元素,展示了产品的各个环节之间的关联和顺序,通常被用于可视化产…...
面试之快速学习STL-map
关联式容器 包括 map、multimap、set 以及 multiset 这 4 种容器。和序列式容器区别: a . 关联式容器在存储元素时还会为每个元素在配备一个键,整体以键值对的方式存储到容器中。 b . 相比前者,关联式容器可以通过键值直接找到对应的元素&am…...
ES的索引结构与算法解析
提到ES,大多数爱好者想到的都是搜索引擎,但是明确一点,ES不等同于搜索引擎。不管是谷歌、百度、必应、搜狗为代表的自然语言处理(NLP)、爬虫、网页处理、大数据处理的全文搜索引擎,还是有明确搜索目的的搜索行为,如各大…...

32.Netty源码之服务端如何处理客户端新建连接
highlight: arduino-light 服务端如何处理客户端新建连接 Netty 服务端完全启动后,就可以对外工作了。接下来 Netty 服务端是如何处理客户端新建连接的呢? 主要分为四步: md Boss NioEventLoop 线程轮询客户端新连接 OP_ACCEPT 事件ÿ…...
代码随想录day11
20. 有效的括号 ● 力扣题目链接 ● 给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串,判断字符串是否有效。 ● 有效字符串需满足: ● 左括号必须用相同类型的右括号闭合。 ● 左…...
RabbitMQ实习面试题
RabbitMQ实习面试题 在 RabbitMQ 中,确保生产者消息正确发布以及确保消费者已经消费是非常重要的任务。以下是一些方法和策略,可以帮助您在 RabbitMQ 中实现这些目标: 确保生产者消息正确发布: 持久化消息:将消息设…...

Electron入门,项目运行,只需四步轻松搞定。
electron 简单介绍: 实现:HTML/CSS/JS桌面程序,搭建跨平台桌面应用。 electron 官方文档: [https://electronjs.org/docs] 本文是基于以下2篇文章且自行实践过的,可行性真实有效。 文章1: https://www.cnbl…...

【C++】visualstudio环境安装
记录了部分安装步骤,可能有点不全,参考下,需要的磁盘空间差不多20GB; 下载 https://visualstudio.microsoft.com/zh-hans/vs/ 下载完成: 双击进入安装状态: 根据自己的需求勾选安装项: 选择…...

测试微信模版消息推送
进入“开发接口管理”--“公众平台测试账号”,无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息: 关注测试号:扫二维码关注测试号。 发送模版消息: import requests da…...

Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...

三分算法与DeepSeek辅助证明是单峰函数
前置 单峰函数有唯一的最大值,最大值左侧的数值严格单调递增,最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值,最小值左侧的数值严格单调递减,最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...
LRU 缓存机制详解与实现(Java版) + 力扣解决
📌 LRU 缓存机制详解与实现(Java版) 一、📖 问题背景 在日常开发中,我们经常会使用 缓存(Cache) 来提升性能。但由于内存有限,缓存不可能无限增长,于是需要策略决定&am…...
关于uniapp展示PDF的解决方案
在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项: 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库: npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...
Vue 3 + WebSocket 实战:公司通知实时推送功能详解
📢 Vue 3 WebSocket 实战:公司通知实时推送功能详解 📌 收藏 点赞 关注,项目中要用到推送功能时就不怕找不到了! 实时通知是企业系统中常见的功能,比如:管理员发布通知后,所有用户…...

Qt的学习(一)
1.什么是Qt Qt特指用来进行桌面应用开发(电脑上写的程序)涉及到的一套技术Qt无法开发网页前端,也不能开发移动应用。 客户端开发的重要任务:编写和用户交互的界面。一般来说和用户交互的界面,有两种典型风格&…...

基于开源AI智能名片链动2 + 1模式S2B2C商城小程序的沉浸式体验营销研究
摘要:在消费市场竞争日益激烈的当下,传统体验营销方式存在诸多局限。本文聚焦开源AI智能名片链动2 1模式S2B2C商城小程序,探讨其在沉浸式体验营销中的应用。通过对比传统品鉴、工厂参观等初级体验方式,分析沉浸式体验的优势与价值…...