【昕宝爸爸小模块】深入浅出之Java 8中的 Stream

news2025/1/11 6:52:20

在这里插入图片描述

深入浅出之Java 8中的 Stream

  • 一、🟢典型解析
    • 1.1 🟠Java 8中的Stream 都能做什么
    • 1.2 🟠Stream的创建
  • 二、✅ Stream中间操作
    • 2.1 🟠Filter
    • 2.2 🟠Map
    • 2.3 🟠limit / skip
    • 2.4 🟠sorted
    • 2.5 🟠distinct
  • 三、 ✅Stream最终操作
    • 3.1 🟠forEach
    • 3.2 🟠count
    • 3.3 🟠collect
  • 四、✅ 扩展知识仓
    • 4.1 🟠Stream有哪些优点和缺点
    • 4.2 🟠Stream中间操作的作用是什么
    • 4.3 🟠Stream终极操作的作用是什么


一、🟢典型解析


1.1 🟠Java 8中的Stream 都能做什么


Stream 使用一种类似用 SOL 语句从数据库查询数据的直观方式来提供一种对Java 集合运算和表达的高阶抽象。


Stream API 可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。


这种风格将要处理的元素集合看作一种流,流在管道中传输,并且可以在管道的节点上进行处理,比如筛选,排序,聚合等。


Stream有以下特性及优点


  • 无存储。Stream不是一种数据结构,它只是某种数据源的一个视图,数据源可以是一个数组,Java容器I/O channel 等。
  • 为函数式编程而生。对 Stream 的任何修改都不会修改背后的数据源,比如对Stream执行过滤操作并不会删除被过滤的元素,而是会产生一个不包含被过滤元素的新Stream。
  • 惰式执行。Stream上的操作并不会立即执行,只有等到用户真正需要结果的时候才会执行。
  • 可消费性。Stream只能被“消费”一次,一旦遍历过就会失效,就像容器的迭代器那样,想要重次遍历必须重新生成。

我们举一个例子,来看一下到底Stream可以做什么事情:


在这里插入图片描述


上面的例子中,获取一些带颜色塑料球作为数据源,首先过滤掉红色的、把它们融化成随机的三角形。再过滤器并删除小的三角形。最后计算出剩余图形的周长。


如上图,对于流的处理,主要有三种关键性操作: 分别是流的创建中间操作 (intermediateoperation) 以及最终操作(terminal operation)


1.2 🟠Stream的创建


在Java 8中,可以有多种方法来创建流。


1、通过已有的集合来创建流


在Java 8中,除了增加了很多Stream相关的类以外,还对集合类自身做了增强,在其中增加了stream方法,可以将一个集合类转换成流。


List<String> strings = Arrays.asList("Java", "JavaAndJ", "Java", "Hello", "HelloWorld","Java");

 Stream<String> stream = strings.stream();

以上,通过一个已有的List创建一个流。除此以外,还有一个parallelStream 方法,可以为集合创建个并行流。


这种通过集合创建出一个Stream的方式也是比较常用的一种方式。


2、通过Stream创建流


可以使用Stream类提供的方法,直接返回一个由指定元素组成的流。


Stream<String> stream = Stream.of("Java", "JavaAndJ", "Java", "Hello", "HelloWorld","Java");

如以上代码,直接通过 of 方法,创建并返回一个Stream。


二、✅ Stream中间操作


Stream有很多中间操作,多个中间操作可以连接起来形成一个流水线,每一个中间操作就像流水线上的一个工人,每人工人都可以对流进行加工,加工后得到的结果还是一个流。


在这里插入图片描述

以下是常用的中间操作列表:


在这里插入图片描述

2.1 🟠Filter


Stream的中间操作Filter的作用是过滤流中的元素,它接受一个Predicate接口作为参数,该接口中的test方法可以对给定的参数进行判断,返回一个布尔值。通过调用filter方法,我们可以从流中过滤出满足条件的元素。

在Java中,我们可以通过以下步骤使用Filter中间操作:

1. 创建Stream对象,对需要过滤的集合对象使用stream().filter(Predicate)方法。

2. 传入一个Lambda表达式作为参数,该Lambda表达式定义了过滤条件。

