警惕自增的陷阱
public class Client7 {
public static void main(String[] args) {
int count=0;
for(int i=0; i<10;i++){
count=count++;
}
System.out.println("count = "+count);
}
}
count++是一个表达式,是由返回值的,它的返回值就是count自加前的值,Java对自加是这样处理的:首先把count的值(注意是值,不是引用)拷贝到一个临时变量区,然后对count变量+1,最后返回临时变量区的值。程序第一次循环处理步骤如下:
JVM把count的值(其值是0)拷贝到临时变量区;
count的值+1,这时候count的值是1;
返回临时变量区的值,注意这个值是0,没修改过;
返回值赋给count,此时count的值被重置为0.
如下理解:
public static int mockAdd(int count) {
// 先保存初始值
int temp = count;
// 做自增操作
count = count + 1;
// 返回原始值
return temp;
}
不要在本类中覆盖静态导入的变量和方法
编译器有一个"最短路径"原则:如果能够在本类中查找到相关的变量、常量、方法、就不会去其它包或父类、接口中查找,以确保本类中的属性、方法优先。
因此,如果要变更一个被静态导入的方法,最好的办法是在原始类中重构,而不是在本类中覆盖.
显示声明serialVersionUID可以避免对象的不一致,但尽量不要以这种方式向JVM撒谎。
避免用序列化类在构造函数中为不变量赋值
反序列化时构造函数不会执行
反序列化时final变量在以下情况下不会被重新赋值:
- 通过构造函数为final变量赋值
- 通过方法返回值为final变量赋值
- final修饰的属性不是基本类型
使用序列化类的私有方法巧妙解决部分属性持久化问题
public class Person implements Serializable {
private static final long serialVersionUID = 9146176880143026279L;
private String name;
private transient Salary salary;
public Person(String _name, Salary _salary) {
this.name = _name;
this.salary = _salary;
}
//序列化委托方法
private void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject();
oos.writeInt(salary.getBasePay());
}
//反序列化委托方法
private void readObject(ObjectInputStream input)throws ClassNotFoundException, IOException {
input.defaultReadObject();
salary = new Salary(input.readInt(), 0);
}
}
switch 语句里面break不可少
慎用动态编译
- 在框架中谨慎使用:比如要在struts中使用动态编译,动态实现一个类,它若继承自ActionSupport就希望它成为一个Action。能做到,但是debug很困难;再比如在Spring中,写一个动态类,要让它注入到Spring容器中,这是需要花费老大功夫的。
- 不要在要求性能高的项目中使用:如果你在web界面上提供了一个功能,允许上传一个java文件然后运行,那就等于说:"我的机器没有密码,大家都可以看看",这是非常典型的注入漏洞,只要上传一个恶意Java程序就可以让你所有的安全工作毁于一旦。
- 记录动态编译过程:建议记录源文件,目标文件,编译过程,执行过程等日志,不仅仅是为了诊断,还是为了安全和审计,对Java项目来说,空中编译和运行时很不让人放心的,留下这些依据可以很好地优化程序。
断言绝对不是鸡肋
什么情况下能够使用assert呢?一句话:按照正常的执行逻辑不可能到达的代码区域可以防止assert。具体分为三种情况:
在私有方法中放置assert作为输入参数的校验:在私有方法中可以放置assert校验输入参数,因为私有方法的使用者是作者自己,私有的方法的调用者和被调用者是一种契约关系,或者说没有契约关系,期间的约束是靠作者自己控制的,因此加上assert可以更好地预防自己犯错,或者无意的程序犯错。
流程控制中不可能到达的区域:这类似于Junit的fail方法,其标志性的意义就是,程序执行到这里就是错误的
public void doSomething() {
int i = 7;
while (i > 7) {
/* 业务处理 */
}
assert false : "到达这里就表示错误";
}
不要只替换一个类
对于final修饰的基本类型和String类型,编译器会认为它是稳定态的(Immutable Status)所以在编译时就直接把值编译到字节码中了,避免了在运行期引用(Run-time Reference),以提高代码的执行效率。对于我们的例子来说,Client类在编译时字节码中就写上了"150",这个常量,而不是一个地址引用,因此无论你后续怎么修改常量类,只要不重新编译Client类,输出还是照旧。
对于final修饰的类(即非基本类型),编译器会认为它不是稳定态的(Mutable Status),编译时建立的则是引用关系(该类型也叫作Soft Final)。如果Client类引入的常量是一个类或实例,及时不重新编译也会输出最新值。
发布应用系统时禁止使用类文件替换方式,整体WAR包发布才是万全之策。
用偶判断,不用奇判断
i % 2 == 0 ? "偶数" : "奇数";
用整数类型处理货币
(1)、使用BigDecimal
BigDecimal是专门为弥补浮点数无法精确计算的缺憾而设计的类,并且它本身也提供了加减乘除的常用数学算法。特别是与数据库Decimal类型的字段映射时,BigDecimal是最优的解决方案。
(2)、使用整型
把参与运算的值扩大100倍,并转为整型,然后在展现时再缩小100倍,这样处理的好处是计算简单,准确,一般在非金融行业(如零售行业)应用较多。此方法还会用于某些零售POS机,他们输入和输出的全部是整数,那运算就更简单了.
基本类型转换时,使用主动声明方式减少不必要的Bug.
long dis2 = LIGHT_SPEED * 60L * 8;
60L是一个长整型,乘出来的结果也是一个长整型的(此乃Java的基本转换规则,向数据范围大的方向转换,也就是加宽类型),在还没有超过int类型的范围时就已经转换为long型了,彻底解决了越界问题。在实际开发中,更通用的做法是主动声明类型转化(注意,不是强制类型转换)代码如下:
long dis2 = 1L * LIGHT_SPEED * 60L * 8
既然期望的结果是long型,那就让第一个参与的参数也是Long(1L)吧,也就说明"嗨"我已经是长整型了,你们都跟着我一块转为长整型吧。
边界还是边界
int long 这些类型的最大值,最小值的边界处理
银行家舍入(Banker's Round)的近似算法,其规则如下:
舍去位的数值小于5时,直接舍去;
舍去位的数值大于等于6时,进位后舍去;
当舍去位的数值等于5时,分两种情况:5后面还有其它数字(非0),则进位后舍去;若5后面是0(即5是最后一个数字),则根据5前一位数的奇偶性来判断是否需要进位,奇数进位,偶数舍去。
import java.math.BigDecimal;
import java.math.RoundingMode;
public class Client25 {
public static void main(String[] args) {
// 存款
BigDecimal d = new BigDecimal(888888);
// 月利率,乘3计算季利率
BigDecimal r = new BigDecimal(0.001875*3);
//计算利息
BigDecimal i =d.multiply(r).setScale(2,RoundingMode.HALF_EVEN);
System.out.println("季利息是:"+i);
}
}
ROUND_UP:原理零方向舍入。向远离0的方向舍入,也就是说,向绝对值最大的方向舍入,只要舍弃位非0即进位。
ROUND_DOWN:趋向0方向舍入。向0方向靠拢,也就是说,向绝对值最小的方向输入,注意:所有的位都舍弃,不存在进位情况。
ROUND_CEILING:向正无穷方向舍入。向正最大方向靠拢,如果是正数,舍入行为类似于ROUND_UP;如果为负数,则舍入行为类似于ROUND_DOWN.注意:Math.round方法使用的即为此模式。
ROUND_FLOOR:向负无穷方向舍入。向负无穷方向靠拢,如果是正数,则舍入行为类似ROUND_DOWN,如果是负数,舍入行为类似以ROUND_UP。
HALF_UP:最近数字舍入(5舍),这就是我们经典的四舍五入。
HALF_DOWN:最近数字舍入(5舍)。在四舍五入中,5是进位的,在HALF_DOWN中却是舍弃不进位。
HALF_EVEN:银行家算法
编写高质量代码:改善Java程序的151个建议 --[0~25]的更多相关文章
-
博友的 编写高质量代码 改善java程序的151个建议
编写高质量代码 改善java程序的151个建议 http://www.cnblogs.com/selene/category/876189.html
-
编写高质量代码改善java程序的151个建议——导航开篇
2014-05-16 09:08 by Jeff Li 前言 系列文章:[传送门] 下个星期度过这几天的奋战,会抓紧java的进阶学习.听过一句话,大哥说过,你一个月前的代码去看下,慘不忍睹是吧.确实 ...
-
编写高质量代码改善java程序的151个建议——[1-3]基础?亦是基础
原创地址: http://www.cnblogs.com/Alandre/ (泥沙砖瓦浆木匠),需要转载的,保留下! Thanks The reasonable man adapts himse ...
-
编写高质量代码:改善Java程序的151个建议 --[117~128]
编写高质量代码:改善Java程序的151个建议 --[117~128] Thread 不推荐覆写start方法 先看下Thread源码: public synchronized void start( ...
-
编写高质量代码:改善Java程序的151个建议 --[106~117]
编写高质量代码:改善Java程序的151个建议 --[106~117] 动态代理可以使代理模式更加灵活 interface Subject { // 定义一个方法 public void reques ...
-
编写高质量代码:改善Java程序的151个建议 --[78~92]
编写高质量代码:改善Java程序的151个建议 --[78~92] HashMap中的hashCode应避免冲突 多线程使用Vector或HashTable Vector是ArrayList的多线程版 ...
-
编写高质量代码:改善Java程序的151个建议 --[65~78]
编写高质量代码:改善Java程序的151个建议 --[65~78] 原始类型数组不能作为asList的输入参数,否则会引起程序逻辑混乱. public class Client65 { public ...
-
编写高质量代码:改善Java程序的151个建议 --[52~64]
编写高质量代码:改善Java程序的151个建议 --[52~64] 推荐使用String直接量赋值 Java为了避免在一个系统中大量产生String对象(为什么会大量产生,因为String字符串是程序 ...
-
编写高质量代码:改善Java程序的151个建议 --[36~51]
编写高质量代码:改善Java程序的151个建议 --[36~51] 工具类不可实例化 工具类的方法和属性都是静态的,不需要生成实例即可访 问,而且JDK也做了很好的处理,由于不希望被初始化,于是就设置 ...
随机推荐
-
ActiveMQ(5.10.0) - Configuring the JAAS Authentication Plug-in
JAAS provides pluggable authentication, which means ActiveMQ will use the same authentication API re ...
-
HTML+js+css实现点击图片弹出上传文件窗口的两种思路
第一种:CSS实现 <style><!-- .fileInputContainer{ height:256px; background:url(upfil ...
-
Linux简介(好!)
Linux操作系统介绍 来源:233网校论文中心[ 2009-12-02 14:23:00 ]阅读:1作者:王长青编辑:studa20 [摘 要]文章从Unix.Minix系统的产生引出了Linux操 ...
-
javascript (六) 引用外部js文件
外部的 JavaScript 也可以把脚本保存到外部文件中.外部文件通常包含被多个网页使用的代码. 外部 JavaScript 文件的文件扩展名是 .js. 如需使用外部文件,请在 <scrip ...
-
Machine Learning and Data Mining Lecture 1
Machine Learning and Data Mining Lecture 1 1. The learning problem - Outline 1.1 Example of mach ...
-
haproxy的丰富特性简介
*/ .hljs { display: block; overflow-x: auto; padding: 0.5em; color: #333; background: #f8f8f8; } .hl ...
-
C语言博客作业02——循环结构
1.本章学习总结 1.1思维导图 1.2本章学习体会及代码量学习体会 1.2.1学习体会 本周学习了循环结构,在之前学习分支结构的时候就涉及到了循环结构中的for循环,这周的又新学了while和do- ...
-
LNMP笔记:阿里云32位 CentOS 5.4 配置 LNMP环境
最近比较郁闷的是 WordPress大学 服务器故障,由于诸多原因没及时处理,导致10多天无法访问.倡萌也是刚接触服务器环境配置,维护的确力不从心,没办法排查出错误根源,所以只好重置系统盘,重新配置L ...
-
将sass快速引入到移动端项目中加速开发
本文以上图为例子: 首先在根目录创建一个sass文件,在sass文件中分别创建4个文件夹bsae,pages,libs,style; base下存放:样式重置_normalize.scss; 自己定义 ...
-
Spring启动后获取所有拥有特定注解的Bean,注解的属性值
最近项目中遇到一个业务场景,就是在Spring容器启动后获取所有的Bean中实现了一个特定接口的对象,第一个想到的是ApplicationContextAware,在setApplicationCon ...