Java流式编程详细介绍

news2024/11/28 5:50:58

文章目录

  • 1. 流式编程介绍
  • 2. 过滤
    • 2.1 filter
    • 2.2 distinct
    • 2.3 limit
    • 2.4 sorted
    • 2.5 skip
  • 3. 映射
    • 3.1 map
    • 3.2 flatmap
  • 4 查找
    • 4.1 allMatch
    • 4.2 anyMatch
    • 4.3 noneMatch
    • 4.4 findFirst
    • 4.5 findAny
  • 5. 归约
  • 6. 收集
    • 6.1 counting
    • 6.2 maxBy,minBy
    • 6.3 summingInt、summingLong、summingDouble
    • 6.4 averageInt、averageLong、averageDouble
    • 6.5 summarizingInt、summarizingLong、summarizingDouble
    • 6.6 joining
    • 6.7 groupingBy
  • 7. 构建流
    • 7.1 由值构建流
    • 7.2 由数组创建流
    • 7.3 由文件生成流
    • 7.4 由函数生成流:创建无限流
  • 8 构建流
    • 8.1 由值构建流
    • 8.2 由数组创建流
    • 8.3 由文件生成流
    • 8.4 由函数生成流:创建无限流

1. 流式编程介绍

流是从支持数据处理操作的源生成的元素序列。

流的操作特点如下:

  1. 元素序列:就像集合一样,流也提供了一个接口,可以访问特定元素类型的一组有序值
  2. 源:流会使用一个提供数据的源,如集合、数组或输入/输出资源
  3. 数据处理操作:流的数据处理功能支持类似于数据库的操作,以及函数式编程语言中的常用操作,如filter、map、reduce、find、match、sort等
  4. 流水线:很多流操作本身会返回一个流,这样多个操作就可以链接起来,形成一个大的流水线
  5. 内部迭代:与使用迭代器显式迭代的集合不同,流的迭代操作是在背后进行的
  6. 流只能遍历一次

以下数据进行举例,

List<User> list = new ArrayList<User>(){
        {
            add(new User(1l,"张三",10, "清华大学"));
            add(new User(2l,"李四",12, "清华大学"));
            add(new User(3l,"王五",15, "清华大学"));
            add(new User(4l,"赵六",12, "清华大学"));
            add(new User(5l,"田七",25, "北京大学"));
            add(new User(6l,"小明",16, "北京大学"));
            add(new User(7l,"小红",14, "北京大学"));
            add(new User(8l,"小华",14, "浙江大学"));
            add(new User(9l,"小丽",17, "浙江大学"));
            add(new User(10l,"小何",10, "浙江大学"));
        }
    };

其中 User 定义如下:

@Data
@AllArgsConstructor
class User {
    private Long id;       //主键id
    private String name;   //姓名
    private Integer age;   //年龄
    private String school; //学校
}

2. 过滤

2.1 filter

我们希望过滤赛选处所有学校是清华大学的user:

System.out.println("学校是清华大学的user");
List<User> userList1 = list.stream()
  .filter(user -> "清华大学".equals(user.getSchool()))
  .collect(Collectors.toList());
userList1.forEach(user -> System.out.print(user.name + '、'));

2.2 distinct

去重,我们希望获取所有user的年龄(年龄不重复)

System.out.println("所有user的年龄集合");
List<Integer> userAgeList = list.stream()
  .map(User::getAge)
  .distinct()
  .collect(Collectors.toList());
System.out.println("userAgeList = " + userAgeList);

2.3 limit

返回前n个元素的流,当集合的长度小于n时,则返回所有集合。

如获取年龄是偶数的前2名user:

System.out.println("年龄是偶数的前两位user");
List<User> userList3 = list.stream()
  .filter(user -> user.getAge() % 2 == 0)
  .limit(2)
  .collect(Collectors.toList());
userList3.forEach(user -> System.out.print(user.name + '、'));

2.4 sorted

排序,如现在我想将所有user按照age从大到小排序:

System.out.println("按年龄从大到小排序");
List<User> userList4 = list.stream()
  .sorted((s1,s2) -> s2.getAge() - s1.getAge())
  .collect(Collectors.toList());
userList4.forEach(user -> System.out.print(user.name + '、'));

2.5 skip

