一文涵盖Lambda,Stream,响应式编程,从此爱上高效率编程

news2024/11/24 7:50:42

一文涵盖Lambda,Stream,响应式编程,从此爱上高效率编程

前言

本文结构为 先是一个例子,带你快速体验,之后再去深究里面的方法。以及一些底层原理是如何实现的。从如何用,到如何用好,如何用精。学习操作,学习思维。

Lambda表达式

初体验

这个是Java8的新特性。来源于数学中的演算。

是一套关于函数定义、输入量、输出量的计算方案。

简单来说,Lambda表达式就是一个简单的函数。

首先来看一个案例。

这里有一个接口。

public interface Factory {
    Object getObject();
}

以及实现类


public class SubClass implements Factory{
    @Override
    public Object getObject() {
        return new User();

    }
}

实体类是:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private String name;
    private Integer age;
}

我们来看前俩种写法

public static void main(String[] args) {
    //1.子类实现接口
    Factory factory = new SubClass();
    User user1 = (User) factory.getObject();
    System.out.println(user1);

    //2.匿名内部类
    factory = new Factory() {
        @Override
        public Object getObject() {
            return new User("xiaou", 18);
        }
    };
    User user2 = (User) factory.getObject();
    System.out.println(user2);
}

之后我们来看一个lambda表达式的写法。

//3.Lambda表达式
factory = () -> {
    return new User("xiaou", 18);
};

可以看出来是非常的简单的

通过对比,我们可以看出这个是非常的简单的。

我们来说一下他的优点:

  • 让代码变得更加简洁、紧凑
  • 函数式编程:
    • 函数是"第一等公民",可以像一个变量一样去调用
    • 可以赋值给变量
    • 可以作为其他函数的参数就行传递
    • 可以作为其他函数的返回值

首先来看第三条

//lambda作为参数进行传递
User user4 = getUserFormFactory(() -> {
    return new User("xiaou", 20);
}, "User");
System.out.println(user4);
public static User getUserFormFactory(Factory factory, String beanName) {
    User object = (User) factory.getObject();
    if (object != null && object.getClass().getSimpleName().equals(beanName)) {
        return object;
    }
    return null;
}

来看第四条

public static Factory getFactory() {
    return () -> {
        return new User("xiaou", 21);
    };
}
//lambda作为参数返回值
Factory factory2 = getFactory();
User user5 = (User) factory2.getObject();
System.out.println(user5);

语法细节

image-20240412115135397

了解了语法,我们就可以进行一个改进对我们上面的案例。

//3.Lambda表达式
factory = () -> {
    return new User("xiaou", 19);
};
//改进版
factory = () -> new User("xiaou", 19);

如果你不知道什么时候应该简写,idea是可以去给你提醒的

image-20240412115421836

之后来看他的别的简写语法:

  • 函数体只有一个语句,省略大括号

      (String msg) -> System.out.println("hello" + msg);
    
  • 只有一个参数,省略圆括号,同时省略类型

    msg -> System.out.println("hello " + msg);
    
  • 函数体只有一个表达式,省略return

    (int a, int b) -> a + b;
    
  • 省略参数类型,编译器可以进行推断

    (a, b) -> a + b;
    

之后来看使用lambda表达式的前提。

使用前提

1.必须有一个函数式接口

函数式接口是Java中的一个关键概念,它指的是具有以下特征的接口:

  • 必须有一个抽象方法:这是函数式接口的核心 特征,接口中只有一个抽象方法。
  • @FunctionalInterface注解:虽然这个注解不是必须的,但它可以用来明确标识一个接口是函数式接口,同时提供编译时检查。

2.常见的函数式接口

Java API提供了多个预定义的函数式接口,这些接口广泛应用于函数式编程中,它们包括:

  • Runnable / Callable:用于表示没有返回值的可执行任务,Callable还可以返回一个值并抛出异常。
  • Supplier:表示一个不带参数但可以产生结果的操作。
  • Consumer:表示一个接受单个参数并返回无内容的操作,通常用于处理输入的数据。
  • Comparator:用于定义对象比较逻辑。
  • Predicate:表示一个参数的谓词(布尔值函数),用于判断一个对象是否满足某个条件。
  • Function:表示一个参数并返回结果的函数。

