[码出高效] 阿里巴巴Java开发手册 1.4.0

在做微服务拆分相关的课题,会涉及到模块化重构和代码重构相关的东西,重构的速度和质量很大程度上取决于代码原本质量的好坏,所以看了一下这本书,有些知识点我也不知道,所以摘抄了其中比较重要的部分规则。

编程规约

命名风格

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

    反例:定义为基本数据类型Boolean isDeleted的属性,它的方法也是isDeleted(),RPC框架在反向解析的时候,“误以为”对应的属性名称是deleted,导致属性获取不到,进而抛出异常。

  2. 【强制】包名统一使用小写,点分隔符之间有且仅有一个自然语义的英语单词。包名统一使用单数形式,但是类名如果有复数含义,类名可以使用复数形式。

    正例:应用工具类包名为com.alibaba.ai.util、类名为MessageUtils(此规则参考spring的框架结构)

  3. 【参考】枚举类名建议带上Enum后缀,枚举成员名称需要全大写,单词间用下划线隔开。

    说明:枚举其实就是特殊的类,域成员均为常量,且构造方法被默认强制是私有。

    正例:枚举名字为ProcessStatusEnum的成员名称:SUCCESS / UNKNOWN_REASON。

常量定义

  1. 【强制】不允许任何魔法值(即未经预先定义的常量)直接出现在代码中。

    反例:

String key = "Id#taobao_" + tradeId;
cache.put(key, value);
  1. 【强制】在long或者Long赋值时,数值后使用大写的L,不能是小写的l,小写容易跟数字1混淆,造成误解。

代码格式

  1. 【强制】采用4个空格缩进,禁止使用tab字符。

    说明: 如果使用 tab 缩进,必须设置 1 个 tab 为 4 个空格。 IDEA 设置 tab 为 4 个空格时,请勿勾选 Use tab character ;而在 eclipse 中,必须勾选 insert spaces for tabs 。

  2. 【强制】IDE的text file encoding设置为UTF-8; IDE中文件的换行符使用Unix格式,不要使用Windows格式。

OOP规约

  1. 【强制】Object的equals方法容易抛空指针异常,应使用常量或确定有值的对象来调用equals。

    正例:“test”.equals(object);

    反例:object.equals(“test”);

    说明:推荐使用java.util.Objects#equals(JDK7引入的工具类)

  2. 【强制】所有的相同类型的包装类对象之间值的比较,全部使用equals方法比较。

    说明:对于Integer var = ? 在-128至127范围内的赋值,Integer对象是在IntegerCache.cache产生,会复用已有对象,这个区间内的Integer值可以直接使用==进行判断,但是这个区间之外的所有数据,都会在堆上产生,并不会复用已有对象,这是一个大坑,推荐使用equals方法进行判断。

  3. 关于基本数据类型与包装数据类型的使用标准如下:

    1) 【强制】所有的POJO类属性必须使用包装数据类型。

    2) 【强制】RPC方法的返回值和参数必须使用包装数据类型。

    3) 【推荐】所有的局部变量使用基本数据类型。

    说明:POJO类属性没有初值是提醒使用者在需要使用时,必须自己显式地进行赋值,任何NPE问题,或者入库检查,都由使用者来保证。

    正例:数据库的查询结果可能是null,因为自动拆箱,用基本数据类型接收有NPE风险。

    反例:比如显示成交总额涨跌情况,即正负x%,x为基本数据类型,调用的RPC服务,调用不成功时,返回的是默认值,页面显示为0%,这是不合理的,应该显示成中划线。所以包装数据类型的null值,能够表示额外的信息,如:远程调用失败,异常退出。

  4. 【强制】定义DO/DTO/VO等POJO类时,不要设定任何属性默认值。

    反例:POJO类的gmtCreate默认值为new Date(),但是这个属性在数据提取时并没有置入具体值,在更新其它字段时又附带更新了此字段,导致创建时间被修改成当前时间。

  5. 【强制】POJO类必须写toString方法。使用IDE中的工具:source> generate toString时,如果继承了另一个POJO类,注意在前面加一下super.toString。

    说明:在方法执行抛出异常时,可以直接调用POJO的toString()方法打印其属性值,便于排查问题。

  6. 【推荐】 类内方法定义的顺序依次是:公有方法或保护方法 > 私有方法 > getter/setter方法。

    说明:公有方法是类的调用者和维护者最关心的方法,首屏展示最好;保护方法虽然只是子类关心,也可能是“模板设计模式”下的核心方法;而私有方法外部一般不需要特别关心,是一个黑盒实现;因为承载的信息价值较低,所有Service和DAO的getter/setter方法放在类体最后。

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

    说明:下例中,反编译出的字节码文件显示每次循环都会new出一个StringBuilder对象,然后进行append操作,最后通过toString方法返回String对象,造成内存资源浪费。

  8. 【推荐】类成员与方法访问控制从严:

    2) 工具类不允许有public或default构造方法。

