雷军有一句名言广为流传:你写程序有写诗一样的感觉吗?

我回答:很有写诗的感觉了,反正都是回车键嘛。

写诗固然要放飞想象,但也要注意格律,才会有美感。

写代码亦是如此,犹如戴着镣铐起舞,谨守章法,否则不成了社会摇了么。

比如前些年大火的“梨花体”、“乌青体”、“废话体”,更多的是戏谑的意味在里面吧,要说艺术成就,仿佛是在开一个很认真的玩笑。

假如用以上三种风格来写代码,几乎可以对程序员生涯宣判死刑了,可见诗歌圈还是很宽容的。

有人说,我就乐意用自己的风格来写,反正也能运行,效果也不错。这确实很有可能,毕竟游击队有时候也能打得过正规军呢,但是想当将军,首先就需要对编制标准了然于心。除非你是李云龙嘛。

刚进入公司写代码,我泥腿子一个,写得真是惨不忍睹。老大很耐心,建议我首先养成规范的习惯,这对于代码可读性和维护以及日后的问题定位都是大有裨益的,并给我推荐了一份Google Java Style的文档。

由于是全英文,我读得效率很低(还是要提高姿势水平),于是我找来了阿里的Java规范文档来读,阿里作为大中华Java界最坚实的堡垒,其规范很有标杆性。文档不长,40页,比较完备,在风格约定的同时,简述了原因,其实背后还是有很多Java原理中的细节体现,我读了受益匪浅,将其中一些适合初级程序员的内容筛选总结出来,分享给大家,也约束自己渐渐养成良好的编码习惯。

像写诗一样去写代码,需要很深的功力和理解,首先能做的,是把自己的代码写得像那么回事。

编程规约

命名风格

前提

  1. 禁止使用拼音和英文单词混搭
  2. 尽量避免使用拼音
  3. 切忌盲目缩写。

  1. 类名使用UpperCamelCase方式。
  2. 抽象类命名使用Abstract开头,测试类使用Test结尾 。
  3. 枚举类名后面带上Enum,成员全部大写。
  4. 假如类、接口、方法使用了某设计模式,需要在名称中体现出来。

变量

  1. 布尔类型的变量,不要加is前缀。否则可能会导致一些框架的解析错误,因为有的框架就是通过变量名来解析的。
  2. 变量、方法名使用lowerCamelCase方式。

常量定义

  1. 不允许任何未经定义的字符串直接出现在代码中。可读性差,如果是一些固定值的字符串,可以将其设为常量,并规范命名。

  2. 将常量通过其功能分类,分开维护。

  3. 如果常量在一个固定范围内变化,建议使用枚举型。

代码风格

空格

  1. 左右小括号不允许与括号内相邻字符间出现空格.比如,禁止:
if (`空格`a == b`空格`)
复制代码
  1. if/for/while/switch/do 等保留字与小括号之间必须空格。二目,三目运算符的左右两边必须加空格。比如,正确:
if (a == b && a == c);
a == b ? a = c : a = d;
复制代码
  1. 注释的双斜线必须与内容之间有且仅有一个空格。比如,正确:
// 这是一条注释
a = b;
复制代码
  • 多个参数情况下,每个参数的逗号后加一个空格。比如:
void swap(int a, int b)
复制代码

缩进

  1. 采用四个空格空格进行缩进,禁止使用tab,如果采用tab,必须设置为1个tab为4个空格。(使用tab还是空格键是世纪论题)
  2. 单行字符数不超过120个,超出需要换行,换行时:第二行相对第一行缩进4个空格,方法调用的点参与换行;但是如果是多个方法参数需要换行时,参数间的逗号不参与。比如:
List<VideoData> data = entityIds.stream().map(i -> {VideoData o = videoDataRepository.findByPartnerIdAndEntityId(partnerId, i);o = o == null ? new VideoData() : o;o.setEntityId(i);o.setPartnerId(partnerId);return o;}).collect(Collectors.toList());
复制代码
public ResponseEntity<?> addxxx(@PathVariable("id") Long id,@RequestBody List<Long> ids,@RequestHeader(value="Authorization") String auth)
复制代码

空行

  1. 不同逻辑、语义、业务的代码之间可以插入一个空行,但不必插入多个空行区分。

OOP规约