下面我们来详细讲解这些函数式接口

常见的函数式接口

Runnable
public static void main(String[] args) {
    new Thread(new Runnable() {
        @Override
        public void run() {
            String name = Thread.currentThread().getName();
            System.out.println(name + "正在运行1");
        }
    }).start();


    //lambda简化
    new Thread(() -> {
        String name = Thread.currentThread().getName();
        System.out.println(name + "正在运行2");
    }).start();
}
supplier
/**
 * 求数组最大值
 */
public class SupplierLambda {
    public static void main(String[] args) {
        int arr[] = {1, 2, 3, 4, 5};
        int max = getMax(() -> {
            int temp = arr[0];
            for (int i : arr) {
                if (i > temp) {
                    temp = i;
                }
            }
            return temp;
        });
        System.out.println(max);
    }

    public static int getMax(Supplier<Integer> supplier) {
        return supplier.get();
    }
}
Consumer

public class ConsumerLambda {
    public static void main(String[] args) {
        consumerString(str -> System.out.println(str));
        consumerString(
                s -> System.out.println(s.toUpperCase()),
                s -> System.out.println(s.toLowerCase())
        );
    }

    static void consumerString(Consumer<String> function) {
        function.accept("Hello");
    }

    static void consumerString(Consumer<String> first, Consumer<String> sec) {
        first.andThen(sec).accept("Hello World");
    }

}
Comparator
public static void main(String[] args) {

    String[] arr = {"abc", "def", "ghi"};

    //匿名类方法
    Comparator<String> comparator = new Comparator<String>() {
        @Override
        public int compare(String o1, String o2) {
            return o1.length() - o2.length();
        }
    };

    //lambda表达式
    Arrays.sort(arr, (o1, o2) -> o1.length() - o2.length());
    System.out.println(Arrays.toString(arr));

}
Predicate
    public static void main(String[] args) {

        // 传统写法
        Predicate<Integer> predicate = new Predicate<Integer>() {
            @Override
            public boolean test(Integer t) {
                return t > 10;
            }
        };
        System.out.println(predicate.test(15));

        // lambda写法
        Predicate<Integer> predicate1 = (t) -> t > 10;
        System.out.println(predicate1.test(15));
    }
Function
public class FunctionLambda {
    public static void main(String[] args) {
        method((str) -> Integer.parseInt(str) + 10, (num) -> num * 2);
        String str = "xiaou,18";
        int ageNum = getAgeNum(str,
                s -> s.split(",")[1],
                s -> Integer.parseInt(s),
                s -> s + 10);
        System.out.println(ageNum);
    }

    static void method(Function<String, Integer> one, Function<Integer, Integer> two) {
        Integer num = one.andThen(two).apply("10");
        System.out.println(num);
    }

    static int getAgeNum(String str, Function<String, String> one, Function<String, Integer> two, Function<Integer, Integer> three) {
        return one.andThen(two).andThen(three).apply(str);
    }

Lambda底层实现

Lambda的本质:

函数式接口的匿名子类的匿名对象

我们来看下面的代码

    public static void main(String[] args) {
        List<String> stringList = Arrays.asList("掘", "金");
        stringList.forEach(s -> System.out.println(s));
    }
}

之后进行一个反编译。

public static void main(String[] args) {
    List<String> stringList = Arrays.asList("\u6398", "\u91d1");
    stringList.forEach((Consumer<String>)LambdaMetafactory.metafactory(null, null, null, (Ljava/lang/Object;)V, lambda$main$0(java.lang.String ), (Ljava/lang/String;)V)());
}

private static /* synthetic */ void lambda$main$0(String s) {
    System.out.println(s);
}

这个就是反编译的内容

可以看到,他其实就是对一个方法返回的结果进行了一个强转

所以说,他本身就是一个实例

这个方法的核心也就是去写了一个字节码文件