集合处理

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

    说明:subList 返回的是 ArrayList 的内部类 SubList,并不是 ArrayList而是ArrayList 的一个视图,对于SubList子列表的所有操作最终会反映到原列表上。

  2. 【强制】在subList场景中,高度注意对原集合元素的增加或删除,均会导致子列表的遍历、增加、删除产生ConcurrentModificationException 异常。

  3. 【强制】使用集合转数组的方法,必须使用集合的toArray(T[] array),传入的是类型完全一样的数组,大小就是list.size()。

    说明:使用toArray带参方法,入参分配的数组空间不够大时,toArray方法内部将重新分配内存空间,并返回新数组地址;如果数组元素个数大于实际所需,下标为[ list.size() ]的数组元素将被置为null,其它数组元素保持原值,因此最好将方法入参数组大小定义与集合元素个数一致。

    正例:

List<String> list = new ArrayList<String>(2);
list.add("guan");
list.add("bao");
String[] array = new String[list.size()];
array = list.toArray(array);
反例:直接使用toArray无参方法存在问题,此方法返回值只能是Object[]类,若强转其它类型数组将出现ClassCastException错误。
  1. 【强制】使用工具类Arrays.asList()把数组转换成集合时,不能使用其修改集合相关的方法,它的add/remove/clear方法会抛出UnsupportedOperationException异常。

    说明:asList的返回对象是一个Arrays内部类,并没有实现集合的修改方法。Arrays.asList体现的是适配器模式,只是转换接口,后台的数据仍是数组。

String[] str = new String[] { "you", "wu" }; 
List list = Arrays.asList(str); 
第一种情况:list.add("yangguanbao"); 运行时异常。 