跳过n个元素后再输出,如输出list集合跳过前两个元素后的list

System.out.println("跳过前面两个user的其他所有user");
List<User> userList5 = list.stream()
  .skip(2)
  .collect(Collectors.toList());
userList5.forEach(user -> System.out.print(user.name + '、'));

3. 映射

3.1 map

/*
* 先找出集合中的偶数  再将这些偶数进行平方操作
*/
List<Integer> numbers=Arrays.asList(1,2,3,4,5,6,7,8,9);
List<Integer> evenNumbers=numbers.stream()
  .filter(x->x%2==0)//寻找偶数
  .map(x->x*x)
  .collect(toList());
System.out.println(evenNumbers);//[2,4,6,8]->[4, 16, 36, 64]

3.2 flatmap

流的扁平化,相当于将流变为一维的数组。

List<String> words=Arrays.asList("Monday","Tuesday");
List<String> characters=words.stream()
  .map(word->word.split(""))//将每个单词转化为一个字符串数组
  .flatMap(Arrays::stream)//将每个字符数组扁平化
  .collect(toList());
System.out.println(characters);//[M, o, n, d, a, y, T, u, e, s, d, a, y]

除了上面这类基础的map,java8还提供了 mapToDouble(ToDoubleFunction<? super T> mapper),mapToInt(ToIntFunction<? super T> mapper),mapToLong(ToLongFunction<? super T> mapper),这些映射分别返回对应类型的流,java8为这些流设定了一些特殊的操作,比如查询学校是清华大学的user的年龄总和:

System.out.println("学校是清华大学的user的年龄总和");
int userList7 = list.stream()
  .filter(user -> "清华大学".equals(user.getSchool()))
  .mapToInt(User::getAge)
  .sum();
System.out.println( "学校是清华大学的user的年龄总和为: "+userList7);

4 查找

4.1 allMatch

用于检测是否全部都满足指定的参数行为,如果全部满足则返回true,例如我们判断是否所有的user年龄都大于9岁,实现如下:

System.out.println("判断是否所有user的年龄都大于9岁");
Boolean b = list.stream()
  .allMatch(user -> user.getAge() >9);
System.out.println(b);

输出为:

判断是否所有user的年龄都大于9

true

4.2 anyMatch

anyMatch则是检测是否存在一个或多个满足指定的参数行为,如果满足则返回true,例如判断是否有user的年龄大于15岁,实现如下:

System.out.println("判断是否有user的年龄是大于15岁");
Boolean bo = list.stream()
  .anyMatch(user -> user.getAge() >15);
System.out.println(bo);

输出为:

判断是否有user的年龄是大于15

true

4.3 noneMatch

noneMatch用于检测是否不存在满足指定行为的元素,如果不存在则返回true,例如判断是否不存在年龄是15岁的user,实现如下:

System.out.println("判断是否不存在年龄是15岁的user");
Boolean boo = list.stream()
  .noneMatch(user -> user.getAge() == 15);
System.out.println(boo);

输出如下:

判断是否不存在年龄是15岁的user

false

4.4 findFirst

findFirst用于返回满足条件的第一个元素,比如返回年龄大于12岁的user中的第一个,实现如下:

System.out.println("返回年龄大于12岁的user中的第一个");
Optional<User> first = list.stream()
  .filter(u -> u.getAge() > 10)
  .findFirst();
User user = first.get();
System.out.println(user.toString());

输出如下:

返回年龄大于12岁的user中的第一个

User{id=2, name='李四', age=12, school='清华大学'}

4.5 findAny

findAny相对于findFirst的区别在于,findAny不一定返回第一个,而是返回任意一个,比如返回年龄大于12岁的user中的任意一个:

System.out.println("返回年龄大于12岁的user中的任意一个");
Optional<User> anyOne = list.stream()
  .filter(u -> u.getAge() > 10)
  .findAny();
User user2 = anyOne.get();
System.out.println(user2.toString());

输出如下:

返回年龄大于12岁的user中的任意一个

User{id=2, name='李四', age=12, school='清华大学'}

5. 归约

归约即使用 reduce 函数,该函数使用用来求和的例子如下:

/*
* reduce的第一个参数:初始值 相当于给求和一个初值
* reduce的第二个参数:一个BinaryOperator<T>来将两个元素结合起来产生一个新值
*/
List<Integer> numbers=Arrays.asList(4,3,5,9);
int sum=numbers.stream()
  .reduce(0, (a,b)->a+b);