image-20240412143018577

下面是一个过程,比较枯燥,如果想看的可以来阅读一下

  • 为lambda表达式生成一个类,类名类似于:$$Lambda$xxx$yyy,其中xxx为lambda源码实现所在的类名,yyy为一串类似md5字符串的值。具体生成算法暂未深入研究。该类会继承于函数式接口,并且有一个public static的名为INSTANCE的字段,该字段的类型为$$Lambda$xxx$yyy,在类cinit中(经典的单例实现)。接口的抽象方法在实现很简单,就是调用一个名为xxx.lambda$zzz$N方法,xxx为lambda源码实现所在的类名,zzz为lambda源码实现所在的类的方法名,N为阿拉伯数字。xxx.lambda$zzz$N其实就是lambda表达式的具体逻辑的藏身之处。
  • xxx.lambda$zzz$N做为lambda实现的类,它是一个位于lambda实现类中的静态方法。如前文所述,它就是lambda表达式的具体实现。
  • 在lambda表达式调用的地方,会将lambda表达式替换为$$Lambda$xxx$yyy.INSTANCE。在后续调用接口方法,就直接调用$$Lambda$xxx$yyy.INSTANCE的接口实现,接着转调到实现类中的xxx.lambda$zzz$N方法,执行lambda真正的逻辑。

你可以把Lambda理解为一个语法糖。他用到了ASM技术,有兴趣的也可以去了解一下。下面是一个图来进行一个总结

image-20240412143405923

方法引用

初体验

我们也直接来看一个事例。

public static void main(String[] args) {
    //调用printString方法,参数是一个Printable类型的对象 也就是函数式接口
    printString(s -> {
        System.out.println(s);
    });
}

public static void printString(Printable p) {
    p.print("Xiaou");
}

我们来进行一个简化

//调用printString方法,参数是一个Printable类型的对象 也就是函数式接口
printString(s -> {
    System.out.println(s);
});


//使用lambda表达式简化
printString(System.out::println);

这个如果你看不懂,我们可以先看一下源码:

我们可以看到out就是一个PrintStream类型的常量

image-20240412144421658

之后我们来看println

image-20240412144652618

也就是说,这个代码也可以这样写

PrintStream out = System.out;
//使用lambda表达式简化
printString(out::println);

这样看起来就很直观了。

为什么需要这个方法引用呢?

当lambda表达式所要完成的业务逻辑已经存在 --已经有某个函数实现了

我们可以直接引用对于的方法

底层实现

我们还是进行一个反编译:

image-20240412144945298

我们可以看出来,lambda和方法引用实际上是一回事。

不过lambda是需要我们自己去写方法。

而方法引用是用系统里面自带的方法。

语法格式

方法引用运算符

双冒号 ::

哪些方法可以引用?

  • 类方法
  • 构造方法
  • 实例方法

被引用方法与函数式接口抽象方法需要满足以下条件:

  • 参数列表相同

    但是这种也是兼容的,属于是特殊情况

image-20240412150159113

  • 返回值类型兼容
格式范例
类名::静态方法Integer::parseInt
类名::newStudent::new
对象::成员方法"Hello"::toUpperCase this::方法名/super::方法名

方法引用举例

静态方法引用
public static void main(String[] args) {
    int number = method(-10, Math::abs);
    System.out.println(number);
}

public static int method(int number, Calcable calcable) {
    return calcable.calsAbs(number);
}

为什么这个可以使用呢?

我们来看我们的接口

public interface Calcable {
    int calsAbs(int num);
}

之后看这个abs

image-20240412150726020

可以发现俩个的返回值是一样的。并且参数也是一样的。所以我们可以使用。

如果我们改为别的类型,例如string

image-20240412150817862

可以发现他就报错了

构造方法引用
public interface PersonBuilder {
    Person builderPerson(String name);
}
public static void main(String[] args) {
    printName("xiaou", Person::new);
}

public static void printName(String name, PersonBuilder personBuilder) {
    Person person = personBuilder.builderPerson(name);
    System.out.println(person.getName());
}
普通方法引用

