《Java开发手册——华山版》读书笔记

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
日志服务 SLS,月写入数据量 50GB 1个月
简介: 《Java开发手册——华山版》读书笔记

《Java开发手册——华山版》读书笔记


编程规约

命名风格

【06】:抽象类命名使用Abstract或Base开头;异常类命名使用Exception结尾;测试类命名以它要测试的类的名称开始,以Test结尾。

【08】:POJO类中布尔类型变量都不要加is前缀,否则部分框架解析会引起序列化错误。

说明:在本文MySQL规约中的建表约定第一条,表达是与否的值采用is_xxx的命名方式,所以,需要在<resultMap>设置从is_xxx到xxx的映射关系。

【14】:如果模块、接口、类、方法使用了设计模式,在命名时需体现出具体模式。


各层命名规约:

A) Service/DAO层方法命名规约

1) 获取单个对象的方法用get做前缀。

2) 获取多个对象的方法用list做前缀,复数形式结尾如:listObjects。

3) 获取统计值的方法用count做前缀。

4) 插入的方法用save/insert做前缀。

5) 删除的方法用remove/delete做前缀。

6) 修改的方法用update做前缀。


B) 领域模型命名规约

1) 数据对象:xxxDO,xxx即为数据表名。

2) 数据传输对象:xxxDTO,xxx为业务领域相关的名称。

3) 展示对象:xxxVO,xxx一般为网页名称。

4) POJO是DO/DTO/BO/VO的统称,禁止命名成xxxPOJO。


常量定义

【03】:不要使用一个常量类维护所有常量,要按常量功能进行归类,分开维护。

说明:大而全的常量类,杂乱无章,使用查找功能才能定位到修改的常量,不利于理解和维护。

正例:缓存相关常量放在类CacheConsts下;系统配置相关常量放在类ConfigConsts下。


【04】:常量的复用层次有五层:跨应用共享常量、应用内共享常量、子工程内共享常量、包内共享常量、类内共享常量。

1) 跨应用共享常量:放置在二方库中,通常是client.jar中的constant目录下。

2) 应用内共享常量:放置在一方库中,通常是子模块中的constant目录下。

3) 子工程内部共享常量:即在当前子工程的constant目录下。

4) 包内共享常量:即在当前包下单独的constant目录下。

5) 类内共享常量:直接在类内部private static final定义。


OOP规约

【07】:所有整型包装类对象之间值的比较,全部使用equals方法比较。

【08】:浮点数之间的等值判断,使用 BigDecimal 包装类进行判断;为了防止精度损失,禁止使用构造方法BigDecimal(double)的方式把double值转化为BigDecimal对象。优先推荐入参为String的构造方法,或使用BigDecimal的valueOf方法。

【21】:循环体内,字符串的连接方式,使用StringBuilder的append方法进行扩展。


集合处理

【01】:关于hashCode和equals的处理,

遵循如下规则:

1) 只要覆写equals,就必须覆写hashCode。

2) 因为Set存储的是不重复的对象,依据hashCode和equals进行判断,所以Set存储的对象必须覆写这两个方法。

3) 如果自定义对象作为Map的键,那么必须覆写hashCode和equals。

【02】:ArrayList的subList结果不可强转成ArrayList,否则会抛出 ClassCastException异常,即java.util.RandomAccessSubList cannot be cast to java.util.ArrayList。

【03】:使用Map的方法keySet()/values()/entrySet()返回集合对象时,不可以对其进行添加元素操作,否则会抛出UnsupportedOperationException异常。

【09】:泛型通配符<? extends T>来接收返回的数据,此写法的泛型集合不能使用add方法,而<? super T>不能使用get方法,作为接口调用赋值时易出错。 说明:扩展说一下PECS(Producer Extends Consumer Super)原则:

第一、频繁往外读取内容的,适合用<? extends T>。

第二、经常往里插入的,适合用<? super T>。

【11】:不要在foreach循环里进行元素的remove/add操作。remove元素请使用Iterator方式,如果并发操作,需要对Iterator对象加锁。

【15】:使用entrySet遍历Map类集合KV,而不是keySet方式进行遍历。

说明:keySet其实是遍历了2次,一次是转为Iterator对象,另一次是从hashMap中取出key所对应的value。而entrySet只是遍历了一次就把key和value都放到了entry中,效率更高。如果是JDK8,使用Map.forEach方法。

【16】:高度注意Map类集合K/V能不能存储null值的情况,如下表格:

image.png


【18】:利用Set元素唯一的特性,可以快速对一个集合进行去重操作,避免使用List的contains方法进行遍历、对比、去重操作。


并发处理(暂无)

控制语句

【01】:在一个switch块内,每个case要么通过continue/break/return等来终止,要么注释说明程序将继续执行到哪一个case为止;在一个switch块内,都必须包含一个default语句并且放在最后,即使它什么代码也没有。

【02】:当switch括号内的变量类型为String并且此变量为外部参数时,必须先进行null判断。