System.out.println("sum="+sum);//21

其执行的流程如下:

归约执行流程

除此之外,reduce 还有另一个重载的方法,可以用来求最大值最小值等问题,示例如下,

/*
* reduce重载的变体
* 它不接受初始值,但是会返回一个Optional对象
*/
List<Integer> numbers=Arrays.asList(4,3,5,9);
Optional<Integer> maxNum=numbers.stream()
  .reduce((x,y)->x>y?x:y);
Optional<Integer> minNum=numbers.stream()
  .reduce((x,y)->x<y?x:y);
System.out.println("maxNum="+maxNum);//maxNum=Optional[9]
System.out.println("minNum="+minNum);//minNum=Optional[3]

6. 收集

前面利用 collect(Collectors.toList()) 是一个简单的收集操作,是对处理结果的封装,对应的还有 toSet、toMap,以满足我们对于结果组织的需求。这些方法均来自于java.util.stream.Collectors,我们可以称之为收集器。

收集器也提供了相应的归约操作,但是与reduce在内部实现上是有区别的,收集器更加适用于可变容器上的归约操作,这些收集器广义上均基于 Collectors.reducing() 实现。

6.1 counting

计算个数,如我现在计算user的总人数,实现如下:

System.out.println("user的总人数");
long COUNT = list.stream()
  .count();//简化版本
long COUNT2 = list.stream()
  .collect(Collectors.counting());//原始版本
System.out.println(COUNT);//10
System.out.println(COUNT2);//10

6.2 maxBy,minBy

计算最大值和最小值,如我现在计算user的年龄最大值和最小值:

System.out.println("user的年龄最大值和最小值");
Integer maxAge =list.stream()
  .collect(Collectors.maxBy((s1, s2) -> s1.getAge() - s2.getAge()))
  .get()
  .getAge();
Integer maxAge2 = list.stream()
  .collect(Collectors.maxBy(Comparator.comparing(User::getAge)))
  .get()
  .getAge();
Integer minAge = list.stream()
  .collect(Collectors.minBy((S1,S2) -> S1.getAge()- S2.getAge()))
  .get()
  .getAge();
Integer minAge2 = list.stream()
  .collect(Collectors.minBy(Comparator.comparing(User::getAge)))
  .get()
  .getAge();
System.out.println("maxAge = " + maxAge);//25
System.out.println("maxAge2 = " + maxAge2);//25
System.out.println("minAge = " + minAge);//10
System.out.println("minAge2 = " + minAge2);//10

6.3 summingInt、summingLong、summingDouble

总和,如计算user的年龄总和:

System.out.println("user的年龄总和");
Integer sumAge =list.stream()
  .collect(Collectors.summingInt(User::getAge));
System.out.println("sumAge = " + sumAge);//145

6.4 averageInt、averageLong、averageDouble

平均值,如计算user的年龄平均值:

System.out.println("user的年龄平均值");
double averageAge = list.stream()
  .collect(Collectors.averagingDouble(User::getAge));
System.out.println("averageAge = " + averageAge);

6.5 summarizingInt、summarizingLong、summarizingDouble

一次性查询元素个数、总和、最大值、最小值和平均值,

System.out.println("一次性得到元素个数、总和、均值、最大值、最小值");
long l1 = System.currentTimeMillis();
IntSummaryStatistics summaryStatistics = list.stream().collect(Collectors.summarizingInt(User::getAge));
long l111 = System.currentTimeMillis();
System.out.println("计算这5个值消耗时间为" + (l111-l1));
System.out.println("summaryStatistics = " + summaryStatistics);

输出如下:

一次性得到元素个数、总和、均值、最大值、最小值

计算这5个值消耗时间为``3

summaryStatistics = IntSummaryStatistics{count=10, sum=145, min=10, average=14.500000, max=25}

6.6 joining

字符串拼接,如输出所有user的名字,用“,”隔开

System.out.println("字符串拼接");
String names = list.stream()
  .map(User::getName)
  .collect(Collectors.joining(","));
System.out.println("names = " + names);

输出如下:

字符串拼接

names = 张三,李四,王五,赵六,田七,小明,小红,小华,小丽,小何