这个是没有优化的

package com.xiaou.demo7;

public class Test {
    public static void main(String[] args) {
        printString(s -> {
            Method method = new Method();
            method.printUpperCassString(s);
        });
    }

    public static void printString(Printable printable) {
        printable.print("Hello");
    }
}
//优化版本 引用某个普通成员的方法 对象名::方法名
public static void main(String[] args) {
    Method method = new Method();
    printString(method::printUpperCassString);
}

public static void printString(Printable printable) {
    printable.print("Hello");
}
super和this
public class Human {
    public void say(){
        System.out.println("xiaou");
    }
}
public class Man extends Human {
    @Override
    public void say() {
        System.out.println("xiaou say");
    }

    public void method(Greetable g) {
        g.greet();
    }

    public void show() {
        method(() -> {
            Human h = new Human();
            h.say();
        });
    }
}

我们需要来简化这个方法。

我们来看一下如何简化

public void show() {
    method(super::say);
}

之后来看this的。

public class Husband {
    public void buyHouse() {
        System.out.println("buyhouse");
    }

    public void marry(Richable richable) {
        richable.buy();
    }

    public void soHappy() {
        marry(() -> this.buyHouse());
    }
}

可以简化为

public void soHappy() {
    marry(this::buyHouse);
}
数组的方法引用
public static void main(String[] args) {
    int[] arr1 = createArray(10, int[]::new);
}

public static int[] createArray(int size, ArrayBuilder arrayBuilder) {
    return arrayBuilder.builderArray(size);
}

Stream流

初体验

我们直接来看需求:

查询集合中复合条件的人员

查询集合中姓张、并且长度为3的人

并打印出来

我们来看传统的做法。

public static void main(String[] args) {
    List<String> list = new ArrayList<>();
    list.add("张三");
    list.add("张三丰");
    list.add("张学友");
    list.add("张伟");

    // 遍历List集合
    List<String> listA = new ArrayList<>();
    for (String s : list) {
        if (s.startsWith("张")) {
            listA.add(s);
        }
    }

    //对listA进行处理
    List<String> listB = new ArrayList<>();
    for (String s : listA) {
        if (s.length() == 3) {
            listB.add(s);
        }
    }
    for (String s : listB) {
        System.out.println(s);
    }
}

可以看出来是非常的长的

我们来看stream实现

public static void main(String[] args) {
    List<String> list = new ArrayList<>();
    list.add("张三");
    list.add("张三丰");
    list.add("张学友");
    list.add("张伟");
    list.stream()
            .filter(name -> name.startsWith("张"))
            .filter(name -> name.length() == 3)
            .forEach(System.out::println);
}

stream只关注做什么,不关注怎么做。

filter也就是过滤。

特点

专注于对容器对象的聚合操作

提供串行/并行两种模式 使用Fork/Join框架拆分任务

image-20240412190954643

提高编程效率、可读性

使用步骤:

获得流->中间操作->终结操作

image-20240412190804942

API

中间操作 (Intermediate Operations)

中间操作会返回一个新的流,可以无限制地在一个流上串联起来。这些操作通常不会执行流的计算,而是构建一个流的处理管道。

  • map: 对流中的每个元素应用一个函数,并将结果作为新流的元素。
  • flatMap: 类似于map,但是可以创建一个流的流,然后将这些流连接起来。
  • filter: 过滤掉不满足给定谓词的元素。
  • distinct: 去除流中重复的元素。
  • sorted: 根据自然顺序或者提供的比较器对流中的元素进行排序。
  • peek: 查看流中的元素,通常用于调试。
  • limit: 限制流中元素的数量。
  • skip: 跳过流中前面的元素,数量由参数指定。
  • parallel: 将流的并行性设置为并行。
  • sequential: 将流的并行性设置为顺序。
  • unordered: 表示流的元素没有特定的顺序。
  • concat: 将两个流连接起来,形成一个有序的流。

终结操作 (Terminal Operations)