Object方法

  1. Object的equals方法容易抛空指针异常,所以应该使用常量或确定有值的对象来调用此方法。比如:
"test".equals(object);
复制代码

避免:

object.equals("test");
复制代码
  1. 所有的相同类型的包装类对象之间值的比较,全部使用 equals 方法比较。因为比如IntegerString在某种情况下,会引用缓存池中的对象,而另外的情况会在堆上生成对象,而==比较的是引用的地址。(具体什么时候指向缓存,什么时候指向堆中新建的对象可以查资料)
  2. 谨慎使用Objectclone方法来拷贝对象,因为这是浅拷贝,想要深拷贝可以对clone方法进行重写。

POJO类

  1. POJO类的属性必须使用包装类型,提醒使用者来进行初始化赋值。而基本数据类型会产生默认初始值,这虽然使程序正常运行,但是是不正确的。
  2. 定义 DO/DTO/VO 等 POJO 类时,不要设定任何属性默认值。
  3. 构造器中禁止任何业务逻辑,如果有必要的初始化逻辑,可以放在init()中。
  4. POJO类必须写toString方法。主要是为了在发生异常时,可以直接调用toString来打印属性值,便于排查问题。

其他

  1. 类内方法定义的顺序依次是:公有方法或保护方法 > 私有方法 > getter/setter 方法。(因为公有方法是调用者或维护者最关心的,这条规则我之前一直做反了)
  2. 循环中的字符串连接方式,使用StringBuilderappend方法,不要直接使用字符串相加,因为这会在堆中循环创建新的字符串对象,造成内存浪费(具体参考StringBuilderStringBufferString,这三者的区别以及String的不可变性也是面试的一个初级高频问题)
  3. 方法权限从严控制,严禁宽泛访问权限。这有利于模块解耦,也有利于维护时更加清晰。

集合处理

  1. Set之所以可以储存不可重复对象,是因为根据对象的equalshashcode方法来判断的。所以这两个方法有一定的关联性,重写equals就务必要重写hashcode。我们平时常采用的String类型作为Map的键来用,因为String中已经帮我们把这两个方法重写过了。如果要用其他类型的对象作为Map的键,务必重写这两个方法。而关于HashSet,可以点开HashSet的源码,发现其中主要是一个HashMap

  2. 在使用泛型通配符时,有这两种形式:<? extends T><? super T> 前者的容器无法接收返回的数据,而后者只能接收T类型及其子类的对象,其原因都是编译器提供了一种类型安全的保护。

  3. 不要在 foreach 循环里进行元素的 remove/add 操作。remove 元素请使用 Iterator 方式。具体为什么这么做,可以看一下手册中的举例以及这个博客的解答foreach循环中为什么不要进行remove/add操作

  4. 集合初始化时,尽量根据实际情况指定集合的大小,因为集合动态扩容是很消耗性能的,具体可以查看源码或者相关博客,也是初级高频面试问题。

  5. 使用 entrySet遍历 Map 类集合KV,而不是 keySet 方式进行遍历。

  6. 利用Set 元素唯一的特性,可以快速对一个集合进行去重操作,避免使用 Listcontains 方法进行遍历、对比、去重操作。

并发处理

  1. 创建线程或线程池时,指定有意义的名字,方便维护和检查。
  2. 线程资源必须通过线程池分配,不能显示创建。这样是为了节省线程之间切换导致的过度开销。
  3. 线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样 的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险(这一点感觉有点苛刻,个人认为Executors提供的四种线程池能较好地解决问题时,不需要自己去构建一个ThreadPoolExecutor对象):
1. FixedThreadPool 和 SingleThreadPool:
允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。
2. CachedThreadPool 和 ScheduledThreadPool:
允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。
复制代码
  • 在高并发时,需要考虑锁的性能损耗,不要多余加锁,并且将锁的范围控制在最小化。
  • HashMap是线程不安全的,在并发情况下容易在扩容时出现死链,导致CPU飙升。可以使用其他数据结构比如ConcurrentHashMap来替代,或者加锁。

