本文共 9497 字,大约阅读时间需要 31 分钟。
1 ) 【强制】对于 Service
和 DAO
类,基于 SOA
的理念,暴露出来的服务一定是接口,内部
CacheServiceImpl
实现 CacheService
接口。 2 ) 【推荐】 如果是形容能力的接口名称,取对应的形容词为接口名 ( 通常是– able 的形式 ) 。 正例: AbstractTranslator
实现 Translatable
。 1 ) 数据对象: xxxDO , xxx
即为数据表名。
xxxDTO , xxx
为业务领域相关的名称。 3 ) 展示对象: xxxVO , xxx
一般为网页名称。 4 ) POJO
是 DO / DTO / BO / VO
的统称,禁止命名成 xxxPOJO
。 说明:大而全的常量类,非得使用查找功能才能定位到修改的常量,不利于理解和维护。
正例:缓存相关常量放在类CacheConsts
下 ; 系统配置相关常量放在类 ConfigConsts
下。 内共享常量、类内共享常量。
1 ) 跨应用共享常量:放置在二方库中,通常是 client . jar 中的 constant 目录下。 2 ) 应用内共享常量:放置在一方库中,通常是 子模块 中的 constant 目录下。 反例:易懂变量也要统一定义成应用内共享常量,两位攻城师在两个类中分别定义了表示 “是”的变量: 类 A 中:public static final String YES = " yes "
; 类 B 中: public static final String YES = " y "
; A . YES . equals(B . YES)
,预期是 true ,但实际返回为 false ,导致线上问题。 3 ) 子工程内部共享常量:即在当前子工程的 constant 目录下。 4 ) 包内共享常量:即在当前包下单独的 constant 目录下。 5 ) 类内共享常量:直接在类内部 private static final 定义 说明:可变参数必须放置在参数列表的最后
。 ( 提倡同学们尽量不用可变参数编程 )
正例:" test " .equals(object);
反例: object.equals( " test " ); 说明:推荐使用 java . util . Objects # equals(JDK 7 引入的工具类 )说明:对于 Integer var = ? 在-128 至 127 范围内的赋值, Integer 对象是在
IntegerCache . cache 产生,会复用已有对象,这个区间内的 Integer 值可以直接使用==进行 判断,但是这个区间之外的所有数据,都会在堆上产生
,并不会复用已有对象,这是一个大坑, 推荐使用 equals 方法进行判断
1 ) 【强制】所有的 POJO 类属性必须使用包装数据类型
。
RPC 方法的返回值和参数必须使用包装数据类型
。 3 ) 【推荐】所有的局部变量使用基本数据类型。 说明: POJO 类属性没有初值是提醒使用者在需要使用时,必须自己显式地进行赋值,任何 NPE 问题,或者入库检查,都由使用者来保证。 正例:数据库的查询结果可能是 null ,因为自动拆箱,用基本数据类型接收有 NPE 风险。 反例:比如显示成交总额涨跌情况,即正负 x %, x 为基本数据类型,调用的 RPC 服务,调用 不成功时,返回的是默认值,页面显示为 0%,这是不合理的,应该显示成中划线。所以包装 数据类型的 null 值,能够表示额外的信息,如:远程调用失败,异常退出。 说明:反编译出的字节码文件显示每次循环都会 new 出一个 StringBuilder 对象,然后进行
append
操作,最后通过 toString
方法返回 String 对象,造成内存资源浪费。 反例: String str = "start";for (int i = 0; i < 100; i++) {str = str + "hello";}
1 ) 如果不允许外部直接通过 new 来创建对象,那么构造方法必须是 private 。
2 ) 工具类不允许有 public 或 default 构造方法。 3 ) 类非 static 成员变量并且与子类共享,必须是 protected 。 4 ) 类非 static 成员变量并且仅在本类使用,必须是 private 。 5 ) 类 static 成员变量如果仅在本类使用,必须是 private 。 6 ) 若是 static 成员变量,必须考虑是否为 final 。 7 ) 类成员方法只供类内部调用,必须是 private 。 8 ) 类成员方法只对继承类公开,那么限制为 protected 。1) 只要重写 equals ,就必须重写 hashCode 。
2) 因为 Set 存储的是不重复的对象,依据 hashCode 和 equals 进行判断,所以 Set 存储的 对象必须重写这两个方法。 3) 如果自定义对象作为 Map 的键,那么必须重写 hashCode 和 equals 。 说明: String 重写了 hashCode 和 equals 方法,所以我们可以非常愉快地使用 String 对象 作为 key 来使用。异常,即 java . util . RandomAccessSubList cannot be cast to java . util . ArrayList .
说明: subList 返回的是 ArrayList 的内部类 SubList ,并不是 ArrayList ,而是 ArrayList 的一个视图,对于 SubList 子列表的所有操作最终会反映到原列表上
Listlist=new ArrayList<>(); list.add("d"); list.add("33"); list.add("44"); list.add("55"); list.add("66"); List list2 = list.subList(0, 2); System.out.println(list.size());//5 System.out.println(list2.size());//2
总结
使用sublist()返回的只是原list对象的一个视图,因此Sublist内部类和ArrayList的内部保存数据的地址是一样得;即它们在内存中是同一个List(集合),只是parentOffset ,size等参数不同对SubList子列表的所有操作都会最终反映到原列表上
ArrayList的subList结果不可强转成ArrayList,否则会抛出ClassCastException异常。 如果达到的效果要对子集进行操作,原始list不改变。建议以下方式: List
一样的数组,大小就是 list . size() 。
说明:使用 toArray 带参方法,入参分配的数组空间不够大时, toArray 方法内部将重新分配 内存空间,并返回新数组地址 ; 如果数组元素个数大于实际所需,下标为 [ list . size() ] 的数组元素将被置为 null ,其它数组元素保持原值,因此最好将方法入参数组大小定义与集 合元素个数一致。 正例:Listlist = new ArrayList (2);list.add("guan");list.add("bao");String[] array = new String[list.size()];array = list.toArray(array);
反例:直接使用 toArray
无参方法存在问题,此方法返回值只能是 Object[]
类,若强转其它
ClassCastException
错误。 把数组转换成集合时,不能使用其修改集合相关的方法,它的 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)
也会随之修改。 泛型通配符<? extends T >
来接收返回的数据,此写法的泛型集合不能使用 add
方
<? super T>
不能使用 get
方法,作为接口调用赋值时易出错。 说明:扩展说一下 PECS(Producer Extends Consumer Super) 原则
: 第一、频繁往外读取内容的,适合用<? extends T >。 第二、经常往里插入的,适合用 <? super T> remove 元素请使用 Iterator方式,如果并发操作,需要对 Iterator 对象加锁。
正例:
//可以加锁Iteratoriterator = list.iterator();while (iterator.hasNext()) {String item = iterator.next();if (删除元素的条件) {iterator.remove();}}
反例:
Listlist = new ArrayList ();list.add("1");list.add("2");for (String item : list) {if ("1".equals(item)) {list.remove(item);}}
说明:以上代码的执行结果肯定会出乎大家的意料,那么试一下把“1”换成“2”,会是同样的
结果吗?不然 Arrays . sort
,Collections . sort
会报 IllegalArgumentException
异常。
new Comparator() {@Overridepublic int compare(Student o1, Student o2) {return o1.getId() > o2.getId() ? 1 : -1; }};
说明: HashMap 使用 HashMap(int initialCapacity) 初始化,
正例:initialCapacity = (需要存储的元素个数 / 负载因子) + 1
。注意负载因子(即loader factor)默认为 0.75, 如果暂时无法确定初始值大小,请设置为 16(即默认值)。 反例: HashMap 需要放置 1024 个元素,由于没有设置容量初始大小,随着元素不断增加,容 量 7 次被迫扩大, resize 需要重建 hash 表,严重影响性能。 说明:有序性是指遍历的结果是按某种比较规则依次排列的。稳定性指集合每次遍历的元素次
序是一定的。如:ArrayList | order / unsort |
---|---|
HashMap | unorder / unsort |
TreeSet | order / sort |
如果定义为static ,必须加锁,或者使用 DateUtils 工具类。
正例:注意线程安全,使用 DateUtils
。亦推荐如下处理:
private static final ThreadLocaldf = new ThreadLocal () {@ Overrideprotected DateFormat initialValue() {return new SimpleDateFormat("yyyy-MM-dd");}};
说明:如果是 JDK 8 的应用,可以使用 Instant
代替 Date
, LocalDateTime
代替 Calendar
,
DateTimeFormatter
代替 SimpleDateFormat
,官方给出的解释: simple beautiful strong immutable thread - safe 要么在应用层加锁,要么在缓存加锁,要么在数据库层使用乐观锁
,使用 version 作为更新依据。
需要使用数据库的锁机制,比如SQL SERVER 的TABLOCKX
(排它表锁) 此选项被选中时,SQL Server 将在整个表上置排它锁直至该命令或事务结束。这将防止其他进程读取或修改表中的数据。
SqlServer中使用
Begin Tran select top 1 @TrainNo=T_NO from Train_ticket with (UPDLOCK) where S_Flag=0 update Train_ticket set T_Name=user, T_Time=getdate(), S_Flag=1 where T_NO=@TrainNocommit
我们在查询的时候使用了with (UPDLOCK)
选项,在查询记录的时候我们就对记录加上了更新锁,表示我们即将对此记录进行更新. 注意更新锁和共享锁是不冲突的,也就是其他用户还可以查询此表的内容,但是和更新锁和排它锁是冲突的.所以其他的更新用户就会阻塞.
用法场景:
1.在并发场景下,通过双重检查锁 (double - checked locking) 实现延迟初始化的优 化问题隐患 ( 可参考 The " Double - Checked Locking is Broken " Declaration),可将目标属性声明为 volatile 型 2.volatile 解决多线程内存不可见问题。对于一写多读,是可以解决变量同步问题, 但是如果多写,同样无法解决线程安全问题比如: NullPointerException , IndexOutOfBoundsException 等等
当一个外部资源的句柄对象(比如FileInputStream对象)实现了AutoCloseable
接口,那么就可以将上面的板式代码简化为如下形式:
public static void main(String[] args) { try (FileInputStream inputStream = new FileInputStream(new File("test"))) { System.out.println(inputStream.read()); } catch (IOException e) { throw new RuntimeException(e.getMessage(), e); }}
装箱 | 拆箱 |
---|---|
(auto)基本数据类型->包装器类型 | (auto)包装器类型->基本数据类型 |
Integer total = Integer.valueOf (99); | int totalprim = total.intValue (); |
1)i >= 128 || i < -128 =====> new Integer(i) 2)i < 128 && i >= -128 =====> SMALL_VALUES[i + 128]
public static Integer valueOf(int i) { return i >= 128 || i < -128 ? new Integer(i) : SMALL_VALUES[i + 128]; }
@Override public int intValue() { return value; }
@Override public boolean equals(Object o) { return (o instanceof Integer) && (((Integer) o).value == value); }
防止 NPE
,是程序员的基本修养,注意 NPE
产生的场景:
public int f() { return Integer 对象}
, 如果为 null ,自动解箱抛 NPE 。 2 ) 数据库的查询结果可能为 null 。 3 ) 集合里的元素即使 isNotEmpty ,取出的数据元素也可能为 null 。 4 ) 远程调用返回对象时,一律要求进行空指针判断,防止 NPE 。 5 ) 对于 Session 中获取的数据,建议 NPE 检查,避免空指针。 6 ) 级联调用 obj . getA() . getB() . getC(); 一连串调用,易产生 NPE 。 正例:使用 JDK8 的 Optional 类来防止 NPE 问题。 注意取值的范围 0≤ x <1 ( 能够取到零值,注意除零异常 ) ,如果想获取整数类型的随机数,不要将 x 放大 10 的若干倍然后取整,直接使用 Random 对象的 nextInt 或者 nextLong
方法
而不是 new Date() . getTime()
因此使用 sum() 时需注意 NPE 问题。
正例:可以使用如下方式来避免 sum 的 NPE 问题:SELECT IF(ISNULL(SUM(g)) ,0, SUM(g)) FROM table;
转载地址:http://ozcii.baihongyu.com/