终结操作是流操作的最后步骤,它会生成一个结果或者副作用,并且会消耗流中的元素。

  • forEach: 对流中的每个元素执行一个操作。
  • forEachOrdered: 与forEach类似,但是保证按照流中元素的遇到顺序执行操作。
  • toArray: 将流中的元素收集到一个数组中。
  • reduce: 对流中的元素进行累积操作,得到一个结果。
  • collect: 收集流中的元素到一个收集器中。
  • min: 返回流中最小的元素。
  • max: 返回流中最大的元素。
  • count: 返回流中元素的数量。
  • iterator: 返回流中元素的迭代器。
  • anyMatch: 检查流中是否至少有一个元素满足给定的谓词。
  • allMatch: 检查流中的所有元素是否都满足给定的谓词。
  • noneMatch: 检查流中是否没有元素满足给定的谓词。
  • findFirst: 返回流中的第一个元素。
  • findAny: 返回流中的任意一个元素。

需要注意的是,我们不能再终结方法之后再去添加中间操作。

因为在执行终结方法后,流就已经执行完了。并且关闭了。

常用API

我们来看一些常用的API

获得流

首先是获取流

public static void main(String[] args) {
    List<String> list = new ArrayList<>();
    Stream<String> stream1 = list.stream();

    Set<String> set = new HashSet<>();
    Stream<String> stream2 = set.stream();

    Map<String, String> map = new HashMap<>();
    Set<String> keySet = map.keySet();
    Stream<String> stream3 = keySet.stream();

    Collection<String> values = map.values();
    Stream<String> stream4 = values.stream();

    Set<Map.Entry<String, String>> entries = map.entrySet();
    Stream<Map.Entry<String, String>> stream5 = entries.stream();


    //把数组转换为Stream流
    Integer[] arr = {1, 2, 3, 4, 5};
    String[] arr2 = {"a", "b", "c"};

    Stream<Integer> stream6 = Stream.of(arr);

    Stream<String> stream7 = Stream.of(arr2);

}
foreach
public static void main(String[] args) {
    Stream<String> stream = Stream.of("a1", "a2", "b1", "c2", "c1");
    stream.forEach(System.out::println);
}
filter

这个就和我们上一个例子是一样的。