3. 执行终止操作,如collect、forEach等,将过滤后的结果输出或处理。


看一个Demo:

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
*   演示了如何使用Java Stream API进行一系列的中间操作和终止操作
*   来处理一个学生列表,包括筛选特定条件的学生、统计满足条件的
*  学生数量、计算平均分
*/
public class StreamComplexExample {
    public static void main(String[] args) {
        List<Student> students = Arrays.asList(
            new Student("Alice", 85),
            new Student("Bob", 90),
            new Student("Charlie", 78),
            new Student("David", 88),
            new Student("Eve", 92)
        );
        
        // 筛选出平均分大于等于85的学生,并计算满足条件的学生数量
        int count = students.stream()
                             .filter(student -> student.getScore() >= 85)
                             .collect(Collectors.toList())
                             .size();
        System.out.println("满足条件的学生数量: " + count); // 输出: 3
        
        // 计算平均分大于等于85的学生的平均分
        double averageScore = students.stream()
                                       .filter(student -> student.getScore() >= 85)
                                       .mapToDouble(Student::getScore) // 将学生对象转换为分数
                                       .average()                      // 计算平均分
                                       .orElse(0);                     // 如果流为空,返回0
        System.out.println("平均分: " + averageScore); // 输出: 88.33333333333334
        
        // 根据性别分组,并计算每个性别的平均分
        Map<String, Double> averageScores = students.stream()
                                                     .collect(Collectors.groupingBy(Student::getGender,
                                                         Collectors.averagingDouble(Student::getScore)));
        System.out.println("平均分(按性别): " + averageScores); 


		// 输出: {男=87.5, 女=86}
    }
}

2.2 🟠Map


Stream的中间操作Map的作用是将流中的每个元素转换成另一个对象,并返回一个新的流。Map操作接受一个Function接口作为参数,该接口中的apply方法可以对给定的参数进行转换,并返回转换后的结果。

在Java中,我们可以通过以下步骤使用Map中间操作:

  1. 创建Stream对象,对需要映射的集合对象使用stream().map(Function)方法。
  2. 传入一个Lambda表达式或方法引用作为参数,该Lambda表达式或方法引用定义了映射规则。
  3. 执行终止操作,如collect、forEach等,将映射后的结果输出或处理。

Demo:


import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
* 使用Java Stream API进行一系列的中间操作和终止操作来处理一个
* 整数列表,包括过滤出偶数、计算每个偶数的平方、以及找出平方值
* 最大的那个偶数
*/
public class StreamComplexExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        
        // 过滤出偶数,并计算每个偶数的平方
        List<Integer> squaredEvens = numbers.stream()
                                              .filter(number -> number % 2 == 0)
                                              .map(number -> number * number)
                                              .collect(Collectors.toList());
        System.out.println("平方的偶数: " + squaredEvens); // 输出: [4, 16, 36, 64]
        
        // 找出平方值最大的那个偶数
        Optional<Integer> maxSquare = squaredEvens.stream()
                                                   .max(Integer::compare);
        if (maxSquare.isPresent()) {
            System.out.println("平方值最大的偶数: " + maxSquare.get()); // 输出: 64
        } else {
            System.out.println("没有找到平方值最大的偶数");
        }
    }
}

//    输出结果:
//    平方的偶数: [4, 16, 36, 64]  
//    平方值最大的偶数: 64

2.3 🟠limit / skip


在Java的Stream API中,limit是一个中间操作,用于限制流中的元素数量。这个操作返回一个新的流,其中只包含原始流中的前N个元素。


Demo:


import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
* 如何使用Java Stream API进行一系列的中间操作和终止操作来处理
* 一个字符串列表,包括将字符串转换为小写、过滤出长度大于等于5的
* 字符串、计算每个字符串的长度、找出长度最大的字符串
*/
public class StreamComplexExample {
    public static void main(String[] args) {
        List<String> strings = Arrays.asList("Hello", "World", "Java", "Stream", "Example");
        
        // 将字符串转换为小写,并过滤出长度大于等于5的字符串
        List<String> lowercaseStrings = strings.stream()
                                                .map(String::toLowerCase) // 将字符串转换为小写
                                                .filter(string -> string.length() >= 5) // 过滤出长度大于等于5的字符串
                                                .collect(Collectors.toList()); // 收集结果到列表
        System.out.println("Lowercase strings: " + lowercaseStrings); // 输出: [hello, world, example]
        
        // 计算每个字符串的长度,并找出长度最大的字符串
        Optional<String> longestString = lowercaseStrings.stream()
                                                           .max(String::compareTo); // 比较字符串长度
        if (longestString.isPresent()) {
            System.out.println("Longest string: " + longestString.get()); // 输出: Example
        } else {
            System.out.println("No longest string found");
        }
    }
}