控制语句

  1. 在一个switch块中,必须包含一个default语句,即使为空。
  2. 在判断或循环中,必须使用大括号。即使只有一行代码,避免采用一行流。
  3. 在高并发场景下,尽量避免使用“=”来作为中断或退出的条件,可以使用“<”、“>”作为区间来判断。假设一个电商场景,商品数量为0时关闭购买入口,但是假如并发出现了错误,数量可能瞬间变为负值,那么程序会一直继续下去。
  4. 在使用判断时,若存在复杂的逻辑语句,可以使用一个命名规范的布尔值来代替这个冗长的语句,以提高代码的可读性。比如:
final boolean existed = (file.open(fileName, "w") != null) && (...) || (...);
if (existed) {...
}
复制代码

异常日志

异常处理

  1. 区分稳定代码与不稳定代码,避免粗暴地对大段代码进行try-catch,这不利于维护和阅读。同时,尽量区分可能抛出的异常类型,再进行相应的处理。
  2. 捕获异常是为了处理它,如果当前处理不了或者不想处理,可以抛给它的调用者。
  3. finally中必须对资源对象、流对象进行关闭。并且不能在内使用return,因为这会导致方法结束,而try中的return得不到执行。
  4. 可能出现的空指针异常:
    1. 包装类型自动拆箱成基本类型
    2. 数据库查询结果为null
    3. 集合中即使有元素,取出的元素也可能为null(比如HashMap允许存入null)
    4. 远程调用返回对象时,一律需要判断是否为空。
    5. 对于session中获取的值,建议进行空指针检查。
  5. 级联调用容易产生空指针异常,比如obj.getA().getB().getC()

日志规约

  1. 对于trace/debug/info级别的日志输出,必须使用条件或占位符的方式,否则可能会出现执行了操作,浪费了资源,但是日志没有打印的情况。建议占位符方式:
logger.debug("Processing trade with id: {} and symbol : {} ", id, symbol);
复制代码
  1. 异常信息应该包括两类信息:案发现场信息和异常堆栈信息。如果不处理,那么通过 关键字 throws 往上抛出。,比如:
logger.error(各类参数或者对象 toString + "_" + e.getMessage(), e);
复制代码
  1. 注意日志输出量的问题,并记得及时删除观察日志。
  2. 注意日志输出的级别。

MYSQL数据库

建表规约

数据类型

  1. 表达布尔概念的字段,必须使用is_xxx来命名,由于mysql中不存在布尔类型的数据类型,使用unsigned tinyint(0和1来表示)
  2. 小数类型为 decimal,禁止使用 floatdouble。因为后两者存在精度丢失的问题,导致在值比较时出现差错。
  3. 使用char定长字符串类型(会预先分配空间)来储存字符串长度几乎相等的数据,比如手机号。varchar是可变长字符串(不会预先分配空间),但是长度不要超过5000。

命名方式

  1. 任何库名、表名、字段名都只能使用小写字母、数字和下划线,并且数字不能放在开头和两个下划线之间
  2. 任何库名、表名、字段名都禁用保留字(这算一个坑,踩过,具体有哪些保留字可以去查文档)表名不能使用复数形式。
  3. 表必备三字段:id, gmt_create, gmt_modified。
  4. 表的命名最好是加上“业务名称_表的作用”。
  5. 主键索引名为 pk_字段名;唯一索引名为 uk_字段名;普通索引名则为 idx_字段名。

分库分表

  1. 单表行数超过 500 万行或者单表容量超过 2GB,才推荐进行分库分表。

索引规约

  1. 具有唯一特性的字段,必须建成唯一索引。唯一索引对insert操作的损耗是可以忽略不计的,而对于提升查找速度的效果非常明显。

工程结构

  1. 开放接口层:可直接封装 Service 方法暴露成 RPC 接口;通过 Web 封装成 http 接口;进行 网关安全控制、流量控制等。
  2. 终端显示层:各个端的模板渲染并执行显示的层。当前主要是 velocity 渲染,JS 渲染, JSP 渲染,移动端展示等。
  3. Web 层:主要是对访问控制进行转发,各类基本参数校验,或者不复用的业务简单处理等。
  4. Service 层:相对具体的业务逻辑服务层。
  5. Manager 层:通用业务处理层,它有如下特征:
    1. 对第三方平台封装的层,预处理返回结果及转化异常信息;
    2. 对 Service 层通用能力的下沉,如缓存方案、中间件通用处理;
    3. 与 DAO 层交互,对多个 DAO 的组合复用。
  6. DAO 层:数据访问层,与底层 MySQL、Oracle、Hbase 等进行数据交互。
  7. 外部接口或第三方平台:包括其它部门 RPC 开放接口,基础平台,其它公司的 HTTP 接口。