6.7 groupingBy

分组,如将user根据学校分组、先按学校分再按年龄分、每个大学的user人数、每个大学不同年龄的人数:

System.out.println("分组");
Map<String, List<User>> collect1 = list.stream()
  .collect(Collectors.groupingBy(User::getSchool));
Map<String, Map<Integer, Long>> collect2 = list.stream()
  .collect(Collectors.groupingBy(User::getSchool, Collectors.groupingBy(User::getAge, Collectors.counting())));
Map<String, Long> collect3 = list.stream()
  .collect(Collectors.groupingBy(User::getSchool, Collectors.counting()));
Map<String, Map<Integer, Map<String, Long>>> collect4 = list.stream()
  .collect(Collectors.groupingBy(User::getSchool, Collectors.groupingBy(User::getAge, Collectors.groupingBy(User::getName,Collectors.counting()))));

System.out.println("collect1 = " + collect1);
System.out.println("collect2 = " + collect2);
System.out.println("collect3 = " + collect3);
System.out.println("collect4 = " + collect4);

输出如下:

分组

collect1 = {浙江大学=[User{id=8, name='小华', age=14, school='浙江大学'}, User{id=9, name='小丽', age=17, school='浙江大学'}, User{id=10, name='小何', age=10, school='浙江大学'}], 北京大学=[User{id=5, name='田七', age=25, school='北京大学'}, User{id=6, name='小明', age=16, school='北京大学'}, User{id=7, name='小红', age=14, school='北京大学'}], 清华大学=[User{id=1, name='张三', age=10, school='清华大学'}, User{id=2, name='李四', age=12, school='清华大学'}, User{id=3, name='王五', age=15, school='清华大学'}, User{id=4, name='赵六', age=12, school='清华大学'}]}

collect2 = {浙江大学={17=1, 10=1, 14=1}, 北京大学={16=1, 25=1, 14=1}, 清华大学={10=1, 12=2, 15=1}}

collect3 = {浙江大学=3, 北京大学=3, 清华大学=4}

collect4 = {浙江大学={17={小丽=1}, 10={小何=1}, 14={小华=1}}, 北京大学={16={小明=1}, 25={田七=1}, 14={小红=1}}, 清华大学={10={张三=1}, 12={李四=1, 赵六=1}, 15={王五=1}}}

7. 构建流

7.1 由值构建流

使用静态方法 Stream.of,通过显式值创建一个流。

Stream<String> stream=Stream.of("Java","Python","Go");
stream.forEach(System.out::println);

7.2 由数组创建流

使用静态方法 Arrays.stream 从数组创建一个流。

int[] numbers= {1,2,3,4,5,6};
IntStream stream=Arrays.stream(numbers);
stream.forEach(System.out::println);

7.3 由文件生成流

Stream<String> lines=null;
try {
  lines=Files.lines(Paths.get("data.txt"),Charset.defaultCharset());	
  lines.forEach(System.out::println);
} catch (IOException e) {

  e.printStackTrace();
}finally {
  lines.close();
}

7.4 由函数生成流:创建无限流

其迭代的一般格式如下:

/*
* iterate方法接受一个初始值(在这里是0),还有一个依次应用在每个产生的新值上的Lambda(UnaryOperator<t>类型)
* 这里,我们使用Lambda n-> n+2,返回的是前一个元素加上2
*/
Stream.iterate(0,n->n+2)
  .limit(10)
  .forEach(System.out::println);

例如,如果需要迭代产生斐波那契数列,其代码如下:

Stream.iterate(new int[] {0,1},t->new int[] {t[1],t[0]+t[1]})
  .limit(10)
  .forEach(t->{System.out.println(t[0]+" "+t[1]);});

还有一种情况是生成,例如其生成10个随机数的代码如下,

Stream.generate(Math::random)
  .limit(10)
  .forEach(System.out::println);

1, 25=1, 14=1}, 清华大学={10=1, 12=2, 15=1}}

collect3 = {浙江大学=3, 北京大学=3, 清华大学=4}

collect4 = {浙江大学={17={小丽=1}, 10={小何=1}, 14={小华=1}}, 北京大学={16={小明=1}, 25={田七=1}, 14={小红=1}}, 清华大学={10={张三=1}, 12={李四=1, 赵六=1}, 15={王五=1}}}