//输出结果:
//Lowercase strings: [hello, world, example]  
//Longest string: Example

2.4 🟠sorted


在Java的Stream API中,sorted是一个中间操作,用于对流中的元素进行排序。它可以按照自然顺序进行排序,也可以根据指定的比较器进行排序。


Demo:

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* 使用Java Stream API的`sorted`中间操作对整数列表进行排序
*/
public class StreamSortedIntegerExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(5, 2, 9, 1, 7);

        // 使用sorted中间操作对整数进行排序
        List<Integer> sortedNumbers = numbers.stream()
                                              .sorted()
                                              .collect(Collectors.toList());

        System.out.println(sortedNumbers); // 输出: [1, 2, 5, 7, 9]

        // 如果你想降序排序,可以使用Comparator.reverseOrder()
        List<Integer> sortedDescending = numbers.stream()
                                                .sorted(Comparator.reverseOrder())
                                                .collect(Collectors.toList());

        System.out.println(sortedDescending); // 输出: [9, 7, 5, 2, 1]
    }
}

注意:sorted方法不会修改原始流中的元素,而是返回一个新的流,其中包含排序后的元素。要查看排序结果,需要使用一个终止操作(在这个例子中是collect)来收集流中的元素。


2.5 🟠distinct


在Java的Stream API中,distinct是一个中间操作,用于去除流中的重复元素。


Demo:

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* 使用`distinct`中间操作
*/
public class StreamDistinctExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 4, 4, 5);
        
        // 使用distinct中间操作去除重复元素
        List<Integer> distinctNumbers = numbers.stream()
                                                 .distinct()
                                                 .collect(Collectors.toList());
        
        System.out.println(distinctNumbers); // 输出: [1, 2, 3, 4, 5]
    }
}

例子中,创建了一个包含七个整数的列表numbers,其中有两个2和两个4。然后,我们使用stream().distinct()将流中的重复元素去除,并将结果收集到一个新的列表distinctNumbers中。最后,我们打印出这个去重后的列表。


接下来我们通过一个例子和一张图,来演示下,当一个Stream先后通过filter、map、sort、limit以及distinct处理后会发生什么。


代码如下:


List<String> strings = Arrays.aslist("Java", "JavaAndJ", "Java", "Hello", "HelloWorld","Java");

Stream s = strings.stream(),filter(string -> string.length( )<= 6)
	.map(string::length).sorted()
	.limit(3)
	.distinct();

过程及每一步得到的结果我已经给大家画出来了,帮助大家快速掌握:


在这里插入图片描述

三、 ✅Stream最终操作


Stream的中间操作得到的结果还是一个Stream,那么如何把一个Stream转换成我们需要的类型呢? 比如计算出流中元素的个数、将流装换成集合等。这就需要最终操作 (terminal operation)


最终操作会消耗流,产生一个最终结果。也就是说,在最终操作之后,不能再次使用流,也不能在使用任何中间操作,否则将抛出异常:


java.lang.IllegalStateException: stream has already been operated upon or closed


俗话说,“你永远不会两次踏入同一条河” 也正是这个意思。


常用的最终操作如下图:


在这里插入图片描述

3.1 🟠forEach


Stream 提供了方法 "forEach’来迭代流中的每个数据。以下代码片段使用 forEach 输出了10个随机数:


Random random = new Random();
random.ints().limit(10).forEach(System.out::println);

3.2 🟠count


count用来统计流中的元素个数。


List<String> strings = Arrays.aslist("Java", "JavaAndJ","Java666", "Java", "Hello", "HelloWorld","Java");