map
public static void main(String[] args) {
    Stream<String> stream = Stream.of("1", "2", "3", "4", "5");
    Stream<Integer> stream2 = stream.map(Integer::parseInt);
    stream2.forEach(System.out::println);
}
count
public static void main(String[] args) {
    ArrayList<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(2);
    list.add(3);
    list.add(4);
    list.add(5);

    long count = list.stream().count();
    System.out.println(count);
}
collect
public static void main(String[] args) {
    List<String> list = new ArrayList<>();
    list.add("张三");
    list.add("李四");
    list.add("王五五");

    Stream<String> stream = list.stream().filter(s -> s.length() > 2);

    List<String> collect = stream.collect(Collectors.toList());
    System.out.println(collect);

    Set<Integer> set = new HashSet<>();
    set.add(10);
    set.add(20);
    set.add(30);
    set.add(50);
    Stream<Integer> integerStream = set.stream().filter(s -> s > 20);
    Set<Integer> collect1 = integerStream.collect(Collectors.toSet());
    System.out.println(collect1);

    String[] strArray = {"张三,30", "李四,35", "王五,20"};
    Stream<String> stringStream = Stream.of(strArray).filter(s -> Integer.parseInt(s.split(",")[1]) > 28);
    Map<String, Integer> collect2 = stringStream.collect(Collectors.toMap(
            s -> s.split(",")[0],
            s -> Integer.parseInt(s.split(",")[1])
    ));
    System.out.println(collect2);
}
skip
public static void main(String[] args) {
    String[] arr = {"a", "b", "c", "d", "e", "f", "g", "h"};
    Stream<String> arr1 = Stream.of(arr);
    //跳过前三个元素
    arr1.skip(3).forEach(System.out::println);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1589007.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

设计模式——2_7 状态(State)

欲买桂花同载酒&#xff0c;终不似&#xff0c;少年游 ——刘过《唐多令芦叶满汀州》 文章目录 定义图纸一个例子&#xff1a;如何模拟一个转笔刀自动转笔刀PencilPencilSharpener 投诉和改善钝刀BladePencilSharpener 没有铅笔PencilSharpener if if ifStatePencilSharpener 碎…

雪亮工程视频联网综合管理/视频智能分析系统建设方案(一)

一、行业背景 雪亮工程主要是针对农村地区治安防控的监控项目&#xff0c;在乡村的主干道、路口、人群聚集地部署高清摄像头&#xff0c;通过三级综治中心和指挥平台&#xff0c;将视频图像信息系统纵向下延至县、乡、村&#xff0c;同时利用系统拓展在安防、社会治理、智慧交…

细胞世界:4.细胞分化(划区域)与细胞衰老(设施磨损)

(1)细胞凋亡 1. 概念&#xff1a;细胞凋亡可以比作城市的规划者主动拆除某些建筑来更新城市或防止危险建筑对市民的潜在伤害。这是一个有序的过程&#xff0c;由城市&#xff08;细胞内部&#xff09;的特定规划&#xff08;基因&#xff09;所决定。 2. 特征&#xff1a;细…

LeetCode-1143. 最长公共子序列【字符串 动态规划】

LeetCode-1143. 最长公共子序列【字符串 动态规划】 题目描述&#xff1a;解题思路一&#xff1a;动规五部曲解题思路二&#xff1a;1维DP解题思路三&#xff1a;0 题目描述&#xff1a; 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长 公共子序列 的长度。…

【攻防世界】Confusion1

php的标志是大象&#xff0c;Python的标志是蛇 。Python 的 Flask 框架( Flask 使用 Jinja2 作为模板引擎 ) 点进register.php 输入{{3*4}} 输入 {{config}} 也有回显&#xff0c;ssti 判断是否存在ssti注入&#xff1a; 1. {{8*8}} 2. {{config}} 过滤了关键字&#xff0…

详解Qt添加外部库

在Qt项目中添加外部库是一项常见任务&#xff0c;无论是静态库还是动态库都需要正确的配置才能让项目顺利编译链接。以下是详细步骤和不同场景下的配置方法&#xff1a; 方法一&#xff1a;手动编辑.pro文件 添加头文件路径&#xff1a; 在Qt项目中的.pro文件中使用INCLUDEPAT…

在线视频教育平台|基于Springboot的在线视频教育平台系统设计与实现(源码+数据库+文档)

在线视频教育平台目录 基于Springboot的在线视频教育平台系统设计与实现 一、前言 二、系统设计 三、系统功能设计 1、前台&#xff1a; 2、后台 用户功能模块 教师功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&a…

Kingbase(人大金仓数据库)(总结全网精华,虚拟机:从安装到操作数据库一条龙)

前言&#xff1a; 前一阵子一直在捣鼓人大金仓数据库&#xff0c;虽然国产化的数据库很值得夸赞&#xff0c;但是网上的资料确实少的可怜。特此记录一下我在学习这个数据库的心酸历程。 安装就看这个大哥的&#xff0c;我之前安装就是看的他的&#xff0c;非常靠谱。 linux安装…

海外代理IP如何助力YouTube广告投放?

一、海外代理的角色与优势 拓展地理访问&#xff1a; 海外代理允许您从其他国家或地区的IP地址进行网络访问。通过使用海外代理&#xff0c;您可以绕过部分限制&#xff0c;实现访问YouTube和其他平台的目的。扩展受众&#xff1a; 利用海外代理&#xff0c;您可以将广告投放面…

每日一题---OJ题: 相交链表

片头 嗨! 小伙伴们,大家好! 今天我们来一起学习这道OJ题---相交链表,准备好了吗? Ready Go! ! ! emmm,看这道题好像不怎么难,我们一起画图分析分析 上图中,A链表有5个结点,分别为 a1,a2,c1,c2,c3 ; B链表有6个结点,分别为 b1,b2,b3,c1,c2,c3 ; A链表和B链表在c1结点相交 …

【Python】数学函数和特殊内置函数大揭秘:Python中隐藏的秘密武器

欢迎来CILMY23的博客 本篇主题为 数学函数和特殊内置函数大揭秘&#xff1a;Python中隐藏的秘密武器 个人主页&#xff1a;CILMY23-CSDN博客 个人专栏系列&#xff1a; Python | C语言 | 数据结构与算法 | C 感谢观看&#xff0c;支持的可以给个一键三连&#xff0c;点赞关…

Partisia Blockchain:被严重低估的隐私区块链生态

在今年 3 月&#xff0c;隐私公链 Partisia Blockchain 迎来了重要的进展&#xff0c;该生态通证 $MPC 上线了交易所&#xff0c;目前 $MPC 通证可以在 Kucoin、Gate、BitMart、Bitfinex、Bitture 等平台交易&#xff0c;并将在不久后上线 MEXC 平台。 在上个月上线市场至今&am…

【Linux】进程间通信——system V版本 共享内存

目录 共享内存 原理 实践 shmget() 创建共享内存 shmctl() 删除共享内存 shmat() 挂接进程和共享内存 shmt() 进程和共享内存去关联 共享内存的特性 优势 劣势 用共享内存实现进程间通信 共享内存 原理 两个进程的PCB各自维护着一个进程地址空间。当两个进…

VsCode 安装Jupyter Notebook

VsCode 安装Jupyter Notebook 安装 1、打开 VSCode 编辑器&#xff0c;点击界面左端的【扩展】栏&#xff1b; 2、在【搜索框】中输入python&#xff0c;点击第一个Python&#xff0c;检查是否已经安装 python 插件&#xff0c;没安装的点击安装&#xff1b;已安装的继续第3步…

32单片机入门持续更新中

配套资料为野火霸道V2 初识 STM32 4.1 什么是 STM32 STM32&#xff0c;从字面上来理解&#xff0c;ST 是意法半导体&#xff0c;M 是 Microelectronics 的缩写&#xff0c;32 表示 32 位&#xff0c;合起 来理解&#xff0c;STM32 就是指 ST 公司开发的 32 位微控制器。在如今…

C++数据结构与算法——动态规划子序列系列

C第二阶段——数据结构和算法&#xff0c;之前学过一点点数据结构&#xff0c;当时是基于Python来学习的&#xff0c;现在基于C查漏补缺&#xff0c;尤其是树的部分。这一部分计划一个月 (2024.1.30-2024.4.10已完结&#xff09;&#xff0c;任务量确实有点大&#xff0c;包括春…

Mysql主从同步原理

master每次提交事务时都会将数据变更记录到二进制文件BINLOG中&#xff0c;binlog文件主要记录除查询以外的DDL和DML&#xff0c;slave的IO线程读取master的BINLOG文件&#xff0c;并写入中继日志Relay log文件中&#xff0c;然后slave的SQL线程读取relay log文件并重做事务映射…

核心api实操-Activiti7从入门到专家(5)

背景 上一节已经搭建了&#xff0c;具体的开发环境&#xff0c;数据库&#xff0c;并且找了一个可以用bpmnjs流程设计器&#xff0c;这一些&#xff0c;我们对核心api做个基础的实操&#xff0c;有个感性的认知&#xff0c;另外对数据库和基本数据流动有个理解。 部署 模板部…

Deblurring 3D Gaussian Splatting去模糊3D高斯溅射

Abstract 摘要 Recent studies in Radiance Fields have paved the robust way for novel view synthesis with their photorealistic rendering quality. Nevertheless, they usually employ neural networks and volumetric rendering, which are costly to train and impede…

Web中使用Weblogic用户

WebLogic用户&#xff0c;组设置 1. 登录weblogic console, domain结构中选择Security Realms&#xff0c;显示安装时默认创建的Realm &#xff1a; myrealm 2. 点击myrealm, 选择 users and Group&#xff0c; 追加用户和组 选择既存的权限组追加到新规的组中&#xff0c;赋予…