首页 文章 精选 留言 我的

精选列表

搜索[技术极客],共10008篇文章
优秀的个人博客,低调大师

极简通讯 JSSDK 发布 - 轻松拥有通讯能力 🐒 WuKongIM

EasyJSSDK 一个简单易用的 WuKongIM 通讯 SDK,基于其 JSON-RPC 协议。(地址:https://gitee.com/WuKongDev/EasyJSSDK) WuKongIM 开源地址:https://gitee.com/WuKongDev/WuKongIM 安装 npm install easyjssdk 使用方法 // 引入必要的组件 import { WKIM, WKIMChannelType, WKIMEvent } from 'easyjssdk'; // 1. 初始化 const im = WKIM.init("ws://your-wukongim-server.com:5200", { uid: "your_user_id", // 你的用户 ID token: "your_auth_token" // 你的认证令牌 // deviceId: "optional_device_id", // 可选的设备 ID // deviceFlag: 2 // 可选的设备标识 (1:APP, 2:WEB, 默认为 2) }); // 2. 收消息 im.on(WKIMEvent.Message, (message) => { console.log("收到消息:", message); // 处理收到的消息 (message.payload, message.fromUid 等) }); // 3. 连接到服务器 im.connect() // 4. 示例:连接成功后发送一条消息 const targetUserId = "friend_user_id"; // 目标用户 ID const messagePayload = { type: 1, content: "来自 EasyJSSDK 的问候!" }; // 你的自定义消息负载 return im.send(targetUserId, WKIMChannelType.Person, messagePayload); 开发 克隆本仓库。 运行 npm install 安装依赖。 运行 npm run build 将 TypeScript 编译成 JavaScript。 运行示例程序 仓库中包含一个简单的 HTML/JS 示例用于测试 SDK。 构建 SDK: 确保你已经先构建了库文件: <pre> npm run build 启动本地服务器: 在你的终端中,导航到本项目的根目录 (EasyJSSDK)。你需要使用一个本地 Web 服务器来提供文件服务,因为示例使用了 ES Modules。一个简单的方法是使用 http-server: <pre> # 如果你还没有 http-server,请全局安装: npm install -g http-server 从 EasyJSSDK 目录运行服务器: http-server . 或者,使用 VS Code 的 "Live Server" 扩展或其他任何本地服务器,确保它从项目根目录 (<code>EasyJSSDK</code>) 提供服务。 </li> <li> <strong>打开示例:</strong> 打开你的 Web 浏览器并访问示例页面,通常是: <code>http://localhost:8080/example/</code> (如果你的服务器使用了不同的端口号,请相应调整)。 </li> <li> <strong>测试:</strong> 输入你的 WuKongIM 服务器信息 (URL, UID, Token),然后使用按钮进行连接、断开和发送消息的测试。 </li>

优秀的个人博客,低调大师

每日一博 | 极简 Java 工作流概念入门

关于 Flowable 松哥已经更新了好几篇文章了,不过考虑到有的小伙伴可能还从来没接触过流程引擎,因此有一些基础的内容我再来和小伙伴们梳理一下。 1. 为什么需要工作流 松哥将之前的文章转发到朋友圈后,有小伙伴评论说一直不理解为什么需要工作流,今天我们就先来说说这个话题。 假设我有一个请假需求,流程如下: 请假可以提交给我的上司,上司可以选择批准或者拒绝,无论批准还是拒绝,都会给我一个通知。 这个流程比较简单,我们很容易想到解决方案,不用工作流也能解决,有一个专门的请假表,当 A 要请假的时候,就往请假表中添加一条记录,这条记录的内容包含了请假的天数、原因、请假的审批人 B 以及一个名为 status 的字段,这个 status 字段表示这个请假申请目前的状态(待审批、已批准还是已拒绝),然后 B 登录系统之后,在请假表中查询到了 A 的请假信息,然后选择批准,此时将 status 字段的值改一下就行了。 这个流程很简单,相信小伙伴们都能想到。 然而,这是一个非常简单的流程,对于这样的流程,一般来说也确实没有必要使用工作流,但是现实中,我们涉及到的工作流往往都是非常复杂的,我举个例子,就说报销审批吧,这个可能很多小伙伴都经历过。 小伙伴们看到,这个流程相对来说还是比较复杂的,此时你再用一个 status 字段去描述,就很难说的请到底是怎么回事了。每一步审批,都有可能批准也有可能拒绝,拒绝并不意味着流程结束,员工修改报销资料之后,还可以继续提交。此时如果还用 status 去描述,那么 status 将有 N 多个值去表示不同的情况,这个维护起来非常不便。 这就复杂了吗?非也非也,我们再来看一个生产笔记本电脑的例子,假设公司研发了一款新型笔记本电脑,整个研发到生产的流程可能是这样: 相比上面两个,这个就更复杂一些了,不仅有串行任务还有并行任务,如何去设计这样一个系统?单纯的通过状态字段去描述显然已经不够用了,此时我们就得考虑一种通用的、更易维护的方案来实现这样的系统了,这种通用的、易维护的方案,也就是工作流。 2. 三大工作流 一个比较早的工作流是 jBPM,这是一个由 Java 实现的企业级流程引擎,是 JBoss 公司开发的产品之一。 jBPM 的创建者是 Tom Baeyens,这个大佬后来离开了 JBoss,并加入到 Alfresco,并推出了基于 jBPM4 的开源工作流系统 Activiti,而 jBPM 则在后续的代码中完全放弃了 jBPM4 的代码。从这个过程中也能看出来,jBPM 在发展过程中,由于意见相左,后来变成了两个 jBPM 和 Activiti。 然而戏剧的是,Activiti5 没搞多久,从 Activiti 中又分出来一个 Camunda,Activiti 继续发展,又从中分出来一个 Flowable。。。 由于开发 jBPM、Activiti、Camunda 以及 Flowable 的人多多少少有一些关联性,让人不得不猜测意见相左拉一票人出来单干是他们的企业文化。 所以现在市面上主流的流程引擎就一共有三个: Activiti Flowable Camunda 这三个各有特点: Activiti 目前是侧重云,他目前的设计会向 Spring Cloud、Docker 这些去靠拢。 Flowable 核心思想还是在做一个功能丰富的流程引擎工具,除了最最基础的工作流,他还提供了很多其他的扩展点,我们可以基于 Flowable 实现出许多我们想要的功能(当然这也是小伙伴们觉得 Flowable 使用复杂的原因之一)。 Camunda 相对于前两个而言比较轻量级,Camunda 有一个比较有特色的功能就是他提供了一个小巧的编辑器,基于 bpmn.io 来实现的(松哥之前已经发文讲过了)。如果你的项目需求是做一个轻巧的、灵活的、定制性强的编辑器,工作流是嵌入式的,那么可以选择 Camunda。 如果仔细比较起这三个的差异,能列一个长长的表格,这个网上也有不少人都总结过了,松哥这里也就不啰嗦了。 3. 流程图 既然有三个不同的工作流,那么三个不同的工作流画出来的流程图是否都各不相同呢? 不是的。 工作流程图这块其实有一个统一的标准,那就是 BPMN。BPMN 全称是 Business Process Model and Notation,中文译作业务流程模型和标记法,这个中文太绕口了,还是简称 BPMN 吧。 这是一套图形化表示法,用图形来表示业务流程模型。BPMN 最初由业务流程管理倡议组织(BPMI, Business Process Management Initiative)开发,BPMI 于 2005 年与对象管理组织(OMG, Object Management Group)合并,并于 2011 年 1 月 OMG 发布 2.0 版本,同时改为现在的名称。 一句话,就是流程图这块有一个特别古老的规范,那就是 BPMN,而我们前面所说的无论是 Activiti、Flowable 还是 Camunda,都是支持这个规范的,所以呢,无论你使用哪一个流程引擎,都可以使用同一套流程图。 那么这个规范究竟都说了些什么事情呢? 我们以上面生产笔记本的流程图为例,来和小伙伴们做一个简单介绍: 从上图中可以看到,一个流程图中主要包含四方面的内容: 事件 连线 任务 网关 我们一个一个来说。 事件 首先在一个流程图中应该有开始事件和结束事件,也就是上图大家看到的两个圆圈。另外还有一些中间事件、边界事件等。举个中间定时事件的例子,比如用户下单之后,可以有一个中间定时事件,延迟 5 分钟发货。 连线 连线就是将事件、任务、网关等连在一起的线条,一般情况下就是普通连线,有的时候连线会有一些条件,例如松哥之前文章和大家分享的请假,如果经理同意请假申请,就走哪一个线条,如果经理不同意请假申请,就走哪一个线条。对应上图的笔记本生产,如果经理审批通过,就载入图纸准备生产,如果经理审批不通过,就重新设计。 任务 任务这块其实有很多分类。 如果细分大致上可以分为如下几种: 接收任务 在上面的流程图中,等待准备工作完成这一项就是一个接收任务。这个任务里并不需要额外做什么事情,流程到这一步就自动停下来了,需要人工去点一下,推动流程继续向下执行。 发送任务 这个一般用来把消息发送给外部参与者。 服务任务 这个一般由系统自动完成,其实说白了就是我们的一个自定义类,可以在一个自定义类里边完成想要做的事情。 脚本任务 一个自动化活动。当流程执行到脚本任务时,自动执行相应的脚本。 业务规则任务 BPMN2.0 新引入用来对接业务规则引擎,业务规则任务用于同步执行一个或多个规则。 用户任务 用于为那些需要由人工参与者完成的工作建模。 虽然细分类别很多,但是仔细看,其实这几种又可以归为两大类: 用户任务:表示人工要介入做的事情。比如同意与否,或者输入一些参数,要让人工完成任务,就需要一个表单系统,让人工输入数据,或者显示数据给人看,这也是为什么用户任务和表单系统结合在一起的原因,用户任务需要用户向引擎提交一个完成任务的动作,否则流程会暂停在这里等待。 服务任务:表示机器自动做的事情。调用服务的任务,这个服务可以是一个 Spring JavaBean,也可以是一个远程 REST 服务,流程会自动执行服务任务。 活动 活动可以算是一种特殊的任务。活动可以调用另外一个流程使之作为当前流程的子流程去运行。活动也可以分为用户活动、脚本活动等等。从显示上来说,活动比任务边框深一些。仅此而已。 网关 网关要是细分起来,也有很多不同类型的网关。 互斥网关 这种网关也叫排他性网关,我们之前请假流程中的那个网关,就是互斥网关。这种网关有且仅有一个有效出口。 相容网关 这种网关会有多个出口,只要条件满足,都会执行。 事件网关 事件网关是通过中间事件驱动,它在等待的事件发生后才会触发决策。基于事件的网关允许基于事件作出决策。 并行网关 并行网关一般是成对出现的,上面生产笔记本的那个流程中,生产屏幕、键盘等并行操作,就是通过并行网关来实现的。 好啦,这就是关于流程引擎的一些基本概念,捋顺了这些基本概念,在回过头看我们前面几篇关于流程引擎的文章,应该会有一些不一样的理解: Spring Boot 整合流程引擎 Flowable,so easy! SpringBoot+Vue+Flowable,模拟一个请假审批流程! 49张图带领小伙伴们体验一把 Flowable-UI Spring Security + Vue + Flowable 怎么玩?

优秀的个人博客,低调大师

Tigon MyBatis v0.0.8 发布,极简 MyBatis Mapper 增强

Tigon MyBatis v0.0.8 已经发布,为 MyBatis Mapper 提供增强,设计精巧,代码量很少,代码洁癖工程师的朋友 此版本更新内容包括: 优化插入生成Key逻辑,之前通过拦截器方式实现,在高并发环境下存在Bug 删除了100多行代码,今天又变强了 详情查看:https://gitee.com/chyxion/tigon-mybatis/releases/v0.0.8 Tigon MyBatis 简介 Tigon MyBatis为Spring工程中MyBatis的Mapper提供增强,主要有以下特点 代码又少又壮,绝不做多余的事情 仅需Mapper继承接口,实现增删改查,无额外配置,爽到没女朋友 用完即走,毫不留恋 开始使用 引入Maven依赖 <dependency> <groupId>me.chyxion.tigon</groupId> <artifactId>tigon-mybatis</artifactId> <version>0.0.8</version> </dependency> 使用示例 定义Entity package me.chyxion.tigon.mybatis.entity; import lombok.Getter; import lombok.Setter; import java.util.Date; import lombok.ToString; import java.io.Serializable; import me.chyxion.tigon.mybatis.Table; import me.chyxion.tigon.mybatis.NotUpdate; import me.chyxion.tigon.mybatis.NotUpdateWhenNull; @Getter @Setter @ToString @Table("tb_user") public class User implements Serializable { private static final long serialVersionUID = 1L; private Integer id; // 标记账户不被更新 @NotUpdate private String account; // 当手机号为null不被更新 @NotUpdateWhenNull private String mobile; private String name; private Gender gender; private String password; private Date birthDate; private String city; private String avatar; private Boolean active; private String remark; private String createdBy; private Date createdAt; private String updatedBy; private Date updatedAt; public enum Gender { MALE, FEMALE } } 定义Mapper package me.chyxion.tigon.mybatis.mapper; import java.util.List; import me.chyxion.tigon.mybatis.BaseMapper; import org.apache.ibatis.annotations.Mapper; import me.chyxion.tigon.mybatis.entity.User; @Mapper public interface UserMapper extends BaseMapper<Integer, User> { } 注入Mapper对象 @Autowired private UserMapper mapper; I. 插入 val user = new User(); user.setName("Donghuang"); user.setAccount("donghuang"); user.setMobile("137647788xx"); user.setPassword(RandomStringUtils.randomAlphanumeric(16)); user.setGender(User.Gender.MALE); user.setBirthDate(DateUtils.parseDate("1994-04-04")); user.setCity("Shanghai"); user.setActive(true); user.setRemark("Uncle Donghuang"); user.setCreatedBy("donghuang"); user.setCreatedAt(new Date()); // 插入单条记录 mapper.insert(user); val user1 = new User(); user1.setName("Gemily"); user1.setAccount("gemily"); user1.setMobile("15770780xxx"); user1.setPassword(RandomStringUtils.randomAlphanumeric(16)); user1.setGender(User.Gender.FEMALE); user1.setBirthDate(DateUtils.parseDate("1990-06-06")); user1.setCity("Hangzhou"); user1.setActive(true); user1.setCreatedBy("donghuang"); user1.setCreatedAt(new Date()); val user2 = new User(); user2.setName("Luffy"); user2.setAccount("luffy"); user2.setMobile("137647799xx"); user2.setPassword(RandomStringUtils.randomAlphanumeric(16)); user2.setGender(User.Gender.MALE); user2.setBirthDate(DateUtils.parseDate("1997-07-07")); user2.setCity("East sea"); user2.setActive(true); user2.setRemark("Luffy"); user2.setCreatedBy("donghuang"); user2.setCreatedAt(new Date()); // 批量插入记录 mapper.insert(Arrays.asList(user1, user2)); II. 查询 根据ID查询单个对象 val id = 1154; // 根据主键查询单条记录 val user = mapper.find(id); 根据属性查询单个对象 // 根据属性account, mobile查询单个对象 val user = mapper.find( new Search("account", "donghuang") .eq("mobile", "137647788xx")); 根据属性查询列表 // 根据属性birthDate, gender查询数据列表 // 查询结果根据属性birthDate升序排序 // 返回数据限制42条 val users = mapper.list(new Search() .between("birthDate", DateUtils.parseDate("1982-04-04"), DateUtils.parseDate("1994-04-04") ) .eq("gender", User.Gender.MALE) .asc("birthDate") .limit(42)); Search对象支持的API ascOrder ASC 列升序排序 descOrder DSC 列降序排序 orderByOrder by 列属性排序 betweenBetween two values 属性列属于2个值之间 buildBuild query criterion 自定义构建一个属性列查询条件 startsWithValue starts with string 属性列以字符串开头,等同于col like 'val%' endsWithValue ends with string 属性列以字符串结尾,等同于col like '%val' containsValue contains string 属性列包含字符串,等同于col like '%val%' likeValue like 属性列与字符串相似 eqEquals 属性列等于 neNot equals 属性列小于或等于 gtGreater than 属性列大于 gteEquals or greater than 属性列大于或等于 ltLess than 属性列小于 lteEquals or less than 属性列小于 inIn values 属性列属于集合 notInNot in values 属性列不属于集合 isNullValue is null 属性列为null notNullValue is not null 属性列不为null isTrueValue is true 属性列为true isFalseValue is false 属性列为false limitReturn rows limit 查询/更新结果行数限制 offsetReturn rows offset 查询结果偏移行数 andAnd anotherSearch且另外一个Search对象 orOr anotherSearch或另外一个Search对象 III. 更新 通过Entity根据ID更新 // 根据主键查询记录 val user = mapper.find(1); user.setName("东皇大叔"); user.setUpdatedBy("SYS"); user.setUpdatedAt(new Date()); // 更新单个实体对象 mapper.update(user); 通过Map<String, Object>更新 val update = new HashMap<String, Object>(6); update.put("name", "东皇大叔"); update.put("updatedBy", "SYS"); update.put("updatedAt", new Date()); // 通过Map更新ID为1的记录 mapper.update(update, 1); // 效果同上 // mapper.update(update, new Search("id", 1)); // mapper.update(update, new Search(1)); 更新列为NULL // 更新id为274229记录的属性列remark为null mapper.setNull("remark", 274229); // 更新id为1154记录的属性列remark为null mapper.setNull("remark", new Search("id", 1154)); // 更新全表的属性列remark为null,小心操作!!! mapper.setNull("remark", new Search()); IV. 删除 通过ID删除数据 // 根据主键删除记录 mapper.delete(1); 通过Search对象删除数据 // 根据属性ID删除记录 mapper.delete(new Search("id", 1)); // 等同于 mapper.delete(1); V. 杂项 除了上面说到的一些基础增删改查操作,还有一些实用功能,如@Transient@UseGeneratedKeys@NoPrimaryKey@NotUpdateWhenNull@RawValue等注解,插入、更新前回调,以及支持扩展自定义的方法等。 配置说明 SpringBoot项目,无需其他操作,引入依赖即可 Spring项目,注册Beanme.chyxion.tigon.mybatis.TigonMyBatisConfiguration 业务Mapper继承me.chyxion.tigon.mybatis.BaseMapper或相关衍生Mapper,Base(Query, Insert, Update, Delete)Mapper

优秀的个人博客,低调大师

Java学习笔记--异常处理(传智播客的总结)

背景: 我们的java程序也是会存在某些不正常 的情况的,这些不正常的 情况我们就统称异常。(还有一种是IO流的异常 要包装成运行时异常) 异常体系: ———-| Throwable 所以异常或者错误类的超类 ————–|Error 错误 错误一般是用于jvm或者是硬件引发的问题,所以我们一般不会通过代码去处理错误的。 ————–|Exception 异常 是需要通过代码去处理的。 如何区分错误与异常呢: 如果程序出现了不正常的信息,如果不正常的信息的类名是以Error结尾的,那么肯定是一个错误。 如果是以Exception结尾的,那么肯定就是一个异常。 Throwable常用的方法: toString() 返回当前异常对象的完整类名+病态信息。 包名+类名 = 完整类名 getMessage() 返回的是创建Throwable传入的字符串信息。 printStackTrace() 打印异常的栈信息 比如:虚拟机能分配的内存是50多mb如果超过了就是Error类型的 疑问: 下面的信息是通过printStackTrace方法打印出来,那么异常对象从何而来呢? Exception in thread “main” java.lang.ArithmeticException: / by zero at Demo10.div(Demo10.java:10) at Demo10.main(Demo10.java:5) jvm运行到a/b这个语句的时候,发现b为0,除数为0在我们现实生活中是属于 不正常的情况,jvm一旦发现了这种不正常的情况时候,那么jvm就会马上创建 一个对应的异常对象,并且会调用这个异常对象 的printStackTrace的方法来处理。 异常的处理: 方式一:捕获处理 捕获处理的格式: try{ 可能发生异常的代码; }catch(捕获的异常类型 变量名){ 处理异常的代码.... } 捕获处理要注意的细节: 如果try块中代码出了异常经过了处理之后,那么try-catch块外面的代码可以正常执行。 如果try块中出了异常的代码,那么在try块中出现异常代码后面的代码是不会执行了。 一个try块后面是可以跟有多个catch块的,也就是一个try块可以捕获多种异常的类型。 一个try块可以捕获多种异常的类型,但是捕获的异常类型必须从小到大进行捕获,否则编译报错。 疑问一 : 异常的处理感觉没有多大作用,因为都是输出一个话而已? 异常处理非常有用,只不过是由于我们目前所接触的知识点太过于局限而已。 疑问二: 以后捕获处理 的时候是否就是捕获Exception即可? 错的,因为我们在现实开发中遇到不同的异常类型的时候,我往往会有不同 的处理方式。 所以要分开不同的异常类型处理。 注意 如果抛出了一个异常 那么接下来的代码就不会执行 */ 举例: try catch方法 class A{ public static void main(String[] args){ div(1,0); } public static void div(int a,int b){ int c=0; try{ c=a/b; }catch(ArithmeticException e){ System.out.println("1"); }catch(NullPointerException e){ System.out.println("2"); }catch(Exception e){ System.out.println("3"); } } } /* 异常的处理方式----抛出处理 抛出处理(throw throws) 抛出处理要注意的细节: 1. 如果一个方法的内部抛出了一个异常 对象,那么必须要在方法上声明抛出。 2. 如果调用了一个声明抛出异常 的方法,那么调用者必须要处理异常。 3. 如果一个方法内部抛出了一个异常对象,那么throw语句后面的代码都不会再执行了(一个方法遇到了throw关键字,该方法也会马上停止执行的)。 4. 在一种情况下,只能抛出一种类型异常对象。 throw 与throws两个关键字: 1. throw关键字是用于方法内部的,throws是用于方法声声明上的。 2. throw关键字是用于方法内部抛出一个异常对象的,throws关键字是用于在方法声明上声明抛出异常类型的。 3. throw关键字后面只能有一个异常对象,throws后面一次可以声明抛出多种类型的 异常。 疑问:何时使用抛出处理?何时捕获处理?原则是如何? 如果你需要通知到调用者,你代码出了问题,那么这时候就使用抛出处理. 如果代码是直接与用户打交道遇到了异常千万不要再抛,再抛的话,就给了用户了。 这时候就应该使用捕获处理。 */ 举例:throw 抛出 class Demo2{ public static void main(String[] args)throws Exception{ try{ div(0,1,null); }catch(Exception e){ System.out.print("1"); throw new Exception(); } } public static void div(int i,int j,int[] arr) throws Exception{ if(i==0){ throw new Exception(); }else if(arr==null){ throw new NullPointerException(); } int c=i/j; System.out.println(c); } } 如果 main函数也抛出异常 那么到时候出错的时候直接打印printStackTrace 自定义异常类: /* sun提供了很多的异常类给我们用于描述程序中各种的不正常情况,但是sun 给我 提供异常类还不足以描述我们现实生活中所有不正常情况,那么这时候我们就需要 自定义异常类。 需求: 模拟feiQ上线的时候,如果没有插上网线,那么就抛出一个没有插上网线的异常, 如果已经插上了网上,那么就正常显示好友列表。 自定义异常类的步骤: 自定义一个类继承Exception即可。 class NullIpException extends Exception{ public NullIpException(String x){ super(x); } } class Demo2{ public static void main(String[] args){ String ip="sdf"; ip=null; try{ xx(ip); }catch(Exception z){ z.printStackTrace(); } } public static void xx(String ip)throws Exception{ if(ip==null){ throw new NullIpException("noip"); } System.out.println("sdfsadfasdfas"); } } —————| 运行时异常: 如果一个方法内部抛出了一个运行时异常,那么方法上 可以声明也可以不 声明,调用者可以以处理也可以不处理。 ——————| 编译时异常(非运行时异常、受检异常): 如果一个方法内部抛出了一个编译时异常对象,那么方法上就必须要声明,而且调用者也必须要处理。 运行时异常: RuntimeException以及RuntimeException子类 都是属于运行时异常。 编译时异常: 除了运行时异常就是编译异常。 疑问: 为什么java编译器会如此严格要求编译时异常,对运行时异常如此宽松? 运行时异常都是可以通过程序员良好的编程习惯去避免,所以java编译器就没有严格要求处理运行时异常。 ———————————————————————————————————— */ finally块的 使用前提是必须要存在try块才能使用。 finally块的代码在任何情况下都会执行的,除了j vm退出的情况。 finally非常适合做资源释放的工作,这样子可以保证资源文件在任何情况下都 会被释放。 finally: 结论: 1、不管有木有出现异常,finally块中代码都会执行; 2、当try和catch中有return时,finally仍然会执行; 3、finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,管finally中的代码怎么样,返回的值都不会改变,任然是之前保存的值),所以函数返回值是在finally执行前确定的; 4、finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值。 System.exit(0);//退出jvm 那么finally是不会执行的 举例: class Demo2{ public static void main(String[] args){ try{ div(1); }catch(Exception e){ e.printStackTrace(); System.out.println("xipanzi"); } } public static void div(int n) throws Exception{ try{ System.exit(0); }catch(Exception e){ System.out.print("sdf"); }finally{ System.out.print("finally"); } } } 如果try里面是return 那么也会执行finally 但是不会影响return的返回值 因为finally是在return之后才执行的 fianlly释放资源的代码 import java.io.*; class Demo6 { public static void main(String[] args) throws Exception { FileReader fileReader = null; try{ //找到目标文件 File file = new File("f:\\a.txt"); //建立程序与文件的数据通道 fileReader = new FileReader(file); //读取文件 char[] buf = new char[1024]; int length = 0; length = fileReader.read(buf); System.out.println("读取到的内容:"+ new String(buf,0,length)); }catch(IOException e){ System.out.println("读取资源文件失败...."); }finally{ try{ //关闭资源 fileReader.close(); System.out.println("释放资源文件成功...."); }catch(IOException e){ System.out.println("释放资源文件失败...."); } } } } 总结: 1:子类覆盖父类方法是,父类方法抛出异常,子类的覆盖方法可以不抛 出异常,或者抛出父类方法的异常,或者该父类方法异常的子类。 2:父类方法抛出了多个异常,子类覆盖方法时,只能抛出父类异常的子 集 3:父类没有抛出异常子类不可抛出异常 1:子类发生非运行时异常,需要进行try{}catch的(){}处理,不能 抛出。 4:子类不能比父类抛出更多的异常

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

用户登录
用户注册