System.out.printIn(strings.stream().count()); //7

3.3 🟠collect

List<String> strings = Arrays.asList ("Java", "JavaAndJ","Java666", "Java", "Hello", "HelloWorld","Java");

strings = strings.stream().filter(string -> string.startsWith("Hollis")).collect(Collectors.tolist());
System.out.println(strings);

接下来,我们还是使用一张图,来演示下,前文的例子中,当一个Stream先后通过filter、map.sort、limit以及distinct处理后会,在分别使用不同的最终操作可以得到怎样的结果。


下图,展示了文中介绍的所有操作的位置、输入、输出以及使用一个案例展示了其结果:


在这里插入图片描述

四、✅ 扩展知识仓


4.1 🟠Stream有哪些优点和缺点


Stream的优点

  1. 声明性:Stream允许我们以声明性的方式处理数据,这意味着我们只需关注需要做什么,而不是如何做。这使得代码更加简洁和易读。
  2. 可复合性:Stream的操作是可复合的,这意味着多个操作可以链式调用,从而简化了代码。
  3. 可并行处理:Stream操作可以并行执行,这使得处理大量数据更加高效。
  4. 延迟计算:Stream操作在需要结果时才执行,这使得计算更加高效。
  5. 操作转换:Stream提供了一种简单而强大的方式来对数据进行过滤、转换、排序和聚合等操作。

Stream缺点

  1. 数据不可变性:Stream操作返回的是新的Stream对象,而不是修改原始数据集。这意味着每次操作都会创建一个新的数据集,这可能会导致内存和性能问题,特别是对于大规模数据集。
  2. 错误处理:当Stream操作发生错误时,需要特别小心处理。由于Stream操作是惰性计算的,一旦发生错误,可能需要重新计算整个数据集才能找到问题所在。
  3. 类型安全:在使用Stream时,需要特别注意类型安全。由于Stream操作是惰性计算的,类型信息在计算过程中可能会丢失,从而导致类型错误。
  4. 函数式编程的限制:Stream是基于函数式编程的,这使得代码更加简洁和易读。但是,这也意味着某些传统的编程模式可能不适用。例如,循环和条件语句在某些情况下可能比使用Stream更简单和直观。

4.2 🟠Stream中间操作的作用是什么


Stream中间操作在Java中扮演着处理数据流的重要角色。它们的主要作用是在数据流上进行一系列转换和操作,以产生一个新的数据流供后续操作使用。中间操作不会立即执行实际的数据处理,而是创建一个新的流,并在其中定义将要执行的操作。这种特性被称为“惰性求值”或“延迟执行”,意味着只有在终端操作被触发时,中间操作才会真正开始执行。


中间操作可以包括过滤、映射、排序、去重等各种转换操作。例如,使用filter方法可以根据给定的条件过滤流中的元素,只保留满足条件的元素。map方法则用于对流中的每个元素应用一个函数,将其转换成另一种形式。这些中间操作可以链式调用,形成一个处理管道,对流进行多次转换。


通过中间操作,可以逐步构建和调整数据流,以满足特定的处理需求。最终,通过终端操作(如collectforEach等)触发实际的数据处理,并产生最终结果或副作用。这种声明性的处理方式使得代码更加简洁、易读,并有助于提高代码的可维护性和可重用性。


4.3 🟠Stream终极操作的作用是什么


Stream的终极操作会消耗流并产生一个最终结果。这意味着一旦进行终极操作,就不能再次使用流,也不再使用任何中间操作,否则会抛出异常。常见的终极操作包括计算出流中元素的个数、将流转换成集合、以及遍历流中的元素等。


终极操作的主要作用是完成数据流的处理,并产生所需的结果。例如,通过collect操作将流转换为集合,或使用forEach操作对每个元素执行某些操作。一旦执行了终极操作,流中的数据就被处理完毕,并且流对象本身通常会被丢弃或不再使用。


注意:在Java中,如果流支持迭代器(iterator),那么在调用iterator()方法后,流就不能再被使用,否则会抛出IllegalStateException异常。这是因为迭代器会消耗流中的元素,并且不支持逆向操作。因此,在使用迭代器时,必须小心处理流的剩余部分,以避免潜在的错误和异常。

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

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