【03】:在高并发场景中,避免使用”等于”判断作为中断或退出的条件。 说明:如果并发控制没有处理好,容易产生等值判断被“击穿”的情况,使用大于或小于的区间判断条件来代替。

【05】:超过3层的 if-else 的逻辑判断代码可以使用卫语句、策略模式、状态模式等来实现,其中卫语句即代码逻辑先考虑失败、异常、中断、退出等直接返回的情况,以方法多个出口的方式,解决代码中判断分支嵌套的问题,这是逆向思维的体现。


其他

【05】:获取当前毫秒数System.currentTimeMillis(); 而不是new Date().getTime(); 说明:如果想获取更加精确的纳秒级时间值,使用System.nanoTime()的方式。在JDK8中,针对统计时间等场景,推荐使用Instant类。


异常日志

异常处理

日志规约

【01】:应用中不可直接使用日志系统(Log4j、Logback)中的API,而应依赖使用日志框架 SLF4J中的API,使用门面模式的日志框架,有利于维护和各个类的日志处理方式统一。

【04】:在日志输出时,字符串变量之间的拼接使用占位符的方式。 说明:因为String字符串的拼接会使用StringBuilder的append()方式,有一定的性能损耗。使用占位符仅是替换动作,可以有效提升性能。 正例:logger.debug(“Processing trade with id: {} and symbol: {}”, id, symbol);

【05】:对于trace/debug/info级别的日志输出,必须进行日志级别的开关判断。

说明:虽然在debug(参数)的方法体内第一行代码isDisabled(Level.DEBUG_INT)为真时(Slf4j的常见实现Log4j和Logback),就直接return,但是参数可能会进行字符串拼接运算。此外,如果debug(getName())这种参数内有getName()方法调用,无谓浪费方法调用的开销。

正例:

// 如果判断为真,那么可以输出trace和debug级别的日志
 if (logger.isDebugEnabled()) { 
  logger.debug("Current ID is: {} and name is: {}", id, getName());
  }


【08】:谨慎地记录日志。生产环境禁止输出debug日志;有选择地输出info日志;如果使用warn来记录刚上线时的业务行为信息,一定要注意日志输出量的问题,避免把服务器磁盘撑爆,并记得及时删除这些观察日志。

【09】:可以使用warn日志级别来记录用户输入参数错误的情况,避免用户投诉时,无所适从。如非必要,请不要在此场景打出error级别,避免频繁报警。 说明:注意日志输出的级别,error级别只记录系统逻辑出错、异常或者重要的错误信息。


单元测试

MySQL数据库

【01】:表达是与否概念的字段,必须使用is_xxx的方式命名,数据类型是unsigned tinyint(1表示是,0表示否)。

说明:任何字段如果为非负数,必须是unsigned。 注意:POJO类中的任何布尔类型的变量,都不要加is前缀,所以,需要在设置从is_xxx到Xxx的映射关系。数据库表示是与否的值,使用tinyint类型,坚持is_xxx的命名方式是为了明确其取值含义与取值范围。 正例:表达逻辑删除的字段名is_deleted,1表示删除,0表示未删除。

【02】:表名、字段名必须使用小写字母或数字,禁止出现数字开头,禁止两个下划线中间只出现数字。数据库字段名的修改代价很大,因为无法进行预发布,所以字段名称需要慎重考虑。

【04】:禁用保留字,如desc、range、match、delayed等,请参考MySQL官方保留字。

【05】:主键索引名为pk_字段名;唯一索引名为uk_字段名;普通索引名则为idx_字段名。

说明:pk_ 即primary key;uk_ 即 unique key;idx_ 即index的简称。

【09】:表必备三字段:id, create_time, update_time。

说明:

其中id必为主键,类型为bigint unsigned、单表时自增、步长为1。

create_time, update_time的类型均为datetime类型。

【14】:单表行数超过500万行或者单表容量超过2GB,才推荐进行分库分表。

说明:如果预计三年后的数据量根本达不到这个级别,请不要在创建表时就分库分表。


索引规约

【07】:利用延迟关联或者子查询优化超多分页场景。

说明:MySQL并不是跳过offset行,而是取offset+N行,然后返回放弃前offset行,返回N行,那当offset特别大的时候,效率就非常的低下,要么控制返回的总页数,要么对超过特定阈值的页数进行SQL改写。

正例:先快速定位需要获取的id段,然后再关联: SELECT a.* FROM 表1 a, (select id from 表1 where 条件 LIMIT 100000,20 ) b where a.id=b.id

【08】:SQL性能优化的目标:至少要达到 range 级别,要求是ref级别,如果可以是consts最好。 说明:

1) consts 单表中最多只有一个匹配行(主键或者唯一索引),在优化阶段即可读取到数据。

2) ref 指的是使用普通的索引(normal index)。

3) range 对索引进行范围检索。