如何优雅地编写Java相关推荐

  1. 如何优雅地停止Java进程

    目录 理解停止Java进程的本质 应该如何正确地停止Java进程 如何注册关闭钩子 使用关闭钩子的注意事项 信号量机制 总结 理解停止Java进程的本质 我们知道,Java程序的运行需要一个运行时环境 ...

  2. vmx进程已提前退出_如何优雅地停止Java进程

    目录 理解停止Java进程的本质 应该如何正确地停止Java进程如何注册关闭钩子使用关闭钩子的注意事项信号量机制 总结 理解停止Java进程的本质 我们知道,Java程序的运行需要一个运行时环境,即: ...

  3. 如何更规范化编写Java 代码

    作者: 涛姐涛哥 出处:https://www.cnblogs.com/taojietaoge/p/11575376.html 原文: https://www.cnblogs.com/taojieta ...

  4. java redis管理_优雅时间管理Java轻松做到,想学么?

    原标题:优雅时间管理Java轻松做到,想学么? 来源 |http://rrd.me/gCQHp 前言:需求是这样的,在与第三方对接过程中,对方提供了token进行时效性验证,过一段时间token就会失 ...

  5. 用vs2017编写html,vs2017可以编写java

    vs2017可以编写java [2021-02-06 06:57:17]  简介: 服务器 Dockerfile这个东西我们之前是介绍过,它方便,快捷,易用,而在vs2017中也对docker进行了支 ...

  6. java build path entries 为空_同事的代码简直没法看,我来教你如何更优雅的设计Java异常...

    点击上方蓝色字体,选择"设为星标" 回复"666"获取面试宝典 异常处理是程序开发中必不可少操作之一,但如何正确优雅的对异常进行处理确是一门学问,笔者根据自己的 ...

  7. 编写运行最简单的java程序——使用记事本编写java程序

    编写运行最简单的java程序--使用记事本编写java程序 第一个java程序--使用记事本编辑 经过上篇文章的java环境搭建成功的小伙伴们可以在自己的计算机上编写属于自己的java程序了yo~ 还 ...

  8. 教你如何更优雅的设计Java异常

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 来源:lrwinx https://lrwinx.github.i ...

  9. 如何优雅的设计java异常

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 来源:lrwinx https://lrwinx.github.i ...

最新文章

  1. 美团确定进军自动驾驶,滴滴如何应对?
  2. 深入浅出解释FFT(六)——深入理解fft变换
  3. EasyExcel实现文件读取、导出、上传、下载操作
  4. 室内定位 - 资料收集
  5. adb 更新 android sdk,[转载]安装Android时SDK AVD MANAGER时更新报错的解决办法
  6. 机器人任务规划:从状态机到形式系统
  7. 3像素尺寸是多少_纸张的尺寸
  8. c语言通讯录程序线性表,数据结构(C语言)课设1——单位员工通讯录管理系统(线性表应用)...
  9. 反编译androd的apk文件
  10. [渝粤教育] 盐城工学院 大学物理(力学、振动与波动) 参考 资料
  11. 【重磅】这家技术贼牛的开源公司开始狂招人啦!
  12. 抛弃clover,爱上QTTabBar
  13. Mysql 索引存放位置
  14. 酷开系统AI智能让生活更简单化
  15. ssm基于Vue的共享单车app系统
  16. 024--离职手续办理
  17. OKR实施方法——关于思路和流程的思考
  18. mongodb的聚合函数的$redact方法运用。
  19. 企业想做好数字化转型,中台是关键
  20. 小超模沈青诗窈 荣获第六季完美童模 全球人气亚军

热门文章

  1. php购物车(session)
  2. ssh 免密登录并用脚本群起服务
  3. iOS 项目开发工具JIRA
  4. JavaScript依赖注入的实现思路
  5. 通用软部件(通用管理信息系统)的研究与生产
  6. galera mysql cluster
  7. CentOS Linux使用logrotate分割管理日志
  8. 第四课-Log的使用
  9. Windows Phone 实用开发技巧(18):使用SystemTray显示全局消息提醒
  10. 网关 Apache APISIX 在 360 基础运维平台项目中的实践