相关文章

基于LVGL编写的windows串口工具: LCOM

LCOM: Serial Port Tools based on LVGL (PC Software) 一直以来我都想用LVGL做一个真正意义上的PC软件&#xff0c;来验证或者表达LVGL出色的特性&#xff0c;现在我用LCOM做到了&#xff01; LCOM 是一个基于LVGL编写的串口工具&#xff0c;界面简洁&#xff0c;功能出色&a…

构建基于RHEL8系列(CentOS8,AlmaLinux8,RockyLinux8等)的Nginx1.24.0的RPM包

本文适用&#xff1a;rhel8系列&#xff0c;或同类系统(CentOS8,AlmaLinux8,RockyLinux8等) 文档形成时期&#xff1a;2022-2023年 因系统版本不同&#xff0c;构建部署应略有差异&#xff0c;但本文未做细分&#xff0c;对稍有经验者应不存在明显障碍。 因软件世界之复杂和个人…

二十四、同域名下JSESSIONID重叠导致退出

同域名下JSESSIONID重叠导致退出 近期在开发项目的时候发现,如果同域名的情况下,如果把一个单页面无登录系统嵌套进入另外一个系统,那么会出现相互退出的问题。 思考解决方案 一、清除掉嵌套的系统的JSESSIONID,意思就是嵌套系统不设置JSESSIONID 1找寻出问题接口 在无痕…

DHCP与时间同步

目录 一、DHCP 1、DHCP定义 1.什么是DHCP 2.DHCP的好处 3.DHCP的分配方式 4.为什么使用DHCP 5.DHCP模式 2、DHCP的工作过程 3、DHCP动态配置主机地址 1.DHCP服务的优点 2.可分配的地址信息 3.动态分配IP地址 二、时间同步 1、ntp 2、chrony 1、搭建本地本地时间…

011集:复制文件(包括exe、 jpg、png、Word、Excel和PPT等二进制文件)—python基础入门实例

在文本文件的内部以字符形式存储数据&#xff0c;字符是有编码的&#xff0c;例如GBK (简体中文) 、UTF-8等;在二进制文件的内部以字节形式存储数据、没有编码的概念。二进制文件较为常用&#xff0c;例如Windows中的exe、图片 (jpg、png等)&#xff0c;以及Word、Excel和PPT等…

多语言生成式语言模型用于零样本跨语言事件论证提取(ACL2023)

1、写作动机&#xff1a; 经过预训练的生成式语言模型更好地捕捉实体之间的结构和依赖关系&#xff0c;因为模板提供了额外的声明性信息。先前工作中模板的设计是依赖于语言的&#xff0c;这使得很难将其扩展到零样本跨语言转移设置。 2、主要贡献&#xff1a; 作者提出了一…

d2l动手学深度学习】 Lesson 13 Dropout层 老板随机丢掉一些做项目的程序员‍,项目的效果会更好!(bushi)

文章目录 1. 什么是Dropout老板随机丢掉一些做项目的程序员&#x1f9d1;‍&#x1f4bb;&#xff0c;项目的效果会更好&#xff01; 2. 代码实现&#xff08;不用torch&#xff09;3. 代码实现&#xff08;使用torch&#xff09;3. 调节实验3.1 老师上课所设置的dropout1, dro…

探索 hasOwnProperty:处理对象属性的关键(下)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

问界又“翻车”了? 新能源电池“怕冷”成短板

文 | AUTO芯球 作者 | 李欣 2023年12月17日&#xff0c;蔚来创始人李斌亲自下场&#xff01;驾驶ET7从上海出发&#xff0c;经过超14小时的行驶后&#xff0c;达成一块电池行驶超过1000公里的成绩&#xff0c;这一直播引起外界的广泛关注。 这不禁让人与”懂车帝冬测“联想到…

Vue3 的基本开发+新特性

Vue3 1.Vue3 1. Vue2 选项式 API vs Vue3 组合式API <script> export default {data(){return {count:0}},methods:{addCount(){this.count}} } </script> <script setup> import { ref } from vue const count ref(0) const addCount ()> count.val…

文件操作(你真的会读写文件吗?)