第二种情况:str[0] = "gujin"; 那么list.get(0)也会随之修改。
  1. 【强制】泛型通配符<? extends T>来接收返回的数据,此写法的泛型集合不能使用add方法,而<? super T>不能使用get方法,作为接口调用赋值时易出错。

    说明:扩展说一下PECS(Producer Extends Consumer Super)原则:第一、频繁往外读取内容的,适合用<? extends T>。第二、经常往里插入的,适合用<? super T>。

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

    原因:https://www.cnblogs.com/luyu1993/p/7148765.html

  3. 【推荐】集合初始化时,指定集合初始值大小。 说明:HashMap使用HashMap(int initialCapacity) 初始化。

    正例:initialCapacity (需要存储的元素个数 / 负载因子) + 1。 注意 负载因子(即loader factor 默认为 0.75,如果 暂时无法 确定 初始值大小,请设置为 16(即默认值)。

    反例: HashMap需要 放置 1024个 元素, 由于 没有设置容量 初 始大小,随着元素不断增加,容量 7 次 被迫扩大, resize需要重建 hash表,严重影响性能。

  4. 【推荐】使用entrySet遍历Map类集合KV,而不是keySet方式进行遍历。

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

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

集合类KeyValueSuper说明
Hashtable不允许为null不允许为nullDictionary线程安全
ConcurrentHashMap不允许为null不允许为nullAbstractMap锁分段技术(JDK8:CAS)
TreeMap不允许为null允许为nullAbstractMap线程不安全
HashMap允许为null允许为nullAbstractMap线程不安全
反例: 由于HashMap的干扰,很多人认为ConcurrentHashMap是可以置入null值,而事实上,存储null值时会抛出NPE异常。
  1. 【参考】合理利用好集合的有序性(sort)和稳定性(order),避免集合的无序性(unsort)和不稳定性(unorder)带来的负面影响。

    说明:有序性是指遍历的结果是按某种比较规则依次排列的。稳定性指集合每次遍历的元素次序是一定的。如:ArrayList是order/unsort;HashMap是unorder/unsort;TreeSet是order/sort。

并发处理

  1. 【强制】线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。

    说明: Executors 返回的线程池对象的弊端如下

    1. FixedThreadPool 和 SingleThread Pool
      允许的请求队列长度为 Integer.MAX_VALUE,可 能会堆积大量的请求,从而导致 OOM。

    2. CachedThreadPool 和 ScheduledThreadPool
      允许的创建线程数量为 Integer.MAX_VALUE 可能会创建大量的线程,从而导致 OOM。

  2. 【强制】SimpleDateFormat 是线程不安全的类,一般不要定义为static变量,如果定义为static,必须加锁,或者使用DateUtils工具类。 正例:注意线程安全,使用DateUtils。亦推荐如下处理:

private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>() {
    @Override
    protected DateFormat initialValue() {
        return new SimpleDateFormat("yyyy-MM-dd");
    }
};
说明:如果是JDK8的应用,可以使用Instant代替Date,LocalDateTime代替Calendar,DateTimeFormatter代替SimpleDateFormat,官方给出的解释:simple beautiful strong immutable thread-safe。

`原因:https://blog.csdn.net/weixin_38810239/article/details/79941964`
  1. 【强制】并发修改同一记录时,避免更新丢失,需要加锁。要么在应用层加锁,要么在缓存加锁,要么在数据库层使用乐观锁,使用version作为更新依据。

    说明:如果每次访问冲突概率小于20%,推荐使用乐观锁,否则使用悲观锁。乐观锁的重试次数不得小于3次。

  2. 【参考】volatile解决多线程内存不可见问题。对于一写多读,是可以解决变量同步问题,但是如果多写,同样无法解决线程安全问题。如果是count++操作,使用如下类实现:AtomicInteger count = new AtomicInteger(); count.addAndGet(1); 如果是JDK8,推荐使用LongAdder对象,比AtomicLong性能更好(减少乐观锁的重试次数)。

  3. 【参考】 HashMap在容量不够进行resize时由于高并发可能出现死链,导致CPU飙升,在开发过程中可以使用其它数据结构或加锁来规避此风险。

  4. 【参考】ThreadLocal无法解决共享对象的更新问题,ThreadLocal对象建议使用static修饰。这个变量是针对一个线程内所有操作共享的,所以设置为静态变量,所有此类实例共享此静态变量 ,也就是说在类第一次被使用时装载,只分配一块存储空间,所有此类的对象(只要是这个线程内定义的)都可以操控这个变量。

控制语句

  1. 【推荐】接口入参保护,这种场景常见的是用作批量操作的接口。

    解释:https://www.cnblogs.com/huahua035/p/6905504.html

其它

  1. 【强制】在使用正则表达式时,利用好其预编译功能,可以有效加快正则匹配速度。

    说明:不要在方法体内定义:Pattern pattern = Pattern.compile(“规则”);

  2. 【强制】获取当前毫秒数System.currentTimeMillis(); 而不是new Date().getTime();

    说明:如果想获取更加精确的纳秒级时间值,使用System.nanoTime()的方式。在JDK8中,针对统计时间等场景,推荐使用Instant类。

异常日志

异常处理

  1. 【强制】有try块放到了事务代码中,catch异常后,如果需要回滚事务,一定要注意手动回滚事务。

  2. 【强制】不要在 finally块中使用 return。

    说明: finally块中的 return返回后方法结束执行,不会再执行 try块中的 return语句。

    原因:https://www.cnblogs.com/curious-xdb/articles/5897325.html

日志规约

  1. 【强制】应用中不可直接使用日志系统(Log4j、Logback)中的API,而应依赖使用日志框架SLF4J中的API,使用门面模式的日志框架,有利于维护和各个类的日志处理方式统一。
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final Logger logger = LoggerFactory.getLogger(Abc.class);
  1. 【强制】对trace/debug/info级别的日志输出,必须使用条件输出形式或者使用占位符的方式。

    说明:logger.debug("Processing trade with id: " + id + " and symbol: " + symbol); 如果日志级别是warn,上述日志不会打印,但是会执行字符串拼接操作,如果symbol是对象,会执行toString()方法,浪费了系统资源,执行了上述操作,最终日志却没有打印。

正例:(条件)建设采用如下方式

if (logger.isDebugEnabled()) {
logger.debug("Processing trade with id: " + id + " and symbol: " + symbol);
}

正例:(占位符)

logger.debug("Processing trade with id: {} and symbol : {} ", id, symbol);
  1. 【强制】避免重复打印日志,浪费磁盘空间,务必在log4j.xml中设置additivity=false。

    正例:

	<logger name="com.taobao.dubbo.config" additivity="false">
  1. 【推荐】谨慎地记录日志。生产环境禁止输出debug日志;有选择地输出info日志;如果使用warn来记录刚上线时的业务行为信息,一定要注意日志输出量的问题,避免把服务器磁盘撑爆,并记得及时删除这些观察日志。

单元测试

  1. 【强制】好的单元测试必须遵守AIR原则。 说明:单元测试在线上运行时,感觉像空气(AIR)一样并不存在,但在测试质量的保障上,却是非常关键的。好的单元测试宏观上来说,具有自动化、独立性、可重复执行的特点。
  • A: Automatic 自动化
  • I: Independent 独立性
  • R: Repeatable 可重复
  1. 【推荐】单元测试的基本目标:语句覆盖率达到70%;核心模块的语句覆盖率和分支覆盖率都要达到100%

    说明:在工程规约的应用分层中提到的DAO层,Manager层,可重用度高的Service,都应该进行单元测试。

  2. 【推荐】编写单元测试代码遵守BCDE原则,以保证被测试模块的交付质量。

  • B Border,边界值测试,包括循环边界、特殊取值、特殊时间点、数据顺序等。
  • C Correct,正确的输入,并得到预期的结果。
  • D Design,与设计文档相结合,来编写单元测试。
  • E Error,强制错误信息输入(如:非法数据、异常流程、非业务允许输入等),并得到预期的结果。

安全规约

  1. 【强制】表单、AJAX提交必须执行CSRF安全验证。 说明:CSRF(Cross-site request forgery)跨站请求伪造是一类常见编程漏洞。对于存在CSRF漏洞的应用/网站,攻击者可以事先构造好URL,只要受害者用户一访问,后台便在用户不知情的情况下对数据库中用户参数进行相应修改。

    https://www.cnblogs.com/qmfsun/p/5779469.html

MySQL数据库

建表规约

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

    说明: 任何字段如果为非负数,必须是 unsigned。

    注意: POJO类中的任何布尔类型的变量,都不要加 is前缀,所以,需要在 resultMap 设置从 is_xxx到 Xxx的映射关系。数据库表示是与否的值,使用 tinyint类型,坚持 is_xxx的命名方式是为了明确其取值含义与取值范围。

    正例: 表达逻辑删除的字段名 is_deleted 1 表示删除, 0 表示未删除。

  2. 【强制】主键索引名为pk_字段名;唯一索引名为uk_字段名;普通索引名则为idx_字段名。
    说明:pk_ 即primary key;uk_ 即 unique key;idx_ 即index的简称。

  3. 【强制】小数类型为decimal,禁止使用float和double。

说明:float和double在存储的时候,存在精度损失的问题,很可能在值的比较时,得到不正确的结果。如果存储的数据范围超过decimal的范围,建议将数据拆成整数和小数分开存储。

  1. 【强制】表必备三字段:id, gmt_create, gmt_modified。

    说明: 其中 id必为主键,类型为 bigint unsigned、单表时自增、步长为 1 。 gmt_create, gmt_modified的类型均为datetime类型,前者现在时表示主动创建,后者过去分词表示被动更新。

索引规约

  1. 【强制】超过三个表禁止join。需要join的字段,数据类型必须绝对一致;多表关联查询时,保证被关联的字段需要有索引。

    说明:即使双表join也要注意表索引、SQL性能。

  2. 【推荐】如果有order by的场景,请注意利用索引的有序性。order by 最后的字段是组合索引的一部分,并且放在索引组合顺序的最后,避免出现file_sort的情况,影响查询性能。

    正例:where a=? and b=? order by c; 索引:a_b_c

    反例:索引中有范围查找,那么索引有序性无法利用,如:WHERE a>10 ORDER BY b; 索引a_b无法排序。

    解释:https://blog.csdn.net/u013705066/article/details/82257099

  3. 【推荐】利用覆盖索引来进行查询操作,避免回表。

    说明:如果一本书需要知道第11章是什么标题,会翻开第11章对应的那一页吗?目录浏览一下就好,这个目录就是起到覆盖索引的作用。

    正例:能够建立索引的种类分为主键索引、唯一索引、普通索引三种,而覆盖索引只是一种查询的一种效果,用explain的结果,extra列会出现:using index。

    解释:https://www.cnblogs.com/happyflyingpig/p/7662881.html

  4. 【推荐】利用延迟关联或者子查询优化超多分页场景。

    说明: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

SQL语句

  1. 【强制】不要使用count(列名)或count(常量)来替代count(),count()是SQL92定义的标准统计行数的语法,跟数据库无关,跟NULL和非NULL无关。

    说明:count(*)会统计值为NULL的行,而count(列名)不会统计此列为NULL值的行。

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

    正例:可以使用如下方式来避免sum的NPE问题:SELECT IF(ISNULL(SUM(g)),0,SUM(g)) FROM table;

  3. 【强制】不得使用外键与级联,一切外键概念必须在应用层解决。

    说明:以学生和成绩的关系为例,学生表中的student_id是主键,那么成绩表中的student_id则为外键。如果更新学生表中的student_id,同时触发成绩表中的student_id更新,即为级联更新。外键与级联更新适用于单机低并发,不适合分布式、高并发集群;级联更新是强阻塞,存在数据库更新风暴的风险;外键影响数据库的插入速度。

  4. 【强制】禁止使用存储过程,存储过程难以调试和扩展,更没有移植性。

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

  6. 【参考】 TRUNCATE TABLE 比 DELETE 速度快,且使用的系统和事务日志资源少,但TRUNCATE无事务且不触发trigger,有可能造成事故,故不建议在开发代码中使用此语句。

    说明:TRUNCATE TABLE 在功能上与不带 WHERE 子句的 DELETE 语句相同。

ORM映射

  1. 【强制】在表查询中,一律不要使用 * 作为查询的字段列表,需要哪些字段必须明确写明。

    说明:1)增加查询分析器解析成本。2)增减字段容易与resultMap配置不一致。3)无用字段增加网络消耗,尤其是text类型的字段。

  2. 【强制】POJO类的布尔属性不能加is,而数据库字段必须加is_,要求在resultMap中进行字段与属性之间的映射。

    说明:参见定义POJO类以及数据库字段定义规定,在中增加映射,是必须的。在MyBatis Generator生成的代码中,需要进行对应的修改。

  3. 【强制】sql.xml配置参数使用:#{},#param# 不要使用${} 此种方式容易出现SQL注入。

  4. 【强制】不允许直接拿HashMap与Hashtable作为查询结果集的输出。

    说明:resultClass=”Hashtable”,会置入字段名和属性值,但是值的类型不可控。

  5. 【参考】@Transactional事务不要滥用。事务会影响数据库的QPS,另外使用事务的地方需要考虑各方面的回滚方案,包括缓存回滚、搜索引擎回滚、消息补偿、统计修正等。

  6. 【参考】中的compareValue是与属性值对比的常量,一般是数字,表示相等时带上此条件;表示不为空且不为null时执行;表示不为null值时执行。

    这一条不是很懂,缺少上下文,可能跟具体的实践相关

