阿里巴巴java开发手册学习

  今天看了下阿里巴巴java开发手册,对其中在工作未注意到的点做了一下整合:
1、对于 Integer var = ? -128 127 范围内的赋值, Integer 对象是在 IntegerCache . cache 产生,会复用已有对象,这个区间内的 Integer 值可以直接使用 == 进行判断,但是这个区间之外的所有数据,都会在堆上产生,并不会复用已有对象,这是一个大坑,推荐使用 equals 方法进行判断。

2、循环体内,字符串的连接方式,使用 StringBuilder append 方法进行扩展。 说明:反编译出的字节码文件显示每次循环都会 new 出一个 StringBuilder 对象,然后进行 append 操作,最后通过 toString 方法返回 String 对象,造成内存资源浪费。
反例:
String str = "start";
for (int i = 0; i < 100; i++) {
str = str + "hello";
}

(在平时经常就是对字符串进行"+"操作,未考虑内存资源问题)

3、如果自定义对象做为 Map 的键,那么必须重写 hashCode equals 。 说明: String 重写了 hashCode equals 方法,所以我们可以非常愉快地使用 String 对象作为 key 来使用。

原因:HashMap中,如果要比较key是否相等,要同时使用这两个函数!因为自定义的类的hashcode()方法继承于Object类,其hashcode码为默认的内存地 址,这样即便有相同含义的两个对象,比较也是不相等的

4、使用集合转数组的方法,必须使用集合的 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 错误。

4、使用工具类 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) 也会随之修改。
需要注意

5、泛型通配符 <? extends T > 来接收返回的数据,此写法的泛型集合不能使用 add 方法,而 <? super T> 不能使用 get 方法,做为接口调用赋值时易出错。 说明:扩展说一下 PECS(Producer Extends Consumer Super) 原则:第一、频繁往外读取内容的,适合用 <? extends T > 。第二、经常往里插入的,适合用 <? super T>

6、集合初始化时,指定集合初始值大小。 说明: HashMap 使用 HashMap(int initialCapacity) 初始化,
正例: initialCapacity = ( 需要存储的元素个数 / 负载因子 ) + 1 。注意负载因子(即 loader factor )默认为 0.75 如果暂时无法确定初始值大小,请设置为 16 (即默认值)。
反例: HashMap 需要放置 1024 个元素,由于没有设置容量初始大小,随着元素不断增加,容量 7 次被迫扩大, resize 需要重建 hash 表,严重影响性能。
在项目的监控服务数据处理过程中,由于数据量庞大,未初始化集合大小,导致底层数据数次扩容,效率降低,导致quart调度器部分任务出现延后执行的情况,在处理最大值及最小值时,对集合采用remove方法,也是效率偏低的一个原因

7、使用 entrySet 遍历 Map 类集合 KV ,而不是 keySet 方式进行遍历。 说明: keySet 其实是遍历了 2 次,一次是转为 Iterator 对象,另一次是从 hashMap 中取出 key 所对应的 value 。而 entrySet 只是遍历了一次就把 key value 都放到了 entry 中,效率更高。如果是 JDK 8 ,使用 Map . foreach 方法。 正例: values() 返回的是 V 值集合,是一个 list 集合对象 keySet() 返回的是 K 值集合,是一个 Set 集合对象 entrySet() 返回的是 K - V 值组合集合。
(lambda表达式之前一直接触过,学习了相应的Map变量方式,确实简洁不少
//map遍历
Map<String,String> map = new HashMap<String,String>();
map.forEach((( id, val) -> print(val)));
)



8、【强制】线程池不允许使用Executors去创建,而是通过 ThreadPoolExecutor 的方式,这样 的处理方式让写同学更加明确线程池运行规则,避资源耗尽风险。 说明:Executors返回的线程池对象 返回的线程池对象 的弊端 如下 : 1)FixedThreadPool和 SingleThreadPoolPool Pool: 允许的请求队列长度为 Integer.MAX_VALUE,可 能会堆积大量的请求,从而导致 OOM。 2)CachedThreadPool 和 ScheduledThreadPool : 允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。
云校园项目采用Executors去创建线程,以后尽量少使用

8、并发修改同一记录时,避免更新丢失,需要加锁。要么在应用层加锁,要么在缓存加锁,要么在数据库层使用乐观锁,使用 version 作为更新依据。 说明:如果每次访问冲突概率小于 20% ,推荐使用乐观锁,否则使用悲观锁。乐观锁的重试次数不得小于 3 次。
监控服务,使用postgres数据库,由于并发,两个节点同时创建数据库表,导致事务出现了问题,后续数据插入不进去,进而导致数据丢失,可采用重试插入的方式来解决

9、多线程并行处理定时任务时, Timer 运行多个 TimeTask 时,只要其中之一没有捕获抛出的异常,其它任务便会自动终止运行,使用 ScheduledExecutorService 则没有这个问题。
项目都是分布式,用的是quart调度器,以后单点环境时需注意


10、volatile 解决多线程内存不可见问题。对于一写多读,是可以解决变量同步问题,但是如果多写,同样无法解决线程安全问题。如果是 count ++ 操作,使用如下类实现: AtomicInteger count = new AtomicInteger(); count . addAndGet( 1 ); 如果是 JDK 8 ,推荐使用 LongAdder 对象,比 AtomicLong 性能更好 减少乐观锁的重试次数
学习了处理变量同步的又一方式
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值