Spring提供的SPEL表达式

SPEL

1. 概述

SpEL是Spring框架中用于表达式语言的一种方式。它类似于其他编程语言中的表达式语言,用于在运行时计算值或执行特定任务。
SpEL提供了一种简单且强大的方式来访问和操作对象的属性、调用对象的方法,以及实现运算、条件判断等操作。它可以被用于XML和注解配置中,可以用于许多Spring框架中的特性,如依赖注入、AOP、配置文件等。
SpEL表达式可以在字符串中进行定义,使用特殊的语法和符号来表示特定的操作。例如,可以使用${expression}来表示一个SpEL表达式,其中expression是具体的SpEL语句。
SpEL支持各种操作和函数,包括算术运算、逻辑运算、条件判断、正则表达式匹配、集合操作等。它还支持访问上下文中的变量和参数,以及调用对象的方法

2. 基础语法学习案例


import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.junit.Test;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.SimpleEvaluationContext;
import org.springframework.expression.spel.support.StandardEvaluationContext;import java.util.*;/*** SPEL表达式案例** @author xuyuan* @see EvaluationContext* @see SimpleEvaluationContext 定制化提供特定的上下文对象,控制读写权限,可以只读如下的SimpleEvaluationContext.forReadOnlyDataBinding().build()* SimpleEvaluationContext.forReadOnlyDataBinding().build():* 适用于简单的、只读的数据绑定场景。* 性能较好,但功能有限。* 不支持复杂的表达式操作。* <p>* new StandardEvaluationContext(obj):* 适用于复杂的表达式求值场景。* 功能全面,支持所有SPEL特性。* 可以设置根对象和其他上下文信息,灵活性高。*/
public class SpelExam {/*** 操作字面量*/@Testpublic void test() {ExpressionParser parser = new SpelExpressionParser();// 获取字符串 "Hello World"String helloWorld = parser.parseExpression("'Hello World'").getValue(String.class);System.out.println(helloWorld);// double类型 6.0221415E23double avogadrosNumber = parser.parseExpression("6.0221415E+23").getValue(Double.class);System.out.println(avogadrosNumber);// int类型 2147483647int maxValue = parser.parseExpression("0x7FFFFFFF").getValue(Integer.class);System.out.println(maxValue);// trueboolean trueValue = parser.parseExpression("true").getValue(Boolean.class);System.out.println(trueValue);// nullObject nullValue = parser.parseExpression("null").getValue();System.out.println(nullValue);}/*** 操作对象*/@Testpublic void test2() {// 定义Parser,可以定义全局的parserExpressionParser parser = new SpelExpressionParser();// 注意!属性名的第一个字母不区分大小写。 birthdate.year等效于Birthdate.Year// 取出Inventor 中,birthdate属性的year属性Inventor zhangsan = new Inventor("zhangsan", new Date(), "China");// 定义StandardEvaluationContext ,传入一个操作对象StandardEvaluationContext zhangsanContext = new StandardEvaluationContext(zhangsan);int year = parser.parseExpression("birthdate.year + 1900").getValue(zhangsanContext, Integer.class);System.out.println(year); // 2025// 取出Inventor的placeOfBirth的city属性PlaceOfBirth placeOfBirth = new PlaceOfBirth("长沙", "中国");zhangsan.setPlaceOfBirth(placeOfBirth);String city = parser.parseExpression("placeOfBirth.City").getValue(zhangsanContext, String.class);System.out.println(city); // 长沙}/*** 操作数组和List*/@Testpublic void test3() {// 定义Parser,可以定义全局的parserExpressionParser parser = new SpelExpressionParser();EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();// 省略数据初始化Society ieee = new Society();Inventor tesla = new Inventor("Tesla", "USA");ieee.getMembers().add(tesla);ieee.getMembers().add(new Inventor("BYD", "CN"));ieee.getMembers().add(new Inventor("BMW", "GE"));ieee.getMembers().add(new Inventor("FLL", "FR"));tesla.setInventions(new String[]{"Lightning", "Telephone", "Computer", "Electricity", "Electric Motor", "Electric Engine", "Electric Car"});String value = parser.parseExpression("inventions[3]").getValue(context, tesla, String.class);System.out.println("取出tesla对象的inventions 第四个数据:" + value);String name = parser.parseExpression("Members[0].Name").getValue(context, ieee, String.class);System.out.println("取出ieee对象的第一个Member的name属性:" + name);String invention = parser.parseExpression("Members[0].Inventions[6]").getValue(context, ieee, String.class);System.out.println("取出ieee对象的第一个Member的第七个Inventions:" + invention);}/*** 操作Map*/@Testpublic void test4() {ExpressionParser parser = new SpelExpressionParser();EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();Society ieee = new Society();ieee.getOfficers().put("president", new Inventor("Tesla", "USA"));ieee.getOfficers().put("advisors", new Inventor("BYD", "CN"));ieee.getOfficers().put("secretary", new Inventor("BMW", "GE"));ieee.getOfficers().put("treasurer", new Inventor("FLL", "FR"));String name = parser.parseExpression("officers['advisors'].name").getValue(context, ieee, String.class);System.out.println("取出ieee对象的advisors的name属性:" + name);}/*** 内嵌List/Map*/@Testpublic void test5() {// 定义Parser,可以定义全局的parserExpressionParser parser = new SpelExpressionParser();// [1, 2, 3, 4]List numbers = (List) parser.parseExpression("{1,2,3,4}").getValue();System.out.println(numbers);// 嵌套: [[a, b], [x, y]]List listOfLists = (List) parser.parseExpression("{{'a','b'},{'x','y'}}").getValue();System.out.println(listOfLists);// {name=Nikola, dob=10-July-1856}Map inventorInfo = (Map) parser.parseExpression("{name:'Nikola',dob:'10-July-1856'}").getValue();System.out.println(inventorInfo);// 嵌套:{name={first=Nikola, last=Tesla}, dob={day=10, month=July, year=1856}}Map mapOfMaps = (Map) parser.parseExpression("{name:{first:'Nikola',last:'Tesla'},dob:{day:10,month:'July',year:1856}}").getValue();System.out.println(mapOfMaps);// List与Map可以嵌套使用,互相结合。// 嵌套:[{name={first=Nikola, last=Tesla}}, {dob={day=10, month=July, year=1856}}]List listOfMaps = (List) parser.parseExpression("{{name:{first:'Nikola',last:'Tesla'}},{dob:{day:10,month:'July',year:1856}}}").getValue();System.out.println(listOfMaps);}/*** 构建数组*/@Testpublic void test6() {ExpressionParser parser = new SpelExpressionParser();int[] numbers1 = parser.parseExpression("new int[4]").getValue(int[].class);// 数组并初始化int[] numbers2 = parser.parseExpression("new int[]{1,2,3}").getValue(int[].class);// 多维数组int[][] numbers3 = parser.parseExpression("new int[4][5]").getValue(int[][].class);}/*** 调用方法*/@Testpublic void test7() {ExpressionParser parser = new SpelExpressionParser();// 调用substring方法System.out.println(parser.parseExpression("'abc'.substring(1, 3)").getValue(String.class));// 调用societyContext中对象的isMember方法,并传值。StandardEvaluationContext societyContext = new StandardEvaluationContext(new Society());boolean isMember = parser.parseExpression("isMember('Mihajlo Pupin')").getValue(societyContext, Boolean.class);}/*** 关系运算* 每个符号操作符也可以被指定为纯字母的等价物。这避免了所使用的符号对于嵌入表达式的文档类型具有特殊含义的问题(例如在XML文档中)。所有文本操作符都不区分大小写。对应的文本是:* lt (<)* gt (>)* le (<=)* ge (>=)* eq (==)* ne (!=)* div (/)* mod (%)* not (!)*/@Testpublic void test8() {ExpressionParser parser = new SpelExpressionParser();boolean trueValue = parser.parseExpression("2 == 2").getValue(Boolean.class);boolean falseValue = parser.parseExpression("2 < -5.0").getValue(Boolean.class);boolean trueValue1 = parser.parseExpression("'black' < 'block'").getValue(Boolean.class);}/*** instanceof 和 正则表达式的匹配操作符* 使用基本类型时要小心,因为它们会立即被装箱为包装器类型,所以1 instanceof T(int)会计算为false,而1 instanceof T(Integer)会计算为true。*/@Testpublic void test9() {ExpressionParser parser = new SpelExpressionParser();boolean value = parser.parseExpression("'xyz' instanceof T(Integer)").getValue(Boolean.class);boolean trueValue = parser.parseExpression("'5.00' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class);boolean falseValue = parser.parseExpression("'5.0067' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class);}/*** 逻辑运算符:and, or, not*/@Testpublic void test10() {ExpressionParser parser = new SpelExpressionParser();StandardEvaluationContext societyContext = new StandardEvaluationContext(new Society());boolean value = parser.parseExpression("true and false").getValue(Boolean.class);String expression1 = "isMember('Nikola Tesla') and isMember('Mihajlo Pupin')";boolean value1 = parser.parseExpression(expression1).getValue(societyContext, Boolean.class);boolean value2 = parser.parseExpression("true or false").getValue(Boolean.class);String expression2 = "isMember('Nikola Tesla') or isMember('Albert Einstein')";boolean valu3 = parser.parseExpression(expression2).getValue(societyContext, Boolean.class);boolean value4 = parser.parseExpression("!true").getValue(Boolean.class);String expression3 = "isMember('Nikola Tesla') and !isMember('Mihajlo Pupin')";boolean value5 = parser.parseExpression(expression3).getValue(societyContext, Boolean.class);}/*** 数学计算符*/@Testpublic void test11() {ExpressionParser parser = new SpelExpressionParser();parser.parseExpression("1 + 1").getValue(Integer.class);  // 2parser.parseExpression("'test' + ' ' + 'string'").getValue(String.class);  // 'test string'parser.parseExpression("1 - -3").getValue(Integer.class);  // 4parser.parseExpression("1000.00 - 1e4").getValue(Double.class);  // -9000parser.parseExpression("-2 * -3").getValue(Integer.class);  // 6parser.parseExpression("6 / -3").getValue(Integer.class);  // -2parser.parseExpression("8.0 / 4e0 / 2").getValue(Double.class);  // 1.0parser.parseExpression("7 % 4").getValue(Integer.class);  // 3parser.parseExpression("8 / 5 % 2").getValue(Integer.class);  // 1parser.parseExpression("1+2-3*8").getValue(Integer.class);  // -21}/*** 类型获取符:T()* T(Type):用于引用静态类型。* T(Type).staticMethod():用于调用静态方法。* T(Type).STATIC_FIELD:用于访问静态字段。* instanceof T(Type):用于类型检查。*/@Testpublic void test12() {ExpressionParser parser = new SpelExpressionParser();Class dateClass = parser.parseExpression("T(java.util.Date)").getValue(Class.class);Class stringClass = parser.parseExpression("T(String)").getValue(Class.class);boolean trueValue = parser.parseExpression("T(java.math.RoundingMode).CEILING < T(java.math.RoundingMode).FLOOR").getValue(Boolean.class);}/*** 调用构造函数*/@Testpublic void test13() {System.out.println(Inventor.class.getName());ExpressionParser parser = new SpelExpressionParser();StandardEvaluationContext societyContext = new StandardEvaluationContext(new Society());Inventor einstein = parser.parseExpression("new com.xuyuan.spring.spel.SpelExam.Inventor('Albert Einstein', 'German')").getValue(Inventor.class);// 创建一个新的Inventor,并且添加到members的list中parser.parseExpression("Members.add(com.xuyuan.spring.spel.SpelExam.Inventor('Albert Einstein', 'German'))").getValue(societyContext);System.out.println(societyContext.getRootObject().getValue());}/*** Spel变量* #variableName语法在表达式中引用变量*/@Testpublic void test14() {ExpressionParser parser = new SpelExpressionParser();EvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build();context.setVariable("newName", "Mike Tesla"); // 设置变量Inventor tesla = new Inventor("Nikola Tesla", "Serbian");// 获取变量newName,并将其赋值给name属性parser.parseExpression("Name = #newName").getValue(context, tesla);System.out.println(tesla.getName());  // "Mike Tesla"}/*** #this变量引用当前的评估对象(根据该评估对象解析非限定引用)。* #root变量总是被定义并引用根上下文对象。虽然#this可能会随着表达式的组成部分的计算而变化,但是#root总是指根。*/@Testpublic void test15() {// 创建一个Integer数组List<Integer> primes = new ArrayList<Integer>();primes.addAll(Arrays.asList(2, 3, 5, 7, 11, 13, 17));ExpressionParser parser = new SpelExpressionParser();EvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build();context.setVariable("primes", primes);List<Integer> primesGreaterThanTen = (List<Integer>) parser.parseExpression("#primes.?[#this>10]").getValue(context);System.out.println(primesGreaterThanTen);}/*** 三元表达式*/@Testpublic void test16() {ExpressionParser parser = new SpelExpressionParser();String expression = "10 > 5 ? 'ten is greater than five' : 'ten is not greater than five'";parser.parseExpression(expression).getValue(String.class);}/*** Elvis操作符*/@Testpublic void test17() {ExpressionParser parser = new SpelExpressionParser();String name = "Elvis Presley";String displayName = (name != null ? name : "Unknown");String name1 = parser.parseExpression("name?:'Unknown'").getValue(String.class);System.out.println(name1);  // 'Unknown'}/*** 安全导航运算符:obj?.prop* 安全导航操作符用于避免NullPointerException,来自Groovy语言。* 通常,当引用一个对象时,可能需要在访问该对象的方法或属性之前验证它不为null。为了避免这种情况,安全导航运算符返回null,而不是引发异常。以下示例显示了如何使用安全导航运算符*/@Testpublic void test18() {ExpressionParser parser = new SpelExpressionParser();EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();Inventor tesla = new Inventor("Nikola Tesla", "Serbian");tesla.setPlaceOfBirth(new PlaceOfBirth("Smiljan", "Croatia"));String city = parser.parseExpression("PlaceOfBirth?.City").getValue(context, tesla, String.class);System.out.println(city);  // Smiljantesla.setPlaceOfBirth(null);city = parser.parseExpression("PlaceOfBirth?.City").getValue(context, tesla, String.class);System.out.println(city);  // null - does not throw NullPointerException!!!}/*** 集合选择:?[predicate]*/@Testpublic void test19() {Society ieee = new Society();ieee.getMembers().add(new Inventor("Tesla", "USA"));ieee.getMembers().add(new Inventor("BYD", "CN"));ieee.getMembers().add(new Inventor("BMW", "GE"));ieee.getMembers().add(new Inventor("FLL", "FR"));ExpressionParser parser = new SpelExpressionParser();StandardEvaluationContext context = new StandardEvaluationContext(ieee);// 语法.?[selectionExpression]List<Inventor> list = parser.parseExpression("Members.?[Nationality == 'Serbian']").getValue(context, List.class);Map<String, Integer> map = new HashMap<>();context.setVariable("map", map);map.put("Tesla0", 28);map.put("Tesla1", 26);map.put("Tesla2", 25);// 返回value小于27的值// 使用参数化的 Map 类型Map<String, Integer> newMap = parser.parseExpression("#map.?[value < 27]").getValue(context, Map.class);System.out.println(newMap);  // 输出符合条件的键值对}/*** 集合投影:![expression]*/@Testpublic void test20() {Society ieee = new Society();ieee.getMembers().add(new Inventor("Tesla", "USA"));ieee.getMembers().add(new Inventor("BYD", "CN"));ieee.getMembers().add(new Inventor("BMW", "GE"));ieee.getMembers().add(new Inventor("FLL", "FR"));ExpressionParser parser = new SpelExpressionParser();StandardEvaluationContext context = new StandardEvaluationContext(ieee);List placesOfBirth = parser.parseExpression("Members.![placeOfBirth?.city]").getValue(context, List.class);}/*** 表达式模板:#{expression}* 通常使用#{}作为模板,与字符串拼接*/@Testpublic void test21() {ExpressionParser parser = new SpelExpressionParser();// 通常使用#{}作为模板,与字符串拼接起来String randomPhrase = parser.parseExpression("random number is #{T(java.lang.Math).random()}", new TemplateParserContext()).getValue(String.class);System.out.println(randomPhrase); // "random number is 0.7038186818312008"}@Data@AllArgsConstructor@NoArgsConstructorclass PlaceOfBirth {private String city;private String country;}@Data@AllArgsConstructor@NoArgsConstructorclass Society {private String name;public String Advisors = "advisors";public String President = "president";private List<Inventor> members = new ArrayList<>();private Map officers = new HashMap();public boolean isMember(String name) {for (Inventor inventor : members) {if (inventor.getName().equals(name)) {return true;}}return false;}}@Data@NoArgsConstructor@AllArgsConstructorclass Inventor {private String name;private String nationality;private String[] inventions;private Date birthdate;private PlaceOfBirth placeOfBirth;public Inventor(String name, String nationality) {GregorianCalendar c = new GregorianCalendar();this.name = name;this.nationality = nationality;this.birthdate = c.getTime();}public Inventor(String name, Date birthdate, String nationality) {this.name = name;this.nationality = nationality;this.birthdate = birthdate;}}}

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

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

相关文章

【Azure 架构师学习笔记】- Azure Databricks (14) -- 搭建Medallion Architecture part 2

本文属于【Azure 架构师学习笔记】系列。 本文属于【Azure Databricks】系列。 接上文 【Azure 架构师学习笔记】- Azure Databricks (13) – 搭建Medallion Architecture part 1 前言 上文搭建了ADB 与外部的交互部分&#xff0c;本篇搭建ADB 内部配置来满足medallion 架构。…

vulnhub靶场之【digitalworld.local系列】的torment靶机

前言 靶机&#xff1a;digitalworld.local-torment&#xff0c;IP地址为192.168.10.12 攻击&#xff1a;kali&#xff0c;IP地址为192.168.10.6 kali采用VMware虚拟机&#xff0c;靶机选择使用VMware打开文件&#xff0c;都选择桥接网络 这里官方给的有两种方式&#xff0c…

docker-compose部署mongodb副本集集群

生成密钥文件 ​ openssl rand -base64 756 > mongodb.key chmod 400 mongodb.key # 权限必须为400‌:ml-citation{ref="4" data="citationList"} chown 999:999 mongodb.key # MongoDB容器用户ID为999‌:ml-citation{ref="4" data="…

k8s v1.28.15部署(kubeadm方式)

k8s部署&#xff08;kubeadm方式&#xff09; 部署环境及版本 系统版本&#xff1a;CentOS Linux release 7.9.2009 k8s版本&#xff1a;v1.28.15 docker版本&#xff1a;26.1.4 containerd版本&#xff1a;1.6.33 calico版本&#xff1a;v3.25.0准备 主机ip主机名角色配置1…

Redis特性总结

一、速度快 正常情况下&#xff0c;Redis 执⾏命令的速度⾮常快&#xff0c;官⽅给出的数字是读写性能可以达到 10 万 / 秒&#xff0c;当然这也取决于机器的性能&#xff0c;但这⾥先不讨论机器性能上的差异&#xff0c;只分析⼀下是什么造就了 Redis 如此之快&#xff0c;可以…

C# Unity 面向对象补全计划 之 索引器与迭代器

本文仅作学习笔记与交流&#xff0c;不作任何商业用途&#xff0c;作者能力有限&#xff0c;如有不足还请斧正 本篇有部分内容出自唐老狮,唐老师网站指路:全部 - 游习堂 - 唐老狮创立的游戏开发在线学习平台 - Powered By EduSoho 目录 1.索引器 2.迭代器 1.索引器 我的理解 索…

深度学习PyTorch之13种模型精度评估公式及调用方法

深度学习pytorch之22种损失函数数学公式和代码定义 深度学习pytorch之19种优化算法&#xff08;optimizer&#xff09;解析 深度学习pytorch之4种归一化方法&#xff08;Normalization&#xff09;原理公式解析和参数使用 深度学习pytorch之简单方法自定义9类卷积即插即用 实时…

C++ Primer 拷贝控制和资源管理

欢迎阅读我的 【CPrimer】专栏 专栏简介&#xff1a;本专栏主要面向C初学者&#xff0c;解释C的一些基本概念和基础语言特性&#xff0c;涉及C标准库的用法&#xff0c;面向对象特性&#xff0c;泛型特性高级用法。通过使用标准库中定义的抽象设施&#xff0c;使你更加适应高级…

【无监督学习】层次聚类步骤及matlab实现

层次聚类 &#xff08;四&#xff09;层次聚类1.算法步骤2.MATLAB 实现参考资料 &#xff08;四&#xff09;层次聚类 层次聚类是一种通过逐层合并或分裂数据点构建树状结构&#xff08;树状图&#xff0c;Dendrogram&#xff09;的聚类方法。它分为两种类型&#xff1a; 凝聚…

02 HarmonyOS Next仪表盘案例详解(一):基础篇

温馨提示&#xff1a;本篇博客的详细代码已发布到 git : https://gitcode.com/nutpi/HarmonyosNext 可以下载运行哦&#xff01; 文章目录 1. 项目概述2. 技术架构2.1 文件结构2.2 ArkTS 语言特性装饰器的使用 3. 数据结构设计3.1 接口定义3.2 数据初始化 4. 生命周期与页面路由…

微信小程序接入deepseek

先上效果 话不多说&#xff0c;直接上代码&#xff08;本人用的hbuilder Xuniapp&#xff09; <template><view class"container"><!-- 聊天内容区域 --><scroll-view class"chat-list" scroll-y :scroll-top"scrollTop":…

istio入门到精通-2

上部分讲到了hosts[*] 匹配所有的微服务&#xff0c;这部分细化一下 在 Istio 的 VirtualService 配置中&#xff0c;hosts 字段用于指定该虚拟服务适用的 目标主机或域名。如果使用具体的域名&#xff08;如 example.com&#xff09;&#xff0c;则只有请求的主机 域名与 exa…

6. PromQL的metric name(在node exporter复制下来交给AI解释的)

目录 前言&#xff1a; Go 运行时指标&#xff1a; Go 内存统计指标&#xff1a; CPU 指标&#xff1a; 内存指标&#xff1a; 磁盘指标&#xff1a; 网络指标&#xff1a; 系统指标&#xff1a; 前言&#xff1a; 写这个得目的是为了后续方便查询&#xff0c;因为在pro…

图像形成与计算机视觉基础

1. 图像形成的基本原理 图像形成是物理世界与传感器&#xff08;如胶片、CCD/CMOS&#xff09;交互的过程&#xff0c;核心是光线的传播与记录。 1.1 直接放置胶片模型 物理原理&#xff1a;物体表面反射的光线直接照射到胶片上&#xff0c;但无任何遮挡或聚焦机制。 问题&a…

Dockerfile概述及编辑

文章目录 Docker 镜像原理操作系统组成部分Docker 镜像原理镜像制作 Dockerfile概念及作用Dockerfile 概念Dockerfile 作用 Dockerfile关键字 案例要求实现步骤 Docker 镜像原理 操作系统组成部分 操作系统组成&#xff1a;进程调度子系统、进程通信子系统、内存管理子系统、…

CES Asia 2025:AR/VR/XR论坛峰会备受瞩目

CES Asia 2025第七届亚洲消费电子技术贸易展&#xff08;赛逸展&#xff09;将在首都北京心盛大举行。作为亚洲极具影响力的消费电子技术展会&#xff0c;此次盛会以“科技重塑生活&#xff0c;创新定义未来”为主题&#xff0c;预计将吸引全球500展商、100,000专业观众参与&am…

【Java线程基础操作详解】

Java线程基础操作详解 前言1. 线程创建1.1 继承Thread类1.2 实现Runnable接口1.3 匿名内部类1.4 lambda表达式 2. 线程中断3. 线程等待4. 线程休眠 前言 在Java编程里&#xff0c;线程是实现多任务处理的关键概念。本文会详细讲解Java中线程的创建、中断、等待以及休眠等操作&…

qt 播放pcm音频

一、获取PCM音频 ffmpeg -i input.mp3 -acodec pcm_s16le -ar 44100 -ac 2 -f s16le output.pcm -acodec pcm_s16le&#xff1a;指定16位小端PCM编码格式&#xff08;兼容性最佳&#xff09;-ar 44100&#xff1a;设置采样率为CD标准44.1kHz&#xff08;可替换为16000/8000等&a…

python实现的可爱卸载动画

在逛掘金时&#xff0c;掘金用户在B站看到的灵感进行的一个卸载窗口的动画效果的实用案例。人类是一种不断在学习的动物&#xff0c;并且是一种模仿能力学习能里比较强的动物。我这里是第三波的学习实践者咯&#xff01; 相对VUE构建动画效果窗口&#xff0c;我更加喜欢用pytho…

出现FullGC的排查思路

一、明确Full GC的触发原因 根据多篇资料&#xff0c;Full GC的触发条件主要包括&#xff1a; 直接调用System.gc()&#xff1a;代码或第三方库&#xff08;如jxl组件&#xff09;可能显式触发。老年代空间不足&#xff1a;大对象直接进入老年代、Minor GC后存活对象过多导致…