命名格调

  • 类名应用UpperCamelCase格调,但下列情景除外:

    • DO: Data Object. 与数据库表构造一一对应,通过DAO层向上传输数据源对象
    • BO: Business Object,业务对象. 由Service层输入的封装业务逻辑的对象
    • DTO: Data Transfer Object,数据传输对象. Service或Manager向外传输的对象
    • VO: View Object,显示对象. 通常是Web向模板渲染引擎层传输的对象
    • AO: Application Object,利用对象. 在Web层与Service层之间形象复用的对象模型
    • PO: POJO缩写,Plain Ordinary Java Object. 专指只有setter/getter/toString的简略类,包含DO,DTO,BO,VO等, 禁止应用xxxPOJO来命名
    • UID
  • 办法名,参数名,成员变量,局部变量都对立应用lowerCamelcase格调
  • 常量命名全副大写,单词间用下划线隔开, 力求语义表白残缺分明,不要嫌名字长
  • 抽象类命名应用Abstract或者Base结尾
  • 异样类命名应用Exception结尾
  • 测试类命名要以要测试的类的名称命名,以Test结尾
  • 类型与中括号紧挨来示意数组
  • POJO类中布尔类型的变量都不要加is前缀,在局部框架中会引起序列化谬误
  • 包名对立应用小写,点分隔符之间有且仅有一个天然语义的英语单词.包名对立应用复数模式.然而类名如果有复数含意,能够应用复数模式
  • 杜绝不标准的缩写,防止望文不知义
  • 为了达到代码自解释的指标,任何自定义的编程元素在命名时,应用尽量残缺的单词组合来表白含意
  • 在常量与变量命名的同时,示意类型的名词放在词尾,以晋升辨识度
  • 如果模块,接口,类,办法应用了设计模式,在命名时须要体现出设计模式
  • 接口类中的办法和属性不要加任何润饰符号(不要加public), 放弃代码的简洁
  • 尽量不要在接口中定义变量,如果肯定要定义变量,肯定是与接口办法无关的,并且是整个利用的根底变量

    • 接口办法签名: void commit()
    • 接口根底常量: String COMPANY="Oxford"
  • 接口和实现类:

    • 对于ServiceDAO类,基于SOA的理念,裸露进去的服务肯定是接口,外部的实现类用Impl的后缀与接口的区别
    • 如果是形容能力的接口名称,去对应的形容词为接口(-able的模式)
  • 枚举类带上Enum后缀,枚举成员名称需全副大写

    • 枚举类是非凡的类,域成员均为常量,且构造方法被默认强制是公有的
  • 各层命名标准:

    • Service或者DAO层办法命名标准:

      • 获取单个对象的办法用get做前缀
      • 获取多个对象的办法用list做前缀 ,复数模式结尾
      • 获取统计值的办法用count做前缀
      • 插入方法应用save或者insert做前缀
      • 删除的办法应用remove或者delete做前缀
      • 批改的办法应用update做前缀
    • 畛域模型命名标准:

      • 数据对象: XxxDO,Xxx为数据表名
      • 数据传输对象: XxxDTO,Xxx为业务畛域相干的名称
      • 展现对象: XxxVO,xxx个别为网页名称
      • POJO为DO,DTO,BO,VO的统称,禁止命名成XxxPOJO

        常量定义

  • 不容许任何未经事后定义的常量呈现在代码中
  • 在long或者Long赋值时,数值后应用大写的L, 不能是小写的l. 因为小写容易和数字1混同,造成误会
  • 不要应用一个常量类保护所有常量,要按常量的性能进行归类,离开保护

    • 大而全的常量类横七竖八,应用查找性能能力定位到批改的常量,不利于了解和保护
  • 常量的复用档次有五层:

    • 跨利用共享常量: 搁置在二方库中,通常是client.jar中的constant目录下
    • 利用类共享常量 搁置在一方库中,通常是子模块中的constant目录下
    • 子工程内共享常量 在以后子工程的constant目录下
    • 包内共享常量 在以后包的constant目录下
    • 类内共享常量 间接在类外部private static final定义
  • 如果变量值仅在一个固定范畴内变动,应用enum类型定义

    • 如果存在名称之外的延长属性应应用enum类型,比方节令,示意一年中第几个节令:

      public enum SeasonEnum {SPRING(1),SUMMER(2),AUTUMN(3),WINTER(4);private int seq;SeasonEnum(int seq) {    this.seq=seq;}} 

      代码格局

  • 大括号的应用约定:

    • 如果大括号内为空,则简洁地写成 { } 即可,不须要换行
    • 如果是非空代码块:

      • 左大括号前不换行
      • 左大括号后换行
      • 右大括号前换行
      • 右大括号后如果还有else则不换行
      • 示意终止的右大括号后必须换行
  • 小括号的应用约定:

    • 左小括号和字符之间不要呈现空格
    • 右小括号和字符之间也不要呈现空格
    • 左大括号之前须要空格
  • if,for,while,switch,do等保留字与括号之间都必须加空格
  • 任何二目,三目运算符左右两边都须要加一个空格

    • 运算符包含:

      • 赋值运算符 :=
      • 逻辑运算符 :&&
      • 加减乘除符号
  • 采纳4个空格进行缩进
  • 正文的双斜线与正文内容之间有且仅有一个空格
  • 办法参数在定义和传入时,多个参数逗号前面必须加空格
  • 单个办法的总行数不要超过80行:

    • 除正文之外的办法签名,左右大括号,办法内代码,空行,回车及任何不可见字符的总行数不超过80行
    • 代码逻辑分清红花和绿叶,共性和共性:

      • 绿叶逻辑独自进去成为额定的办法,使骨干代码更加清晰
      • 共性逻辑抽取成共性办法,便于复用和保护
  • 不须要减少若干空格来使某一行的字符与上一行对应地位的字符对齐
  • 不同逻辑,不同语义,不同业务代码之间只须要插入一个空行宰割来晋升可读性即可

    OPP规约

  • 防止通过一个类的对象援用拜访类的动态变量和静态方法,这会减少编译器的解析老本,间接应用类名拜访即可
  • 所有的覆写办法,必须加 @Override
  • 雷同参数类型,雷同业务含意,才能够应用Java的可变参数,防止可变参数应用Object类型

    • 可变参数必须搁置在参数列表的最初, 倡议尽量不要用可变参数编程
  • 内部正在调用的或者二方库依赖的接口,不容许批改办法签名(办法名和参数列表),防止对接口的调用方产生影响 .接口过期必须加上 ==@Deprecated== 注解,并清晰地阐明采纳的新接口和新服务是什么
  • 不能应用过期的类或办法:

    • 接口的提供方既然明确是过期接口,那么有任务提供新接口
    • 作为调用方,有任务考据过期办法的新实现是什么
  • Objectequals办法容易抛出空指针异样,应应用常量或者确定有值的对象来调用equals

    • "test".equals(Object)
    • 举荐应用java.util.objects
  • 所有雷同类型的包装类对象之间的值的比拟,全副应用equals办法比拟

    • 对于 Integer var = ? 在-128至127范畴内赋值时 ,Integer对象是在IntegerCache.cache中产生,会复用已有对象,这个区间内的Integer值能够间接应用 == 进行判断
    • 然而这个区间之外的所有数据,都会在堆上产生,并不会复用已有对象,所以举荐应用equals办法进行比拟
  • 任何货币金额,均以最小货币单位且整型类型来进行存储
  • 浮点数之间的等值判断:

    • 根本类型不能用 == 来比拟
    • 包装类型不能应用equals来判断

      • 浮点数采纳尾数+阶码的编码方式,相似与迷信计数法有效数字+指数的示意形式. 二进制无奈准确示意大部分十进制小数
    • 为了避免出现问题,所有的浮点数都应用BigDecimal定义

      /* * float类型的浮点数: *         指定一个误差范畴, *         两个浮点数的差值在此范畴之内, *         则认为是相等的. */ float a = 1.0f - 0.9f; float b = 0.9f - 0.8f; float diff = 1e - 6f; if (Math.abs(a-b) < diff) { System.out.println("true"); }/*  *  应用BigDecimal来定义值,再进行浮点数的运算操作 */ BigDecimal a = new BigDecimal("1.0"); BigDecimal b = new BigDecimal("0.9"); BigDecimal c = new BigDecimal("0.8"); BigDecimal x = a.substract(b);  BigDecimal y = b.substract(c); if (x.equals(y)) { System.out.println("true"); } 
  • 定义数据对象DO类时,属性类型要与数据库字段类型相匹配

    • 数据库字段的bigint必须与类属性Long类型绝对应
  • 禁止应用构造方法BigDecimal(double) 的形式将double值转化为BigDecimal对象:

    • BigDecimal(double)存在精度损失危险,在准确计算或值比拟的场景中会导致业务逻辑异样

      • 举荐应用入参为String的构造方法
      • 或者应用BigDecimalvalueOf办法: 此办法外部执行了Double的toString,理论能表白的精度对尾数进行了截断

        BigDecimal a = new BigDecimal("0.1");BigDecimal b = BigDecimal.valueOf(0.1);
  • 根本类型和包装类型的应用规范:

    • 所有的POJO类属性必须应用包装类数据类型
    • RPC办法的返回值和参数必须应用包装数据类型
    • 所有的局部变量应用根本数据类型
  • 定义DO,DTO,VO等POJO类时,不要设定任何属性默认值
  • 序列化类新增属性时,不能批改serialVersionUID字段,这样会导致反序列化失败;如果齐全不兼容降级,防止反序列化凌乱,能够批改serialVersionUID值.在serialVersionUID不统一时会抛出序列化运行时异样
  • 构造方法中禁止退出任何业务逻辑,如果有初始化逻辑,要放在init
  • POJO类必须写toString办法.如果继承了一个POJO类,须要在后面增加super.toString

    • 这样在办法执行抛出异样时,能够间接调用POJO的toString()办法打印属性值,便于排查问题
  • 禁止在POJO类中,同时存在对应属性Xxx的isXxx()getXxx() 办法

    • 框架在调用属性Xxx的获取办法时,不能确定哪个办法肯定是被优先调用到的
  • 应用索引拜访用String的split办法失去的数组时,须要做最初一个分隔符后有无内容的查看, 否则会有IndexOutofBoundsException异样
  • 当一个类有多个构造方法,或者多个同名办法,这些办法应该按程序搁置在一起,便于浏览
  • 类内办法定义的程序顺次为:

    • 私有办法或者爱护办法

      • 私有办法是类调用者或者保护最频繁应用的办法,最好首先展现
      • 爱护办法只管是子类须要的办法,但也可能是模板设计模式中的外围办法
    • 公有办法

      • 公有办法内部个别不须要关怀,是一个黑盒实现
    • getter或者setter办法

      • 所有Service和DAO的getter或者setter办法都放在类的最初
  • setter办法中,参数名称要和类成员变量名称统一 ,this.成员名=参数名.
  • 在getter或者setter办法中,不要减少业务逻辑
  • 循环体内,字符串的类连贯形式,应用StringBuilderappend办法进行扩大

    • 否则会导致每次循环都会new一个新的StringBuilder对象
    • 而后再进行append操作
    • 最初通过toString办法返回String对象,造成资源节约
  • final能够申明类,成员变量,办法,以及本地变量. 应用final的状况:

    • 不容许被继承的类

      • String
    • 不容许批改的援用的域对象
    • 不容许被重写的办法

      • POJO中的setter办法
    • 不容许运行过程中从新赋值的局部变量
    • 防止上下文重复使用一个变量,应用final形容能够强制从新定义,不便更好地进行重构
  • 不要应用Objectclone办法拷贝对象:

    • 对象的clone办法默认是浅拷贝
    • 若想实现深度拷贝须要重写clone办法实现域对象的深度遍历拷贝须要重写clone办法实现域对象的深度遍历拷贝
  • 类成员与办法访问控制规约:

    • 如果不容许内部间接通过new来创建对象,那么构造方法必须是private
    • 工具类不容许有public或者default构造方法
    • 类非static成员变量并且与子成员共享,必须是protected
    • 类非static成员变量并且仅在本类中应用,必须是private
    • 类static成员变量如果仅在本类中应用,必须是private
    • 若是static成员变量,思考是否为final
    • 类成员办法只供类外部调用时,必须是private
    • 类成员办法只对继承类公开时,限度应用protected

      日期工夫

  • 日期格式化时,传入pattern中示意年份对立应用小写的yyyy

    • 日期格式化时:

      • yyyy示意当天所在的年
      • YYYY示意当天所在的周属于的年份,一周从周日开始,至周六完结.如果本周跨年,返回的YYYY就是下一年
  • 在日期格局中分分明大写的M和小写的m,大写的H和小写的h的含意:

    • 示意月份的是大写的M
    • 示意分钟的是小写的m
    • 24小时的是大写的H
    • 12小时的是小写的h
  • 获取以后的毫秒数 :System.currentTimeMillis()

    • 如果想要获取更加准确的纳秒级的工夫值,应用System.nanoTime()
    • 针对统计工夫的场景,举荐应用Instant
  • 不要应用java.sql中的相干工夫办法
  • 不要在程序中写死一年的为365,防止在公历平年时呈现日期转换谬误或程序逻辑谬误

    • 应用LocalDate办法

      // 获取往年的天数int daysOfThisYear = LocalDate.now().lengthOfYear();// 获取指定某年的天数LocalDate.of(2011, 1, 1).lengthOfYear();
  • 应用Calendar中的枚举值来指代月份

    • 如果应用数字,要留神Date,Calendar等日期相干类的月份month的值在0 - 11之间

      汇合解决

  • hashCode和equals的解决:

    • 只有重写equals, 就必须重写hashCode
    • Set中存储的是不反复的对象,根据hashCodeequals进行判断,所以Set存储的对象必须重写这两个办法
    • 如果自定义对象作为Map的键,必须重写hashCodeequals

      • String重写了hashCodeequals办法所以能够应用String对象作为key来应用
  • ArrayList的subList后果不能够强转成ArrayList,否则会抛出ClassCastException异样:

    • subList返回的是ArrayList的外部类SubList, 并不是ArrayList, 而是ArrayList的一个视图.对于SubList子列表的所有操作最终会反映到原列表上
  • 在subList场景中,要留神对原汇合元素的减少或者删除,都会导致子列表的遍历,减少和删除产生ConcurrentModificationException异样
  • 应用Map的办法:

    • keySet()
    • values()
    • entrySet()
    • 返回汇合对象时,不能够进行增加元素的操作,否则会抛出UnsupportedOperationException异样
  • Collections类返回的对象不能够进行增加或者删除操作:

    • 如果查问无后果,则返回Collection.emptyList()空集合对象. 调用方一旦进行了增加元素操作,就会触发UnsupportedOperationException异样
  • 应用汇合转数组的办法,必须应用汇合的 toArrary(T[] array), 传入的是类型齐全一样的数组,数组的大小就是list.size()

    • 应用toArray带参办法,入参调配的数组空间不够大时,toArray办法外部将重新分配内存空间,并返回新数组的地址;
    • 如果数组元素个数大于理论所需,下标为[list.size()] 的元素的数组元素将被置为null,其余数组元素放弃原值
    • 因而最好将办法入参数组大小定义为与汇合元素个数统一

      List<String> list = new ArrayList<>();list.add("guan");list.add("bao");String[] array = new String[list.size];array = list.toArray(array);
  • 在应用Collection接口任何实现类的addAll() 办法时,都要对输出汇合参数进行NPE判断
  • 应用工具类Arrays.asList()将数组转换成汇合时,不能应用这个相干的批改汇合的办法,这个汇合的add, remove, clear办法会抛出UnsupportedOperationException异样

    • asList的返回对象是一个Arrays外部类,并没有实现汇合的批改办法
    • Arrays.asList体现的是适配器模式,只是转换接口,后盾数据仍旧是数组
  • 泛型通配符 <? extends T> 来接管返回的数据,这种写法的泛型汇合不能应用add办法 ;<? super T> 不能应用get办法,作为接口调用赋值时会出错

    • PECS(Producer Extends Consumer Super)准则:

      • 频繁往外读取内容,适宜应用<? extends T>
      • 常常往里插入的,适宜应用<? super T>
  • 不要在foreach循环里进行元素的remove或者add操作

    • remove元素要应用Iterator形式,如果是并发操作,要对Iterator对象加锁

      List<String> list = new ArrayList<>();list.add("1");list.add("2");Iterator<String> iterator = list.iterator();while (iterator.hasNext()) {String item = iterator.next();if (condition) {    iterator.remove();}}
  • JDK 7当前的版本中 ,Comparator实现要满足三个条件,否则Arrays.sort, Collections.sort会呈现IllegalArgumentException异样:

    • x, y的比拟后果和y, x的比拟后果相同
    • x > y, y > z, 则 x > z
    • x = y, 则x, z比拟后果和y, z比拟后果雷同
  • JDK 7当前的版本中,给汇合的泛型定义时,应用全省略,即间接应用 <> 来指定前边曾经指定的类型
  • 汇合初始化时,指定汇合初始值大小

    • HashMap应用HashMap(int initialCapacity) 初始化
    • initalCapacity = (须要存储的元素个数 / 负载因子) + 1. 留神负载因子(即loader factor)默认为0.75,如果临时无奈确定初始值的大小,设为为默认值16
  • 应用entrySet遍历Map类汇合kv, 而不是应用keySet形式进行遍历

    • 如果应用keySet形式遍历,其实是遍历了两次:

      • 一次转换为Iterator对象
      • 一次从hashMap中取出key所对应的value
    • entrySet只是遍历一次就把keyvalue都放到了entry中,效率更高
    • 如果是JDK 8当前的版本,应用Map.foreach办法
    • 示例:

      • values()返回的是V值汇合,是一个list汇合对象
      • keySet()返回的是K值汇合,是一个Set汇合对象
      • entrySet()返回的是K-V值组合汇合
  • 要留神Map类汇合中的K-V能不能存储null值的状况:
汇合类KeyValueSuper阐明
Hashtable不容许为null不容许为nullDictionary线程平安
ConcurrentHashMap不容许为null不容许为nullAbstractMap锁分段技术
TreeMap不容许为null容许为nullAbstractMap线程不平安
HashMap容许为null容许为nullAbstractMap线程不平安

因为HashMap的烦扰,误以为ConcurrentHashMap能够置入null值,其实这样会抛出NPE异样

  • 正当利用汇合的有序型 - sort和汇合的稳定性 - order, 防止汇合的无序性 - unsort和不稳定性 - unorder带来的负面影响

    • 有序性是指遍历的后果依照某种比拟规定顺次排列的
    • 稳定性是指汇合每次遍历的元素秩序是肯定的
    • ArrayList, HashMap, TreeSet
  • 利用Set元素惟一的个性,能够疾速对一个汇合进行去重操作

    • 防止应用List的contains办法进行遍历,比照,去重操作

      并发解决

  • 获取单例对象须要保障线程平安,其中的办法也要保障线程平安

    • 资源驱动类, 工具类, 单例工厂类都须要留神
  • 创立线程或者线程池时要指定有意义的线程名称,不便出错时回溯
  • 线程资源必须通过线程池提供,不容许在利用中自行显式创立线程

    • 应用线程池的益处是缩小在创立和销毁线程上所耗费的工夫以及系统资源的开销,解决资源有余的问题
    • 如果不应用线程池,有可能造成零碎创立大量同类线程而导致耗费完内存或者适度切换的问题
  • 线程池不容许应用Executors创立,要通过ThreadPoolExecutors创立,这样能够让人更加明确线程池的运行规定,躲避资源耗费的危险

    • Executors返回线程池对象存在以下问题:

      • FixedThreadPool和SingleThreadPool:

        • 容许申请队列长度为Integer.MAX_VALUE,可能会沉积大量申请,导致OOM
      • CachedThreadPool和ScheduledThreadPool:

        • 容许创立的线程数量为Integer.MAX_VALUE,可能会创立大量线程,导致OOM
  • SimpleDateFormat是线程不安全类,不要定义为static变量.如果定义为static,必须加锁,或者应用DateUtils工具类

    • 留神线程平安,应用DateUtils,能够进行如下解决:

      private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>() {  @Override  protected DateFormat initialValue() {      return new SimpleDateFormat("yyyy-MM-dd");  }}
    • 在JDK 8中,能够应用:

      • Instant 代替 Date
      • LocalDateTime 代替 Calendar
      • DateTimeFormatter 代替 SimpleDateFormat
  • 必须回收自定义的ThreadLocal变量:

    • 尤其在线程池场景下,线程常常会被复用,如果不清理自定义的ThreadLocal变量,会影响后续业务逻辑和造成内存透露的问题
    • 尽量在代理中应用try - finally块进行回收

      ObjectThreadLocal.set(userInfo);try {...} finally {ObjectThreadLocal.remove();} 
  • 高并发时,同步调用应该考量锁的性能损耗.

    • 能用无锁数据结构,就不要用锁
    • 能用锁区块,就不要锁整个办法体
    • 能用对象锁,就不要用类锁

      • 尽可能使加锁的代码块工作量尽可能的小,防止在锁代码块中调用RPC办法
  • 对多个资源, 数据库表, 对象同时加锁时,须要保持一致的加锁程序,否则可能会造成死锁

    • 如果线程一须要对A, B, C顺次全副加锁后才能够进行更新操作
    • 那么线程二的加锁程序也必须是A, B, C.否则可能会呈现死锁
  • 在应用阻塞期待获取锁的形式中:

    • 必须在try代码块之外

      • 如果lock办法在try代码块之内,可能因为其它办法抛出异样 ,导致在finally代码块中 ,unlock对未加锁的对象解锁,会调用AQStryRelease办法,抛出IlleagalMonitorStateException异样
    • 必须在加锁办法与try代码块之间没有任何可能抛出异样的办法调用,防止加锁胜利后,在finally中无奈解锁

      • 如果在lock办法与try代码块之间的办法调用抛出异样,那么无奈解锁,造成其它线程无奈获取锁
    • Lock对象的lock办法实现中可能抛出unchecked异样,导致unlock对未加锁的对象解锁,会调用AQStryRelease办法,抛出IlleagalMonitorStateException异样

      Lock lock = new XxxLock();lock.lock();try {...} finally {lock.unlock();}
  • 在应用尝试机制来获取锁的形式中:

    • 进入业务代码之前,必须先判断以后线程是否持有锁
    • 锁的开释规定与锁阻塞期待的形式雷同

      • Lock对象的unlock办法在执行时,会调用AQStryRelease办法,如果以后线程不持有锁, 则抛出IllegalMonitorStateException异样

        Lock lock = new XxxLock();boolean isLocked = lock.tryLock();if (isLocked) {try {  ...} finally {  lock.unlock();}}
  • 并发批改同一记录时,防止更新失落,须要加锁:

    • 在应用层加锁
    • 在缓存加锁
    • 在数据库中加锁
    • 应用version作为更新根据

      • 如果每次拜访概率小于20%, 举荐应用乐观锁
      • 否则的话,应用乐观锁
      • 乐观锁的重试次数不得小于3
  • 多线程并行处理定时工作时:

    • Timer运行多个TimerTask时只有其中之一没有捕捉抛出的异样,工作便会主动终止运行
    • 应用ScheduleExecutorService则没有这个问题
  • 乐观锁遵循一锁二判三更新四开释的准则
  • 应用CountDownLatch进行异步转同步操作:

    • 每个线程退出前必须调用countDown办法
    • 线程执行代码留神catch异样,确保counDown办法被执行到
    • 防止主线程无奈执行至await办法,直到超时才返回后果

      • 子线程抛出的异样堆栈,不能在主线程try-catch失去异样
  • 防止Random实例被多线程应用,共享该实例是线程平安的,然而会因为竞争同一个seed导致性能降落

    • Random实例:

      • java.util.Random的实例
      • Math.random() 的形式
    • 在JDK 7后,能够间接应用ThreadLoalRandom
  • 在并发的场景下,通过双重查看锁double-check locking实现提早初始化来优化问题隐患:

    • 将指标属性申明为volatile
  • volatile用于解决多线程内存不可见问题:

    • 对于一写多读,能够解决变量同步问题
    • 对于多写,无奈解决线程平安问题
    • 对于count++操作,应用如下的类实现:

      AtomicInteger count = new AtomicInteger();count.addAndGet(1);
    • 在JDK 8后,举荐应用LongAdder对象,比AtomicLong性能更好,因为能够缩小乐观锁的重试次数
  • HashMap在容量不够进行resize操作时会因为高并发可能呈现死锁,导致CPU减少:

    • 应用其它的数据结构
    • 加锁
  • ThreadLocal无奈解决共享对象的更新问题,倡议要应用static进行润饰:

    • 这个变量是针对一个线程内所有操作共享的
    • 因而设置为动态变量,所有的此类实例共享此动态变量
    • 即这个变量在类第一次被应用时装载,只调配一块内存空间,只有这个线程内定义的所有此类的对象都能够操作这个变量

      管制语句

  • 在一个switch块内:

    • 每个case要通过break或者return来终止
    • 或者正文阐明程序将继续执行到哪一个case为止
    • 必须蕴含一个default语句并且放在最初,即便是空代码
  • 当Switch括号内的变量类型为String并且此变量为内部参数时,必须进行null判断
  • if, else, for, while, do语句中必须应用大括号,即便只有一行代码,防止采纳单行编码模式
  • 三目运算符: condition ? 表达式1 : 表达式2 要留神表达式1和表达式2在类型对齐时,可能因主动拆箱导致NPE异样

    • 触发类型对齐的拆箱操作:

      • 表达式1或者表达式2只有有一个原始类型
      • 表达式1或者表达式2类型不统一,会强制拆箱升级成示意范畴更大的那个类型
  • 在高并发的场景中,防止应用 “等于” 判断作为中断或者退出的条件

    • 因为如果并发管制没有解决好,容易产生等值判断被 “击穿” 的状况 .要应用大于或者小于区间判断条件来代替
    • 示例: 判断残余数量等于0时,当数量等于0的过程中,因为并发处理错误导致数量霎时变成了正数,这样的话,解决无奈终止
  • 表白异样的分支时,不要应用if - else形式,改写为

    if (condition) {  ...  return obj;}// 而后写else的业务解决逻辑

    对于超过3层的if - else的逻辑判断代码能够应用卫语句,策略模式,状态模式等实现

  • 除罕用的办法 :getXxx, isXxx等,不要在条件判断中执行简单的语句,将简单逻辑判断的后果赋值给一个有意义的布尔变量名,以进步可读性

    • 很多if语句内的逻辑相当简单,须要剖析表达式的最终后果,能力明确什么样的条件执行什么样的语句
  • 不要在其它表达式中(尤其时条件表达式),插入赋值语句
  • 循环体中的语句要考量性能,以下操作尽量挪动至循环体外解决:

    • 定义对象,变量
    • 获取数据库连贯
    • 进行不必要的try - catch操作(思考这个try - catch操作是否能够挪动至循环体外)
  • 防止应用取反逻辑运算符

    • 取反逻辑运算符不利于疾速了解
    • 取反逻辑写法必然存在对应的正向逻辑写法
  • 接口入参爱护: 这种场景常见的是用作批量操作的接口
  • 参数校验:

    • 须要进行参数校验的情景:

      • 调用频次低的办法
      • 执行工夫开销很大的办法

        • 此情景中,参数校验的工夫简直能够忽略不计
        • 然而如果因为参数谬误导致两头执行被退回,或者谬误,就得失相当
      • 须要极高稳定性和可用性的办法
      • 对外提供凋谢接口,无论是 RPC, API, HTTP接口
      • 敏感权限入口
    • 不须要进行参数校验的情景:

      • 极有可能被循环调用的办法. 然而在办法阐明里必须注明内部参数的查看要求
      • 底层调用频度比拟高的办法
      • 被申明成private只会被本人代码所调用的办法.如果可能确定调用办法的代码传入参数曾经做过查看或者必定不会有问题,此时能够不校验参数

        正文规约

  • 类, 类属性, 类办法的正文必须应用Javadoc标准,应用/* xxx /格局,不容许应用// xxx形式
  • 所有形象办法, 包含接口中的办法, 都必须应用Javadoc正文,除了返回值, 参数, 异样阐明外,还必须指出该办法做了什么事件,实现什么性能. 对子类的实现要求以及调用的注意事项须要一并阐明
  • 所有的类都必须增加创建者和创立日期
  • 办法外部正文:

    • 单行正文: 在被正文语句上方另起一行,应用 // 正文
    • 多行正文: 应用 / / 正文,留神与代码对齐
  • 所有枚举类型字段必须要有正文,阐明每个数据项的用处
  • 当程度足够高时,该当应用英文正文. 否则就用中文把问题说分明,只有将专有名词关键字放弃英文原文即可
  • 代码批改的同时,正文也要进行相应的批改,尤其是参数, 返回值, 异样, 外围逻辑等. 要放弃代码与正文更新同步
  • 审慎正文代码:

    • 正文的代码要进行具体的阐明,而不是简略的正文
    • 如果无用,则应该删除
  • 正文的要求:

    • 可能精确反映设计思维和代码逻辑
    • 可能形容业务含意,可能迅速理解到代码背地的信息
  • 好的命名,代码构造是自解释的,正文保障精简精确,表白到位
  • 非凡的正文标记,须要注明标记人与标记工夫.留神及时处理这些标记,通过标记扫描,常常清理此类标记.线上故障有时候就源于这些标记处的代码

    • 待办事宜TODO : (标记人, 标记工夫, [预处理工夫])

      • 示意要实现,但目前尚未实现的性能.这实际上是一个Javadoc的标签.只能利用于类, 接口, 办法
    • 谬误,不能工作FIXME : (标记人, 标记工夫, [预处理工夫])

      • 在正文中用FIXME标记某段代码是谬误的,而且不能工作,须要及时纠正状况

        前后拆散

  • 前后端交互的API,须要明确协定,域名,门路,申请办法,申请内容,状态码,响应体:

    • 协定: 生产环境必须应用HTTPS
    • 门路: 每一个API须要对应一个门路,示意API具体的申请地址

      • 代表资源,只能为名词,举荐应用复数,不能为动词,因为申请办法曾经表白动作含意
      • URL门路不能应用大写,单词如果须要宰割,对立应用下划线
      • 门路禁止携带申请内容类型的后缀 : ".json",".xml", 通过accept头表白即可
    • 申请办法: 对具体操作的定义

      • GET: 获取
      • POST: 新增
      • PUT: 批改
      • DELETE: 删除
    • 申请内容:

      • URL带的参数必须无敏感信息或者合乎平安要求
      • body里带参数时必须设置Content-Type
    • 响应体: 响应体body能够搁置多种数据类型,由Content-Type头来确定
  • 前后端数据列表相干的接口返回时,如果为空,则返回空数组 [ ] 或者空集合 { }
  • 服务端产生谬误时,返回给前端的响应信息必须蕴含HTTP状态码, errorCode, errorMessage, 用户提示信息四个局部:

    • HTTP状态码: 浏览器

      • 200 OK : 表明该申请被胜利实现, 所申请的资源发送到客户端
      • 401 Unauthorized : 申请要求身份验证, 通常是须要登录而用户未登录的状况
      • 403 Forbidden : 服务器拒绝请求, 通常是机密信息或复制其余登录用户链接拜访服务器的状况
      • 404 Not Found : 服务器无奈获得所申请的网页. 申请的资源不存在
      • 500 Internal Server Error: 服务器外部谬误
    • errorCode: 前端开发
    • errorMessage: 谬误排查人员
    • 用户提示信息: 用户. 要求简短清晰,提醒敌对,疏导用户进行下一步操作或者解释谬误起因,上下文环境,举荐操作
  • errorMessage是前后端谬误追踪机制的体现,能够在前端输入到 type="hidden" 的文字类控件或者用户端的日志中,这样可能疾速地定位问题
  • 对于须要应用超大整数的场景,服务端一律应用String字符串返回类型,禁止应用Long类型

    • Java服务端如果间接返回Long整型数据给前端 ,JS会主动转换为Number类型:

      • Number类型: 双精度浮点数,示意原理和取值范畴等同于Java中的Double
      • Long类型: 示意的最大值为2^63^ -1. 超过2^53^(9007199254740992) 的数值转化为JSNumber时,有些数值会有精度损失

        • Long取值范畴内,任何2的指数次整数都是相对不会存在精度损失的,所以说精度损失是一个概率问题
        • 如果浮点数尾数位与指数位空间不限,则能够准确示意任何整数.然而双精度浮点数的尾数位只有52
    • 示例: 通常在订单号或者交易号大于等于16位,大概率会呈现前后端单据不统一的状况. 比方后端的362909601374617692到前端则是362909601374617660
  • HTTP申请通过URL传递参数时,不能超过2048个字节:

    • 不同浏览器对于URL的最大长度限度略有不同,并且对超出最大长度的解决逻辑也有差别. 2048字节是取所有浏览器的最小值
  • HTTP申请通过body传递内容时,必须管制长度,超出最大长度后,后端解析会出错:

    • Nginx默认限度是1MB
    • Tomcat默认限度是2MB
    • 当的确有业务须要传较大内容时,能够通过调大服务器端的限度
  • 在分页场景中,用户输出参数小于1, 则前端返回第一页参数给后端. 后端发现用户输出的参数大于总页数,间接返回最初一页
  • 服务器外部重定向必须应用forward. 内部重定向地址必须应用URL对立代理模块生成,否则会因为线上采纳HTTPS协定而导致浏览器提醒 "不平安", 并且还会带来URL保护不统一的问题
  • 服务器返回信息必须被标记是否能够缓存,如果缓存,客户端可能会重用之前的申请后果

    • 缓存有利于缩小交互次数,缩小交互的均匀提早
    • 示例: http 1.1,s-maxage告诉服务器进行缓存,工夫单位为秒:

      • response.setHeader("Cache-Control", "s-maxage=" + cacheSeconds)
  • 服务端返回的数据,应用JSON格局而非XML :

    • HTTP反对应用不同的输入格局,例如纯文本,JSON,CSV,XML,RSS以至HTML
    • 在应用面向用户的服务,应该抉择JSON作为通信中应用的规范数据交换格局,包含申请和响应

      • application/JSON是一种通用的MIME类型,具备实用,精简,易读的特点
  • 前后端的工夫格局对立为 "yyyy-MM-dd HH:mm:ss", 对立为GMT

    其它留神

  • 在应用正则表达式时, 利用好预编译性能,能够无效放慢正则匹配速度
  • 不要在办法体内定义
  • 二方库中能够定义枚举类型,参数能够应用枚举类型,然而接口返回值不容许应用枚举类型或者蕴含枚举类型的POJO对象
  • velocity调用POJO类的属性时,间接应用属性名取值即可,模板引擎会主动按标准调用POJO的getXxx(), 如果是boolean根本类型变量 ,boolean命名不要加is前缀, 会主动调用isXxx办法.如果是Boolean包装类对象,优先调用getXxx() 办法
  • 后盾输送给页面变量必须加上 $ ! {var},留神两头的感叹号

    • 如果var等于null或者不存在,那么${var}会间接显示在桌面上
  • 留神Math.random() 这个办法返回是double类型,取值范畴0 <= x <1(可能取到零值,留神除零)

    • 如果获取整数类型的随机数,不须要将x放大10的若干倍而后取整,间接应用Random对象的nextInt或者nextLong办法
  • 获取以后秒数System.currentTimeMillis(), 不是应用new Date().getTime()

    • 如果想获取更加准确的纳秒级工夫值,应用System.nanoTime() 的形式
    • 在JDK 8当前,针对统计工夫等常景,须要应用Instant
  • 不要在视图模版中退出任何简单逻辑,依据MVC实践,视图的职责是展现,不要有模型和控制器的代码逻辑
  • 任何数据结构的结构和初始化,都应指定大小,防止数据结构有限增长吃光内存
  • 及时清理不再应用的代码段或配置信息

    • 对于垃圾代码或过期配置,坚定清理洁净,防止程序适度臃肿,代码冗余
    • 对于临时被正文掉,后续可能复原应用的代码片段,在正文代码的上方,对立规定应用三个斜杠/// 来阐明凝视掉代码的理由