8 构建流

8.1 由值构建流

使用静态方法 Stream.of,通过显式值创建一个流。

Stream<String> stream=Stream.of("Java","Python","Go");
stream.forEach(System.out::println);

8.2 由数组创建流

使用静态方法 Arrays.stream 从数组创建一个流。

int[] numbers= {1,2,3,4,5,6};
IntStream stream=Arrays.stream(numbers);
stream.forEach(System.out::println);

8.3 由文件生成流

Stream<String> lines=null;
try {
  lines=Files.lines(Paths.get("data.txt"),Charset.defaultCharset());	
  lines.forEach(System.out::println);
} catch (IOException e) {

  e.printStackTrace();
}finally {
  lines.close();
}

8.4 由函数生成流:创建无限流

其迭代的一般格式如下:

/*
* iterate方法接受一个初始值(在这里是0),还有一个依次应用在每个产生的新值上的Lambda(UnaryOperator<t>类型)
* 这里,我们使用Lambda n-> n+2,返回的是前一个元素加上2
*/
Stream.iterate(0,n->n+2)
  .limit(10)
  .forEach(System.out::println);

例如,如果需要迭代产生斐波那契数列,其代码如下:

Stream.iterate(new int[] {0,1},t->new int[] {t[1],t[0]+t[1]})
  .limit(10)
  .forEach(t->{System.out.println(t[0]+" "+t[1]);});

还有一种情况是生成,例如其生成10个随机数的代码如下,

Stream.generate(Math::random)
  .limit(10)
  .forEach(System.out::println);

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

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

相关文章

zookeeper 3.8.1安装和入门使用

1、zookeeper环境搭建&#xff08;Windows单机版&#xff09; 1.1、 前提 必须安装jdk 1.8&#xff0c;配置jdk环境变量&#xff0c;步骤略 1.2、安装zookeeper 地址&#xff1a;https://zookeeper.apache.org/ 1.2.1、选择releases版本 1.2.2、下载安装包并解压 1.2.3、配…

大厂面试解码:如何准备Google, Amazon等公司的面试

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

Spring Session中会将会话ID记录到标准输出流中危漏洞CVE-2023-20866

文章目录 0.前言漏洞受影响的Spring产品和版本 1.参考文档2.基础介绍描述 3.解决方案3.1. 升级版本 4.HeaderHttpSessionIdResolver 解析5. Spring Session 使用教程 0.前言 背景&#xff1a;公司项目扫描到 CVE-2023-20866&#xff1a;在Spring Session中会将会话ID记录到标准…

WevSocket(java基于spring框架实现)

一、概述 本文基于spring-boot-starter-websocket简单的完成收发信息功能&#xff0c;使用spring框架进行实现。 二、相关配置 spring:2.0.2&#xff0c;jdk:1.8.202&#xff0c;maven:3.3.9 因为spring和maven有版本匹配的要求&#xff0c;请大家注意自己的版本是否匹配 …

专线连接交换机设置 – 如何实现高效率的网络连接?

专线链接交换机设置 – 如何实现高效率的网络连接&#xff1f; 什么是专线连接交换机&#xff1f; 在现代互联网中&#xff0c;网络连接的快速和高效是至关重要的。尤其是对于需要大量数据传输和保证网络稳定性的企业和组织来说&#xff0c;专线连接交换机是一项非常重要的技…

华为云Stack的学习(四)

五、Service OM资源管理 1.Service OM简介 1.1 Service OM介绍 在华为云Stack解决方案中&#xff0c;Service OM是FusionSphere OpenStack的操作管理界面&#xff0c;是资源池&#xff08;计算、存储、网络&#xff09;以及基础云服务的管理工具。 1.2 Service OM定位 Serv…

分类算法系列②:KNN算法

目录 KNN算法 1、简介 2、原理分析 数学原理 相关公式及其过程分析 距离度量 k值选择 分类决策规则 3、API 4、⭐案例实践 4.1、分析 4.2、代码 5、K-近邻算法总结 &#x1f343;作者介绍&#xff1a;准大三网络工程专业在读&#xff0c;努力学习Java&#xff0c;涉…

Vue-关于路由规则模块的封装