文章目录 一、为什么使用文件&#xff1f;二、什么是文件&#xff1f;2.1 程序文件2.2 数据文件2.3 文件名 三、二进制文件和文本文件3.1 二进制文件3.2 文本文件 四、文件的打开和关闭4.1 流和标准流4.1.1 流4.1.2 标准流 4.2 文件指针4.3 fopen和fclose 五、文件的顺序读写5.…

代码随想录刷题第四十八天| 198.打家劫舍 ● 213.打家劫舍II ● 337.打家劫舍III

代码随想录刷题第四十八天 今天是打家劫舍三部曲&#xff0c;最后一题树形dp有点难&#xff0c;其他还好 打家劫舍 (LC 198) 题目思路&#xff1a; 代码实现&#xff1a; class Solution:def rob(self, nums: List[int]) -> int:dp [0 for _ in range(len(nums)1)]dp[1…

Open3D 截取感兴趣的点云部分

import time import open3d as o3d; import numpy as np; import matplotlib.pyplot as plt from scipy.signal import find_peaks#坐标 mesh_coord_frame o3d.geometry.TriangleMesh.create_coordinate_frame(size355, origin[0, 0, 0]) #mesh_coord_frame mesh_coord_frame…

机器学习_实战框架

文章目录 介绍机器学习的实战框架1.定义问题2.收集数据和预处理(1).收集数据(2).数据可视化(3).数据清洗(4).特征工程(5).构建特征集和标签集(6).拆分训练集、验证集和测试集。 3.选择算法并建立模型4.训练模型5.模型的评估和优化 介绍机器学习的实战框架 一个机器学习项目从开…

UVa1308/LA2572 Viva Confetti

题目链接 本题是2002年ICPC亚洲区域赛金沢(日本)赛区的H题 题意 我已经把n个圆盘依次放到了桌面上。现按照放置顺序依次给出各个圆盘的圆心位置和半径&#xff0c;问最后有多少圆盘可见&#xff1f;如下图所示。 分析 《训练指南》的题解&#xff1a; 题目说“保证在对输入数据…

87.乐理基础-记号篇-反复记号(一)反复、跳房子

内容参考于&#xff1a;三分钟音乐社 上一个内容&#xff1a;86.乐理基础-记号篇-速度记号-CSDN博客 首先是反复记号表总结图&#xff1a; 当前是写前两个记号&#xff0c;其余记号后面写&#xff1a;这些反复记号最主要的目的很简单&#xff0c;还是为了节约纸张&#xff0c…

使用Linux安装Mysql Community Server 8.0.35

一、下载Mysql 官网&#xff1a;https://www.mysql.com/ 第一步&#xff1a;进入Linux官网&#xff0c;点击下载 第二步&#xff1a;点击MySQL Community (GPL) Downloads 第三步&#xff1a;进入页面&#xff0c;选择 MySQL Community Server 第四步&#xff1a;根据自己服务…

SpringBoot集成RabbitMq,RabbitMq消费与生产,消费失败重发机制,发送签收确认机制

RabbitMq消费与生产&#xff0c;消费失败重发机制&#xff0c;发送确认机制&#xff0c;消息发送结果回执 1. RabbitMq集成spring bootRabbitMq集成依赖RabbitMq配置RabbitMq生产者&#xff0c;队列&#xff0c;交换通道配置&#xff0c;消费者示例 2. RabbitMq消息确认机制消息…

LangChain 72 reference改变结果 字符串评估器String Evaluation

LangChain系列文章 LangChain 60 深入理解LangChain 表达式语言23 multiple chains链透传参数 LangChain Expression Language (LCEL)LangChain 61 深入理解LangChain 表达式语言24 multiple chains链透传参数 LangChain Expression Language (LCEL)LangChain 62 深入理解Lang…

Nginx——基础配置

和大多数软件一样&#xff0c;Nginx也有自己的配置文件&#xff0c;但它又有很多与众不同的地方&#xff0c;本帖就来揭开Nginx基础配置的面纱。 1、Nginx指令和指令块 了解指令和指令块有助于大家了解配置的上下文&#xff0c;下面是一个配置模板示例&#xff1a; 在这个配…