-
格式 以-D开头,多个jvm运行参数 用空格隔开 -Dproperty=Value 例如-Dfile.encoding=UTF-8 -Dspring.profiles.active=dev 注意: 1、如果-Dproperty=value的value中包含空格,可以将value使用引号引起来。例如:-Dmyname=“hello world”。 2、如果配置了-Dproperty=value参数,又在程序中使用了System.setProperty对同一个变量进行设置,那么以程序中的设置为准。 优先级关系 代码中的配置>Application中的配置>全局配置 ———————————————— 原文链接:https://blog.csdn.net/iijik55/article/details/126384345
-
背景 之前做项目配数据源信息,一般是把用户名,密码这些都放在一个properties文件中。最近做了个项目是把用户名密码配置在了web容器(tomcat)启动选项里,然后通过${key}注入到properties文件中。 由此产生很多疑问 容器的启动选项是怎么注入到properties文件中的。 容器的启动选项设置的属性的使用范围。 properties中配置的属性是怎么注入到spring配置文件中的。 properties中配置的属性的使用范围。 个人理解 (有问题请指教) 在网上找了很久,没有找到说清楚VM options是什么的相关帖子。我就自己理解一下吧。 写了一个demo,最后发现在VM options中配置的参数,可以通过${}占位符在项目的任何位置注入,比如spring的xml配置文件,properties文件以及通过@Value注入java文件中。 可以理解为容器的启动选项配置的属性是整个web容器的全局变量,可以在容器中的所有项目,所有项目中的所有文件中通过${key}引用到。 关于properties文件 紧接着我顺带深入理解了一下properties文件以及properties中定义的属性在spring中的作用域。 基础操作 首先properties就是一个定义键值对的文件,我们可以通过Properties类加载然后通过getProperty("key")来获取value,参考 通常做法: 但是我们用的最多的是在spring的相关配置中使用properties来收集一些配置属性方便修改。 在spring的xml配置文件中使用 来加载properties文件,然后在xml中用${key}来注入对应value,或者在java类属性上用@Value(${key})来注入对应value。 于是我又产生了一个疑问:在xml中引入的properties文件的作用域是什么,是当前xml文件?是spring容器?还是整个项目? 写了一个demo测了一下,发现xml中引入的properties的属性是容器级别的。比如springmvc系统中会有springmvc子容器和spring核心父容器两个容器,在springmvc.xml中引入的properties的属性只能在springmvc子容器中的bean以及同级别xml配置文件中获取到,而spring父容器中的bean则获取不到,反之亦然。 总结: 容器的启动选项是怎么注入到properties文件中的。解答:我们只需要配置容器启动选项,其他完全由容器实现和处理。 容器的启动选项设置的属性的使用范围。解答:容器中所有项目,项目中所有文件。 properties中配置的属性是怎么注入到spring配置文件中的。解答:我们只需要引入properties文件,其他由spring实现和处理 properties中配置的属性的使用范围。解答:属性引入的容器 ———————————————— 原文链接:https://blog.csdn.net/weixin_35186171/article/details/113548243
-
1:建议下载软件Everything 2:准备好Jetbrains家的相关IDE下载链接:jetbrains.com【安装过程不描述了】 3:建议下载付费的!没钱买正版可以去淘宝1r买激活码几乎全家桶适用,或者找人要 4:安装完后不要打开、否则自动生成配置文件在系统盘!先修改配置文件 二:配置文件 #这个配置可以减少默认在系统盘占用大量内存 1:在一个内存足够的磁盘创建文件夹【随便取,要英文】 2:搜索并打开文件idea.properties 3:分别有四个关键字且有对应的路径 idea.config.path、idea.system.path、idea.plugins.path、idea.log.path #找到第一步创建好的文件夹的路径、替换四个关键字对应的路径。 #注意不要有反斜杠\和中文,若修改当前行数的一行有#号记得删掉,否则为注释不做处理 4:配置成功三:按键配置 #此按键布局的移动键位和Vim编辑器操作有点类似【个人习惯】 #习惯后就不太需要鼠标了 1:打开IDE---Setting---Keymap---右边齿轮---Duplicated【复制一份新的按键布局】 2:搜索文件Windows copy.xml 3:将原来的Windows copy.xml 替换成我的按键布局 四:基础设置【便捷】 1:File---Settings---General---Change font size with Ctrl + Mouse Wheel 【打勾✔】 【Ctrl+鼠标滑轮可缩放大小】 2:File---Settings---Inspections---右边搜索Typo【取消勾勾】【或者是取消Spelling Error】 3:FIle---Settings---plguins---搜索Translation并下载【看个人需求】【这是翻译插件】 4:File---Settings---Editor---Font---Size设置26,字体我推荐JetBrains Mono 5:File---Settings---Appearance---自己看着设置,这里size我选择20。字体自选 6:设置背景 五:方法\函数模板设置【方便查看、看图】 #需要在【方法\函数】前加输入自己设置的模板快捷按键才会生成模板注释 二:点击 1:Abbreviation内我写的是/add代表我输入/add+Tab【在Expand With中设置】就会生成注释 2:这个符号$$里面的参数随便填写,包括前面的Name也是,填完后就可以选择Edit variables 3:填写完成后根据下图就可以翻译一下Expression内表达式的意思,比如date()就是日期然后Okay【不懂下载个百度翻译】 六:类模板设置#创建类文件后会自动生成模板注释 三:具体的模板的变量参数还得看官网给的文档、但是大部分都是相同的 ———————————————— 原文链接:https://blog.csdn.net/qq_38431616/article/details/120272815
-
Android Studio: ~/.config/Google/AndroidStudioPreview2022.3/studio64.vmoptions 其他IDE: ~/.config/JetBrains/RustRover2023.3/rustrover64.vmoptions ~/.config/JetBrains/PyCharm2023.3/pycharm64.vmoptions ~/.config/JetBrains/GoLand2023.1/goland64.vmoptions 以上是安装包默认的配置文件位置,如果设置以下环境变量,则会优先使用环境变量中指定的配置文件: JETBRAINSCLIENT_VM_OPTIONS=/home/jetbra/vmoptions/jetbrainsclient.vmoptions GOLAND_VM_OPTIONS=/home/jetbra/vmoptions/goland.vmoptions WEBSTORM_VM_OPTIONS=/home/jetbra/vmoptions/webstorm.vmoptions PHPSTORM_VM_OPTIONS=/home/jetbra/vmoptions/phpstorm.vmoptions WEBIDE_VM_OPTIONS=/home/jetbra/vmoptions/webide.vmoptions GATEWAY_VM_OPTIONS=/home/jetbra/vmoptions/gateway.vmoptions DATASPELL_VM_OPTIONS=/home/jetbra/vmoptions/dataspell.vmoptions APPCODE_VM_OPTIONS=/home/jetbra/vmoptions/appcode.vmoptions IDEA_VM_OPTIONS=/home/jetbra/vmoptions/idea.vmoptions STUDIO_VM_OPTIONS=/home/jetbra/vmoptions/studio.vmoptions CLION_VM_OPTIONS=/home/jetbra/vmoptions/clion.vmoptions DATAGRIP_VM_OPTIONS=/home/jetbra/vmoptions/datagrip.vmoptions RIDER_VM_OPTIONS=/home/jetbra/vmoptions/rider.vmoptions JETBRAINS_CLIENT_VM_OPTIONS=/home/jetbra/vmoptions/jetbrains_client.vmoptions PYCHARM_VM_OPTIONS=/home/jetbra/vmoptions/pycharm.vmoptions RUBYMINE_VM_OPTIONS=/home/jetbra/vmoptions/rubymine.vmoptions DEVECOSTUDIO_VM_OPTIONS=/home/jetbra/vmoptions/devecostudio.vmoptions ———————————————— 原文链接:https://blog.csdn.net/yinminsumeng/article/details/137033690
-
下拉列表(下拉框)可以确保用户仅从预先给定的选项中进行选择,这样不仅能减少数据输入错误,还能节省时间提高效率。在MS Excel中,我们可以通过 “数据验证” 提供的选项来创建下拉列表,但如果要在Java程序中通过代码实现这一功能,可能需要借助一些第三方库。本文将分享两种使用免费Java库在Excel中创建下拉列表的方法。操作Excel的免费Java控件:Free Spire.XLS for Java. (下载后手动引入jar包或者通过Maven仓库安装均可)方法一:基于字符串数组中的值来创建Excel下拉列表该方法是通过 Free Spire.XLS for Java 提供的 IDataValidation 接口下的 setValue() 方法先定义一个字符串数组作为列表项,然后再通过将 isSuppressDropDownArrow() 方法的参数设置为false 来应用下拉箭头。该方法就等同于在Excel “数据验证” 选项中的 “来源” 中直接输入一串内容作为列表项。Java代码:import com.spire.xls.*;import java.awt.*; public class ExcelDropdownList { public static void main(String[] args) { //创建Workbook对象 Workbook workbook = new Workbook(); //获取第一张工作表 Worksheet sheet = workbook.getWorksheets().get(0); //在指定单元格中添加文本 sheet.getCellRange("B2").setValue("职员"); sheet.getCellRange("B3").setValue("张三"); sheet.getCellRange("C2").setValue("部门"); //设置字体和单元格样式 sheet.getCellRange("B2:C2").getStyle().getFont().isBold(true); sheet.getCellRange("B2:C2").getStyle().getFont().setColor(Color.BLUE); sheet.getCellRange("B2:C3").getStyle().getFont().setSize(11); sheet.getCellRange("B2:C3").setRowHeight(18); sheet.getCellRange("B2:C3").setColumnWidth(12); //设置下拉列表的值 sheet.getCellRange("C3").getDataValidation().setValues(new String[]{"财务部", "采购部", "销售部", "行政部"}); //在指定单元格中创建下拉列表 sheet.getCellRange("C3").getDataValidation().isSuppressDropDownArrow(false); //保存结果文件 workbook.saveToFile("Excel下拉列表.xlsx", ExcelVersion.Version2013); }}方法二:基于单元格区域的内容来创建Excel下拉列表该方法是通过 Validation 类的 setDataRange() 方法指定一个单元格区域中的内容作为下拉列表的数据源。该方法更加灵活,创建后如果你想更新下拉列表的选项,直接更新单元格中的数据即可。效果如图:Java代码:import com.spire.xls.*;import java.awt.*; public class DropdownList { public static void main(String[] args) { //创建Workbook对象 Workbook workbook = new Workbook(); //获取第一张工作表 Worksheet sheet = workbook.getWorksheets().get(0); //在指定单元格中添加文本 sheet.getCellRange("B2").setValue("职员"); sheet.getCellRange("B3").setValue("张三"); sheet.getCellRange("C2").setValue("部门"); sheet.getCellRange("A11").setValue("财务部"); sheet.getCellRange("A12").setValue("采购部"); sheet.getCellRange("A13").setValue("销售部"); sheet.getCellRange("A14").setValue("行政部"); //设置字体和单元格样式 sheet.getCellRange("B2:C2").getStyle().getFont().isBold(true); sheet.getCellRange("B2:C2").getStyle().getFont().setColor(Color.BLUE); sheet.getCellRange("B2:C3").getStyle().getFont().setSize(11); sheet.getCellRange("B2:C3").setRowHeight(18); sheet.getCellRange("B2:C3").setColumnWidth(12); //将指定的单元格区域的内容作为数据源来创建下拉列表 sheet.getCellRange("C3:C4").getDataValidation().setDataRange(sheet.getCellRange("A11:A14")); //保存结果文件 workbook.saveToFile("Excel下拉列表2.xlsx", ExcelVersion.Version2013); }}转载自https://www.cnblogs.com/Yesi/p/18051989
-
在处理PDF文档时,有时需要为文档中的每一页添加页眉和页脚,以包含一些有用的信息,如文档标题、章节名称、日期、页码等。对于需要自动化处理的场景,或者需要在大量文档中添加一致的页眉和页脚,可以通过编程的方式来实现。本文将介绍如何使用Java为PDF文件添加页眉、页脚。所需工具:Free Spire.PDF for Java 免费库。可以点击链接下载最新版本并手动添加引用到你的Java项目中,同时也支持通过Mave仓库安装。方法简介:在以下示例中,我们用到了 PdfCanvas 类的DrawString()、DrawImage() 和 DrawLine() 方法,分别用于在PDF页面上指定位置绘制文本、图片和线条。如果要添加动态的信息如页码、页数、章节编号等,则可以使用Free Spire.PDF for Java提供的PdfPageNumberField、PdfPageCountField 和 PdfSectionNumberField 类,然后再使用Draw() 方法将其绘制到PDF页眉或页脚位置。示例代码:1. 使用Java在PDF中插入页眉import com.spire.pdf.PdfDocument;import com.spire.pdf.PdfPageBase;import com.spire.pdf.graphics.*; import java.awt.*; public class PDFHeader { public static void main(String[] args) { //加载PDF文档 PdfDocument pdf = new PdfDocument(); pdf.loadFromFile("考核.pdf"); //加载图片 PdfImage headerImage = PdfImage.fromFile("logo.jpg"); //获取图片宽度 float width = headerImage.getWidth(); PdfUnitConvertor unitCvtr = new PdfUnitConvertor(); float pointWidth = unitCvtr.convertUnits(width, PdfGraphicsUnit.Pixel, PdfGraphicsUnit.Point); //指定页眉文本 String headerText = "年度绩效考核\nAAA有限责任公司"; //创建字体 PdfTrueTypeFont font = new PdfTrueTypeFont(new Font("宋体", Font.BOLD, 12),true); //创建画笔 PdfBrush brush = PdfBrushes.getRed(); PdfPen pen = new PdfPen(PdfBrushes.getBlack(), 1.0f); //遍历所有PDF页面 for (int i = 0; i < pdf.getPages().getCount(); i++) { //获取指定页面 PdfPageBase page = pdf.getPages().get(i); //在顶部空白区域绘制图像 page.getCanvas().drawImage(headerImage, page.getActualSize().getWidth() - pointWidth - 55, 20); //在顶部空白区域绘制文本 page.getCanvas().drawString(headerText, font, brush, 55, 30); //在顶部空白区域绘制一条线 page.getCanvas().drawLine(pen, new Point(55, 70), new Point((int)page.getActualSize().getWidth() - 55, 70)); } //保存生成PDF文件 pdf.saveToFile("PDF页眉.pdf"); pdf.dispose(); }}以上代码遍历了PDF文档的所有页面,并在每一页的页眉位置添加了文本、图片和分隔线,运行后效果图如下:2. 使用Java在PDF中插入页脚import com.spire.pdf.PdfDocument;import com.spire.pdf.PdfPageBase;import com.spire.pdf.automaticfields.PdfCompositeField;import com.spire.pdf.automaticfields.PdfPageCountField;import com.spire.pdf.automaticfields.PdfPageNumberField;import com.spire.pdf.graphics.*; import java.awt.*;import java.awt.geom.Dimension2D;import java.awt.geom.Point2D; public class PDFFooter { public static void main(String[] args) { //加载PDF文档 PdfDocument pdf = new PdfDocument(); pdf.loadFromFile("考核.pdf"); //创建字体 PdfTrueTypeFont font = new PdfTrueTypeFont(new Font("宋体", Font.BOLD, 12),true); //创建画笔 PdfBrush brush = PdfBrushes.getBlack(); PdfPen pen = new PdfPen(PdfBrushes.getBlack(), 1.0f); //创建页码字段 PdfPageNumberField pageNumberField = new PdfPageNumberField(); //创建页数字段 PdfPageCountField pageCountField = new PdfPageCountField(); //创建一个复合字段,将页数字段和页码字段合并为一个字符串 PdfCompositeField compositeField = new PdfCompositeField(font, brush, "第{0}页/共{1}页", pageNumberField, pageCountField); //获取文本尺寸 Dimension2D fontSize = font.measureString(compositeField.getText()); //获取页面尺寸 Dimension2D pageSize = pdf.getPages().get(0).getSize(); //设置复合字段的位置 compositeField.setLocation(new Point2D.Double((pageSize.getWidth() - fontSize.getWidth())/2, pageSize.getHeight() - 45)); //遍历PDF页面 for (int i = 0; i < pdf.getPages().getCount(); i++) { //获取指定页 PdfPageBase page = pdf.getPages().get(i); //在底部空白区域绘制一条线 page.getCanvas().drawLine(pen, new Point(72, (int) (pageSize.getHeight() - 60)), new Point((int)pageSize.getWidth() - 72, (int) pageSize.getHeight()- 60)); //在底部空白区域绘制复合字段 compositeField.draw(page.getCanvas()); } //保存生成PDF文件 pdf.saveToFile("PDF页脚.pdf"); pdf.dispose(); }}以上代码遍历了PDF文档的所有页面,并在每一页的页脚位置添加了对应的页码、页数信息以及一条分隔线,运行后效果图如下:小结:在不破坏PDF文档布局的情况下,我们可以使用Free Spire.PDF for Java免费库将所需的元素绘制到PDF页面顶部和底部的指定位置来生成自定义页眉页脚,提高PDF文档的可读性和专业性。转载自https://www.cnblogs.com/Yesi/p/18094584
-
JAVA实现树的遍历
-
1.日志系统概述 关于日志系统,其要支撑的核心能力无非是日志的存储以及查看,最好的查看方式当然是实现可视化。目前市面上有成熟的解决方案——ELK,即elastic search+logstash+kibana。前文中我们已经聊过了ELK这条线,本文主要就是基于ELK并在其中加一个MQ作为中间层来流量削峰、异步写日志。 这里首先要声明的是,虽然本文在日志系统中使用到了MQ,但MQ真的是必要的嘛? 这个要看系统的体量了。除非是超大型的分布式架构,服务上百个并且并发量较高,才会考虑用MQ来做一层缓存从而来降低IO压力。如果不是上述情况的话是没有必要上MQ来做一个中间层的。日志作为系统中掺入的"沙子",其量本来就不会很大,一次API调用平均能产生一条日志吗?其实是不见的是吧。所以就这点数据量上MQ这种吞吐量的中间层简直就是杀鸡用牛刀,过度设计,徒增了系统的复杂度了。MQ更多的时候是拿来做移步任务或者定时任务的,用来做业务上的流量削峰或者异步的去做些事情。比如异步的下订单、订单超时取消等。绝大多数时候我们的日志系统的架构,直接让存储去直面日志IO都是能轻轻松松顶得住的。所谓的让存储去直面日志的IO是什么意思?就是比如我走了ELK这条线,那么就直接讲日志往es里面丢就对了。ELK这么用前面已经有文章介绍过了。本文还是聊一聊假设真的到了很极限的中间需要引入MQ的情况。 ELK的搭建这里就不赘述了,前面有文章详细聊过: https://bugman.blog.csdn.net/article/details/135964825?spm=1001.2014.3001.5502 https://bugman.blog.csdn.net/article/details/136017853?spm=1001.2014.3001.5502 https://bugman.blog.csdn.net/article/details/136066171?spm=1001.2014.3001.5502 这里我们只需要关注几个点: 应用的日志如何推到mq中 logstash如何去取mq中存放的日志 2.环境搭建 ELK相关内容: MQ我们选择rabbitMQ,作为一个开箱即食的MQ,rabbitMQ的下载安装网上文章车载斗量,此处就不赘述了。 3.应用如何推日志到MQ 写日志肯定是JAVA的日志框架来负责的,前面有文章已经详细的介绍了JAVA的日志框架: 【JAVA日志框架】JUL,JDK原生日志框架详解。_jul jdk-CSDN博客 JAVA的日志框架总的来说架构都是大同小异的,都是由不同的appender(有的里面叫handler其实都是一个东西)来向不同的地方写日志: 既然要往rabbitMQ里面写日志,那当然就要一个rabbitMQ的appender了。这个appender在哪里?在rabbitMQ的JAVA API依赖中: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency> <dependency> <groupId>org.springframework.amqp</groupId> <artifactId>spring-rabbit</artifactId> </dependency> 然后配置一下日志框架的配置文件即可,这里我们以spring boot默认的日志框架logback为例,在其配置文件中配置好rabbitMQ的appender即可: <configuration> <!-- 定义 RabbitMQ 连接 --> <appender name="RABBIT" class="com.github.logback.amqp.AmqpAppender"> <host>localhost</host> <!-- RabbitMQ 主机地址 --> <port>5672</port> <!-- RabbitMQ 端口 --> <username>guest</username> <!-- RabbitMQ 用户名 --> <password>guest</password> <!-- RabbitMQ 密码 --> <exchange>logs</exchange> <!-- RabbitMQ 交换机 --> <routingKey>logstash</routingKey> <!-- RabbitMQ 路由键 --> <declareExchange>true</declareExchange> <!-- 是否声明交换机 --> <exchangeType>fanout</exchangeType> <!-- 交换机类型 --> <durable>true</durable> <!-- 是否持久化消息 --> <applicationId>myApplication</applicationId> <!-- 应用程序标识 --> <!-- 其他可选配置 --> <!--<declareQueue>true</declareQueue>--> <!--<queue>logQueue</queue>--> <!--<declareBinding>true</declareBinding>--> </appender> <!-- 定义日志输出格式 --> <layout class="ch.qos.logback.classic.PatternLayout"> <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern> </layout> <!-- 根日志输出到 RabbitMQ --> <root level="INFO"> <appender-ref ref="RABBIT"/> </root> </configuration> 4.logstash如何去MQ中取日志 logstash的input可以理解为插件,既然是插件当然就有很多中类型,其中就包括rabbitMQ的(自然也有其它的),下面是logstash从MQ中取数据然后推给es的一份示例: input { rabbitmq { host => "localhost" # RabbitMQ 主机地址 port => 5672 # RabbitMQ 端口 user => "guest" # RabbitMQ 用户名 password => "guest" # RabbitMQ 密码 queue => "logQueue" # RabbitMQ 队列名 durable => true # 是否持久化队列 ack => true # 是否需要手动确认消息 threads => 1 # 线程数 } } output { stdout { codec => rubydebug } # 输出到控制台,可选 elasticsearch { hosts => ["localhost:9200"] # Elasticsearch 主机地址 index => "logstash-%{+YYYY.MM.dd}" # Elasticsearch 索引名 } } 5.如何兼顾分布式链路追踪 这里顺带讨论一个问题,就是在ELK体系中如何去实现分布式链路跟踪。分布式链路跟踪相关内容前面有文章详细讨论过: https://bugman.blog.csdn.net/article/details/135258207?spm=1001.2014.3001.5502 https://bugman.blog.csdn.net/article/details/135258207?spm=1001.2014.3001.5502 其实在ELK中实现分布式链路追踪的方式很简单,思路如下: 仍然在应用侧上链路追踪技术来统一日志格式,然后要进行查询追踪的时候直接使用Kibana的搜索和过滤功能来仅显示与特定跟踪ID或请求ID相关的日志消息,或者利用Kibana的图表功能,将日志数据与分布式追踪数据结合起来,创建可视化的图表和仪表板。你可以根据需要显示请求的整个路径、每个步骤的响应时间、错误率等指标。 ———————————————— 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 原文链接:https://blog.csdn.net/Joker_ZJN/article/details/136357635
-
请问按照要求修改了java目录为src\com\huawei\codecraft后,提交zip文件依然提示程序编译异常
-
大家好,二月的合集又来了,本次涵盖了java,linux,spirng诸多内容供大家学习。 1.Vue中的$nextTick有什么作用?【转】 https://bbs.huaweicloud.com/forum/thread-02109144317537776031-1-1.html 2.基于Python的地图绘制教程【转】 https://bbs.huaweicloud.com/forum/thread-0240144319944756030-1-1.html 3.hcache 介绍(1)--Ehcache 功能特性 【转】 https://bbs.huaweicloud.com/forum/thread-0268144320319800023-1-1.html 4.Java 操作 XML(1)--DOM 方式处理 XML【转】 https://bbs.huaweicloud.com/forum/thread-02109144320463478034-1-1.html 5.Java操作XML(3)--StAX方式处理XML 【转】 https://bbs.huaweicloud.com/forum/thread-0240144320615655031-1-1.html 6.Java操作XML(4)--使用woodstox处理XML【转】 https://bbs.huaweicloud.com/forum/thread-0270144320690142025-1-1.html 7.Java操作XML(5)--使用JDOM处理XML【转】 https://bbs.huaweicloud.com/forum/thread-0240144320817429032-1-1.html 8.Java操作XML(6)--使用dom4j处理XML【转】 https://bbs.huaweicloud.com/forum/thread-02101144320893290020-1-1.html 9.基于原生Go语言开发一个博客系统【转】 https://bbs.huaweicloud.com/forum/thread-0269144558086016006-1-1.html 10.详解Golang如何使用Debug库优化代码【转】 https://bbs.huaweicloud.com/forum/thread-0225144558556243005-1-1.html 11.Python3中的指针你了解吗【转】 https://bbs.huaweicloud.com/forum/thread-0274144558593208011-1-1.html 12.Python绘图实现坐标轴共享与复用详解【转】 https://bbs.huaweicloud.com/forum/thread-02104144558721772010-1-1.html 13.使用Golang开发一个简易版shell【转】 https://bbs.huaweicloud.com/forum/thread-0226144559187797004-1-1.html 14.python导入其它py文件的实现步骤【转】 https://bbs.huaweicloud.com/forum/thread-0284144559442791006-1-1.html 15.Python property函数的具体使用【转】 https://bbs.huaweicloud.com/forum/thread-0259144559705810008-1-1.html 16.正则表达式的神奇世界之表达、匹配和提取全解析【转】 https://bbs.huaweicloud.com/forum/thread-02104144569438876012-1-1.html 17.正则去除中括号(符号)及里面包含的内容(最新推荐)【转】 https://bbs.huaweicloud.com/forum/thread-0226144569604407008-1-1.html 18.Javaweb项目启动Tomcat常见的报错解决方案【转】 https://bbs.huaweicloud.com/forum/thread-0274144571948983013-1-1.html 19.SpringBoot+Vue前后端分离实现审核功能的示例【转】 https://bbs.huaweicloud.com/forum/thread-0269144572025869007-1-1.html 20.Java中Collections.sort()排序方法举例详解【转】 https://bbs.huaweicloud.com/forum/thread-0269144572170830008-1-1.html 21.Java中回调函数 (callback) 及其实际应用场景【转】 https://bbs.huaweicloud.com/forum/thread-0259144572260172012-1-1.html 22.Redis实现商品秒杀的示例代码【转】 https://bbs.huaweicloud.com/forum/thread-0274144574350854015-1-1.html
-
前言回调函数在编程中是一种常见的设计模式,它允许一个函数在特定的时刻或条件下调用另一个函数。在Java中,我们可以通过接口和匿名内部类实现回调函数。本文将详细介绍Java中的回调函数,并提供相关代码示例。一、回调函数的概念回调函数是一种将函数作为参数传递给另一个函数的方法。当特定事件或条件发生时,被传递的函数将被调用。这种方式可以让我们在不修改原有代码的情况下,灵活地扩展和定制功能。这种设计模式在许多编程语言中都有应用,它的主要优点是提高了代码的模块化程度和可重用性。二、Java中的回调函数实现在Java中,我们可以通过接口和实现接口的类来实现回调函数。下面是一个简单的示例:定义一个回调接口:public interface Callback { void onCallback(String message); } 这个接口定义了一个名为onCallback的方法,该方法接受一个字符串作为参数。创建一个类,该类接受回调接口作为参数,并在特定条件下调用回调方法: public class Caller { private Callback callback; public Caller(Callback callback) { this.callback = callback; } public void doSomething() { // 执行一些操作... String message = "操作完成"; callback.onCallback(message); } } 在这个类中,我们定义了一个名为doSomething的方法。这个方法在执行一些操作后,会调用回调接口的onCallback方法。实现回调接口并创建Caller对象: public class Main { public static void main(String[] args) { Callback callback = new Callback() { @Override public void onCallback(String message) { System.out.println("回调函数被调用: " + message); } }; Caller caller = new Caller(callback); caller.doSomething(); } } 在这个例子中,我们创建了一个实现了Callback接口的匿名内部类,并将其传递给Caller类的构造函数。然后,我们调用Caller类的doSomething方法。当doSomething方法执行完毕后,它会调用我们传递给它的回调函数。三、使用Lambda表达式简化回调函数从Java 8开始,我们可以使用Lambda表达式简化回调函数的实现。以下是使用Lambda表达式的示例: public class Main { public static void main(String[] args) { Callback callback = message -> System.out.println("回调函数被调用: " + message); Caller caller = new Caller(callback); caller.doSomething(); } } 通过使用Lambda表达式,我们可以更简洁地实现回调函数,提高代码的可读性。四、回调函数的应用场景回调函数在Java中有许多应用场景。例如,我们可以使用回调函数来处理异步操作。在异步编程中,我们经常需要在某个操作完成后执行一些操作,但是我们无法预知这个操作何时完成。在这种情况下,我们可以使用回调函数。一个具体的例子是我们在springboot中使用RabbitMQ时,通常需要保障生产者投递消息的可靠性,rabbitmq为我们提供了这样一种方式,即生产者确认机制,这个机制就是利用回调函数实现的,当交换机收到生产者提供的消息之后,会调用我们实现的回调函数,然后我们可以在回调函数中实现一些自己的处理逻辑,从而实现发送者的可靠性。另一个常见的应用场景是在图形用户界面(GUI)编程中。在GUI编程中,我们经常需要在用户进行某些操作(如点击按钮)时执行一些操作。我们可以将这些操作封装在回调函数中,然后在用户进行操作时调用这些回调函数。五、回调函数的注意事项5.1接口设计合理设计回调接口,确保回调函数的参数和返回值类型与实际需求匹配,从而避免出现类型错误或不一致的问题。5.2. 空指针异常在使用回调函数时,需要注意空指针异常的处理。例如,在调用回调函数之前,需要进行空值检查,以确保回调函数的实例不为空。5.3. 逻辑复杂性当回调逻辑较为复杂时,可能会导致代码难以维护和理解。因此,在设计回调函数时,应尽量保持逻辑简洁明了,避免过于复杂的嵌套和逻辑判断。5.4. 性能影响在使用回调函数时,由于涉及到多个类之间的交互,可能会引入一定的性能开销。因此,在需要高性能的场景中,应谨慎使用回调函数,以避免性能影响。
-
1.介绍Collections.sort()方法的参数为一个List集合,用于给集合进行排序。Collections.sort()内部进行了方法重载,可以只传入一个List集合参数,也可以传入一个List集合参数和一个Comparator接口对象并实现其中的compare方法2.Comparator接口下的compare方法升序排列 public static void main(String[] args) { Integer[] nums = new Integer[]{3, 7, 9, 2, 1}; Arrays.sort(nums, new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o1 - o2; } }); for (Integer i : nums) { System.out.print(i + " "); // 1 2 3 7 9 } }降序排列public static void main(String[] args) { Integer[] nums = new Integer[]{3, 7, 9, 2, 1}; Arrays.sort(nums, new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o2 - o1; } }); for (Integer i : nums) { System.out.print(i + " ");9 7 3 2 1 } }所以更多时候我们是直接记住了compare(int o1, int o2)方法 return o1 - o2 是升序,return o2 - o1 是降序。为什么会这样写呢?我们不妨看一下sort(T[] a, Comparator<? super T> c)方法public static <T> void sort(T[] a, Comparator<? super T> c) { if (c == null) { sort(a); } else { if (LegacyMergeSort.userRequested) legacyMergeSort(a, c); else TimSort.sort(a, 0, a.length, c, null, 0, 0); } }可以看出他是进去了else内,不妨先进入legacyMergeSort看一下private static <T> void legacyMergeSort(T[] a, Comparator<? super T> c) { T[] aux = a.clone(); if (c==null) mergeSort(aux, a, 0, a.length, 0); else mergeSort(aux, a, 0, a.length, 0, c); }这里很明显也是进去了else内,继续看mergeSortprivate static void mergeSort(Object[] src,Object[] dest,int low, int high, int off,Comparator c) { int length = high - low; // Insertion sort on smallest arrays if (length < INSERTIONSORT_THRESHOLD) { for (int i=low; i<high; i++) for (int j=i; j>low && c.compare(dest[j-1], dest[j])>0; j--) swap(dest, j, j-1); return; } // Recursively sort halves of dest into src int destLow = low; int destHigh = high; low += off; high += off; int mid = (low + high) >>> 1; mergeSort(dest, src, low, mid, -off, c); mergeSort(dest, src, mid, high, -off, c); // If list is already sorted, just copy from src to dest. This is an // optimization that results in faster sorts for nearly ordered lists. if (c.compare(src[mid-1], src[mid]) <= 0) { System.arraycopy(src, low, dest, destLow, length); return; } // Merge sorted halves (now in src) into dest for(int i = destLow, p = low, q = mid; i < destHigh; i++) { if (q >= high || p < mid && c.compare(src[p], src[q]) <= 0) dest[i] = src[p++]; else dest[i] = src[q++]; } }这一段的代码关键就是如下部分 if (length < INSERTIONSORT_THRESHOLD) { for (int i=low; i<high; i++) for (int j=i; j>low && c.compare(dest[j-1], dest[j])>0; j--) swap(dest, j, j-1); return; } 可以看到这里面调用了compare方法,当方法的返回值大于0的时候就将数组的前一个数和后一个数做交换。以升序为例来讲解,升序的话compare方法就 return o1 - o2,那么就是 return dest[j-1] - dest[j]。当 dest[j-1] > dest[j] 时,就进行交换。当 dest[j-1] <= dest[j] 时位置不变,从而达到数组升序。降序也是一样的道理。
-
重定向:1)什么是重定向? 服务器向浏览器发送一个状态码302 及一个消息头location(location 的值是一个地址),浏览器会立即向 location所指定的地址发送一个新的请求。我们把这样一种机制叫重定向。2)编程: response.sendRedirect(String url);3)需要注意的问题 在重定向之前,不能够有任何的输出;如果response 缓存当中有数据,在重定向之前,会自动清空。4)重定向的特点: a,地址任意 b,浏览器地址栏地址会变化(即变化为跳转之后的地址)。转发:1)什么是转发? 一个web组件(servlet/jsp)将未完成的处理交给另外一个web组件继续完成。转发所涉的各个web组件可以共享request和response 对象。 2)编程 step1 绑定数据到request对象上。 step2 获得转发器 RequestDispatcher rd = request.getRequestDispatcher(String url); step3 转发 rd.forward(request,response); servlet:负责业务逻辑处理(包括数据访问) 。 jsp:负责生成界面。 3)需要注意的问题: 在转发之前,response缓存的数据会被清空。
-
所谓生命周期,指的是servlet容器如何创建servlet实例、分配其资源、调用其方法、并销毁其实例的整个过程。阶段一: 实例化(就是创建servlet对象,调用构造器)在如下两种情况下会迚行对象实例化。第一种情况: 当请求到达容器时,容器查找该servlet对象是否存在,如果不存在,才会创建实例。第二种情况:容器在启动时,或者新部署了某个应用时,会检查web.xml当中,servlet是否有 load-on-starup 配置。如果有,则会创建该servlet实例。 load-on-starup 参数值越小,优先级越高(最小值为0,优先级最高)。阶段二: 初始化为servlet分配资源,调用init(ServletConfig config);方法 config 对象可以用来访问servlet的初始化参数。初始化参数是使用init-param配置的参数。init可以override。阶段三: 就绪/调用有请求到达容器,容器调用servlet对象的service()方法。HttpServlet的service()方法,会依据请求方式来调用doGet()或者doPost()方法。但是,这两个do 方法默认情况下,会抛出异常,需要子类去override。阶段四: 销毁容器依据自身的算法,将不再需要的servlet对象删除掉。在删除之前,会调用servlet对象的 destroy()方法。destroy()方法用于释放资源。在servlet的整个生命周期当中,init,destroy只会执行一次,而service 方法会执行多次。
上滑加载中
推荐直播
-
HDC深度解读系列 - Serverless与MCP融合创新,构建AI应用全新智能中枢2025/08/20 周三 16:30-18:00
张昆鹏 HCDG北京核心组代表
HDC2025期间,华为云展示了Serverless与MCP融合创新的解决方案,本期访谈直播,由华为云开发者专家(HCDE)兼华为云开发者社区组织HCDG北京核心组代表张鹏先生主持,华为云PaaS服务产品部 Serverless总监Ewen为大家深度解读华为云Serverless与MCP如何融合构建AI应用全新智能中枢
回顾中 -
关于RISC-V生态发展的思考2025/09/02 周二 17:00-18:00
中国科学院计算技术研究所副所长包云岗教授
中科院包云岗老师将在本次直播中,探讨处理器生态的关键要素及其联系,分享过去几年推动RISC-V生态建设实践过程中的经验与教训。
回顾中 -
一键搞定华为云万级资源,3步轻松管理企业成本2025/09/09 周二 15:00-16:00
阿言 华为云交易产品经理
本直播重点介绍如何一键续费万级资源,3步轻松管理成本,帮助提升日常管理效率!
回顾中
热门标签