工程结构

应用分层

  1. 【参考】 (分层异常处理规约)在DAO层,产生的异常类型有很多,无法用细粒度的异常进行catch,使用catch(Exception e)方式,并throw new DAOException(e),不需要打印日志,因为日志在Manager/Service层一定需要捕获并打印到日志文件中去,如果同台服务器再打日志,浪费性能和存储。在Service层出现异常时,必须记录出错日志到磁盘,尽可能带上参数信息,相当于保护案发现场。如果Manager层与Service同机部署,日志方式与DAO层处理一致,如果是单独部署,则采用与Service一致的处理方式。Web层绝不应该继续往上抛异常,因为已经处于顶层,如果意识到这个异常将导致页面无法正常渲染,那么就应该直接跳转到友好错误页面,加上用户容易理解的错误提示信息。开放接口层要将异常处理成错误码和错误信息方式返回。

二方库依赖

  1. 【强制】定义GAV遵从以下规则:

    1) GroupID格式:com.{公司/BU }.业务线 [.子业务线],最多4级。

    说明:{公司/BU} 例如:alibaba/taobao/tmall/aliexpress等BU一级;子业务线可选。

    正例:com.taobao.jstorm 或 com.alibaba.dubbo.register

    2) ArtifactID格式:产品线名-模块名。语义不重复不遗漏,先到中央仓库去查证一下。

    正例:dubbo-client / fastjson-api / jstorm-tool

    3) Version:详细规定参考下方。

  2. 【强制】二方库版本号命名方式:主版本号.次版本号.修订号
    1) 主版本号:产品方向改变,或者大规模API不兼容,或者架构不兼容升级。

    2) 次版本号:保持相对兼容性,增加主要功能特性,影响范围极小的API不兼容修改。

    3) 修订号:保持完全兼容性,修复BUG、新增次要功能特性等。

    说明: 注意起始版本号 必须 为: 1.0.0,而不是 0.0.1 正式发布的类库必须先去中央仓库进行查证,使版本号有延续性,正式版本号不允许覆盖升级。如当前版本:1.3.3,那么下一个合理的版本号:1.3.4 或 1.4.0 或 2.0.0

  3. 【参考】为避免应用二方库的依赖冲突问题,二方库发布者应当遵循以下原则:

    1)精简可控原则。移除一切不必要的API和依赖,只包含 Service API、必要的领域模型对象、Utils类、常量、枚举等。如果依赖其它二方库,尽量是provided引入,让二方库使用者去依赖具体版本号;无log具体实现,只依赖日志框架。

    2)稳定可追溯原则。每个版本的变化应该被记录,二方库由谁维护,源码在哪里,都需要能方便查到。除非用户主动升级版本,否则公共二方库的行为不应该发生变化。