路由的封装抽离 对路由的封装进行封装&#xff0c;方便main.js文件维护 首先&#xff1a; 我们需要再src文件夹中创建一个router文件夹&#xff0c;在里面在创建一个index.js文件夹。 然后&#xff1a; 我们再index.js文件夹中进行封装路由规则 import Find from /views/F…

技术深入解析与教程:网络安全技术探秘

第一章&#xff1a;引言 在当今数字化时代&#xff0c;网络安全已经成为了重要议题。随着各种信息和业务在网络上的传输与存储&#xff0c;安全问题也日益突出。本文将带您深入探讨网络安全领域中的关键技术&#xff0c;涵盖渗透测试、漏洞挖掘以及恶意软件分析等方面&#xf…

opencv android sdk 使用中的问题

Plugin with id ‘kotlin-android’ not found 在build.gradle(:app)中添加以下内容 buildscript {ext {Kotlin_Verion "1.9.10"}dependencies {classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$Kotlin_Verion"}repositories {mavenCentral()} …

SpringBoot通过@Cacheable注解实现缓存功能

目录 一、Spring从3.1开始支持Cache二、Cacheable常用属性1、value/cacheNames2、key3、condition4、unless5、keyGenerator6、sync7、cacheManager 三、整合步骤1、加入pom2、启动类加EnableCaching注解3、controller或service加Cacheable注解即可 四、代码实例五、Spring Boo…

Linux下批量创建文件夹

检测文件是否存在 这里的文件包含普通文件或者是目录文件,下面是CentOS 7环境下的测试. #include <sys/stat.h> #include <unistd.h> #include <iostream>int main() {int ret access("../lesson01/file.txt", F_OK);if (ret 0){std::cout <…

经管博士科研基础【6】:如何理解箱式图

箱形图,也叫盒须图,盒式图,boxplot。有95%的把握猜中你现在已经不太确定,这图中有几条线?每条线代表什么意思?中间的那条线代表的究竟是算数平均数还是中位数,还是众数? 再问的深点,箱形图存在的意义为何?之于数据分析的实践意义在哪里? 接下来,带你从概念开始,…

如何回答‘行为面试题’:用实例展示你的能力

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

Linux 8 下的容器引擎Podman概述

一、前言 最近在进行OS国产化交流中&#xff0c;了解到部分业务迁移到BClinux 8.2或Anolis 8.2时&#xff0c;原有docker业务需要迁移到新的容器平台&#xff1a;Podman&#xff0c;来完成容器的新的管理。Podman&#xff08;全称 Pod Manager&#xff09;是一款用于在 Linux 系…

MOS管的损耗分析

目的 1、MOS管的损耗分类&#xff1a; 开关损耗&#xff1a; 栅驱动损耗&#xff1a; 导通损耗&#xff1a; 主要内容 MOS管损耗主要有开关损耗&#xff08;开通损耗和关断损耗&#xff0c;关注参数Cgd(Crss)&#xff09;、栅极驱动损耗&#xff08;关注参数Qg&#xff09;和…

面试流程解析:从初面到终面,程序员需要注意什么

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

RabbitMQ 的快速使用

docker部署rabbitmq # management才有管理页面 docker pull rabbitmq:management# 新建容器并运行 docker run \-e RABBITMQ_DEFAULT_USERadmin \ -e RABBITMQ_DEFAULT_PASSadmin \ -v mq-plugins:/plugins \--name mq \--hostname mq \-p 15672:15672 \-p 5672:5672 \-itd \ra…

客服系统哪个好用?

在当今竞争激烈的商业环境中&#xff0c;良好的客户服务是企业成功的关键因素之一。通过提供优质的客户服务&#xff0c;企业可以吸引、留住、回馈顾客&#xff0c;增加口碑宣传&#xff0c;提高产品或服务质量&#xff0c;同时还可以减少客户投诉率&#xff0c;从而为企业带来…

docker容器运行成功但无法访问,原因分析及对应解决方案(最新,以Tomcat为例,亲测有效)

原因分析&#xff1a; 是否能访问当运行docker容器虚拟机&#xff08;主机&#xff09;地址 虚拟机对应的端口号是否开启或者防墙是否关闭 端口映射是否正确&#xff08;这个是我遇到的&#xff09; tomcat下载的是最新版&#xff0c;docker运行后里面是没有东西的&am…