反例:explain表的结果,type=index,索引物理文件全扫描,速度非常慢,这个index级别比较range还低,与全表扫描是小巫见大巫。


SQL语句

【01】:不要使用count(列名)或count(常量)来替代count(*),count(*)是SQL92定义的标准统计行数的语法,跟数据库无关,跟NULL和非NULL无关。 说明:count(*)会统计值为NULL的行,而count(列名)不会统计此列为NULL值的行。

【02】:count(distinct col) 计算该列除NULL之外的不重复行数,注意 count(distinct col1, col2) 如果其中一列全为NULL,那么即使另一列有不同的值,也返回为0。

【03】:当某一列的值全是NULL时,count(col)的返回结果为0,但sum(col)的返回结果为NULL,因此使用sum()时需注意NPE问题。

正例:使用如下方式来避免sum的NPE问题:SELECT IFNULL(SUM(column), 0) FROM table;

【08】:数据订正(特别是删除、修改记录操作)时,要先select,避免出现误删除,确认无误才能执行更新语句。

【09】:in操作能避免则避免,若实在避免不了,需要仔细评估in后边的集合元素数量,控制在1000个之内。


相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
28天前
|
Java
Java开发实现图片URL地址检验,如何编码?
【10月更文挑战第14天】Java开发实现图片URL地址检验,如何编码?
59 4
|
27天前
|
监控 Java 测试技术
Java开发现在比较缺少什么工具?
【10月更文挑战第15天】Java开发现在比较缺少什么工具?
34 1
|
28天前
|
Java
Java开发实现图片地址检验,如果无法找到资源则使用默认图片,如何编码?
【10月更文挑战第14天】Java开发实现图片地址检验,如果无法找到资源则使用默认图片,如何编码?
52 2
|
8天前
|
SQL 安全 Java
安全问题已经成为软件开发中不可忽视的重要议题。对于使用Java语言开发的应用程序来说,安全性更是至关重要
在当今网络环境下,Java应用的安全性至关重要。本文深入探讨了Java安全编程的最佳实践,包括代码审查、输入验证、输出编码、访问控制和加密技术等,帮助开发者构建安全可靠的应用。通过掌握相关技术和工具,开发者可以有效防范安全威胁,确保应用的安全性。
21 4
|
10天前
|
缓存 监控 Java
如何运用JAVA开发API接口?
本文详细介绍了如何使用Java开发API接口,涵盖创建、实现、测试和部署接口的关键步骤。同时,讨论了接口的安全性设计和设计原则,帮助开发者构建高效、安全、易于维护的API接口。
32 4
|
20天前
|
开发框架 JavaScript 前端开发
HarmonyOS UI开发:掌握ArkUI(包括Java UI和JS UI)进行界面开发
【10月更文挑战第22天】随着科技发展,操作系统呈现多元化趋势。华为推出的HarmonyOS以其全场景、多设备特性备受关注。本文介绍HarmonyOS的UI开发框架ArkUI,探讨Java UI和JS UI两种开发方式。Java UI适合复杂界面开发,性能较高;JS UI适合快速开发简单界面,跨平台性好。掌握ArkUI可高效打造符合用户需求的界面。
71 8
|
15天前
|
SQL Java 程序员
倍增 Java 程序员的开发效率
应用计算困境:Java 作为主流开发语言,在数据处理方面存在复杂度高的问题,而 SQL 虽然简洁但受限于数据库架构。SPL(Structured Process Language)是一种纯 Java 开发的数据处理语言,结合了 Java 的架构灵活性和 SQL 的简洁性。SPL 提供简洁的语法、完善的计算能力、高效的 IDE、大数据支持、与 Java 应用无缝集成以及开放性和热切换特性,能够大幅提升开发效率和性能。
|
16天前
|
存储 Java 关系型数据库
在Java开发中,数据库连接是应用与数据交互的关键环节。本文通过案例分析,深入探讨Java连接池的原理与最佳实践
在Java开发中,数据库连接是应用与数据交互的关键环节。本文通过案例分析,深入探讨Java连接池的原理与最佳实践,包括连接创建、分配、复用和释放等操作,并通过电商应用实例展示了如何选择合适的连接池库(如HikariCP)和配置参数,实现高效、稳定的数据库连接管理。
33 2
|
16天前
|
监控 Java 数据库连接
在Java开发中,数据库连接管理是关键问题之一
在Java开发中,数据库连接管理是关键问题之一。本文介绍了连接池技术如何通过预创建和管理数据库连接,提高数据库操作的性能和稳定性,减少资源消耗,并简化连接管理。通过示例代码展示了HikariCP连接池的实际应用。
17 1
|
24天前
|
Java 大数据 API
别死脑筋,赶紧学起来!Java之Steam() API 常用方法使用,让开发简单起来!
分享Java Stream API的常用方法,让开发更简单。涵盖filter、map、sorted等操作,提高代码效率与可读性。关注公众号,了解更多技术内容。