服务器

  1. 【参考】服务器内部重定向使用forward;外部重定向地址使用URL拼装工具类来生成,否则会带来URL维护不一致的问题和潜在的安全风险。

设计规约

  1. 【强制】如果某个业务对象的状态超过3个,使用状态图来表达并且明确状态变化的各个触发条件。

    说明:状态图的核心是对象状态,首先明确对象有多少种状态,然后明确两两状态之间是否存在直接转换关系,再明确触发状态转换的条件是什么。

    正例:淘宝订单状态有已下单、待付款、已付款、待发货、已发货、已收货等。比如已下单与已收货这两种状态之间是不可能有直接转换关系的。

专有名词解释

  1. POJO(Plain Ordinary Java Object): 在本手册中,POJO专指只有setter / getter / toString的简单类,包括DO/DTO/BO/VO等。

  2. GAV(GroupId、ArtifactctId、Version): Maven坐标,是用来唯一标识jar包。

  3. OOP(Object Oriented Programming): 本手册泛指类、对象的编程处理方式。

  4. ORM(Object Relation Mapping): 对象关系映射,对象领域模型与底层数据之间的转换,本文泛指iBATIS, mybatis等框架。

  5. NPE(java.lang.NullPointerException): 空指针异常。

  6. SOA(Service-Oriented Architecture): 面向服务架构,它可以根据需求通过网络对松散耦合的粗粒度应用组件进行分布式部署、组合和使用,有利于提升组件可重用性,可维护性。

  7. IDE(Integrated Development Environment): 用于提供程序开发环境的应用程序,一般包括代码编辑器、编译器、调试器和图形用户界面等工具,本《手册》泛指IntelliJ IDEA和eclipse。

  8. OOM(Out Of Memory): 源于java.lang.OutOfMemoryError,当JVM没有足够的内存来为对象分配空间并且垃圾回收器也无法回收空间时,系统出现的严重状况。

  9. 一方库: 本工程内部子项目模块依赖的库(jar包)。

  10. 二方库: 公司内部发布到中央仓库,可供公司内部其它应用依赖的库(jar包)。

  11. 三方库: 公司之外的开源库(jar包)。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值