我的github: https://github.com/soyoungboy
我的segmentfault: http://segmentfault.com/u/soyoungboy
【不积跬步,无以至千里;不积小流,无以成江海】
博客园 首页 新随笔 联系 订阅 管理
编写高质量代码:改善Java程序的151个建议 --[0~25]
编写高质量代码:改善Java程序的151个建议
警惕自增的陷阱
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:银行家算法
评论: #1楼40268692018/7/23 15:45:04 2018-07-23 15:45 | 夜里挑灯看剑
期待后续。。。 支持(0)反对(0) http://pic.cnblogs.com/face/1129619/20170414104450.png 刷新评论刷新页面返回顶部 注册用户登录后才能发表评论,请 登录 或 注册,访问网站首页。 【推荐】超50万VC++源码: 大型组态工控、电力仿真CAD与GIS源码库!
【前端】SpreadJS表格控件,可嵌入应用开发的在线Excel
【推荐】如何快速搭建人工智能应用?
【活动】AI技术全面场景化落地实践
【大赛】2018首届“顶天立地”AI开发者大赛
最新IT新闻:
· 人类和细菌间的军备竞赛:新型抗生素为何如此难寻?
· 出门问问李志飞:目前是选择性亏损 希望今年营收10亿
· 联手软银 阿里云IoT进入日本市场
· 假如安卓“无法保持免费”,谷歌能做些什么?
· 软银计划年底在日本启动支付业务:与印度Paytm合作
» 更多新闻... 最新知识库文章:
· 那些让人睡不着觉的bug,你有没有遭遇过?
· 观察之道:带你走进可观察性
· 危害程序员职业生涯的三大观念
· 断点单步跟踪是一种低效的调试方法
· 测试 | 让每一粒尘埃有的放矢
» 更多知识库文章... 历史上的今天:
2017-07-23 Cookie知识点总结
昵称:西北野狼
园龄: 4年11个月
粉丝:36
关注: 4 +加关注
|
||||||
日 | 一 | 二 | 三 | 四 | 五 | 六 |
---|---|---|---|---|---|---|
24 | 25 | 26 | 27 | 28 | 29 | 30 |
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 | 1 | 2 | 3 | 4 |
搜索
常用链接
我的标签
- android 5.0(16)
- ormlite(3)
- AndroidGradle(2)
- java复习(2)
- swift object c学习(1)
- Swift or Object c(1)
随笔分类
- 【android 面试】(13)
- 【android】(195)
- 【android--bug】(33)
- 【android--openGL】(1)
- 【androidstudio--学习和使用经验】(2)
- 【android--Thread--线程池的使用】(1)
- 【android--性能优化】(19)
- 【App研发录读书笔记】(6)
- 【Effactive Java】(2)
- 【Eventbus】(7)
- 【Gradle学习】
- 【html5】(6)
- 【IOS】(3)
- 【J2EE】(27)
- 【J2EE面试题】(9)
- 【Java -- JDBC 学习】(12)
- 【java 1.8 新特性学习】(1)
- 【Java NIO -- IO高级进阶】(7)
- 【java 基础复习】(12)
- 【JavaWeb】(5)
- 【java多线程 -- 高级进阶】(13)
- 【JDK源码学习】(8)
- 【json异常】(2)
- 【Kotlin学习和实践】(1)
- 【maven学习】(4)
- 【MySQL】(2)
- 【phoneGap学习】(1)
- 【python 学习】(11)
- 【Rxjava学习】(1)
- 【Servlet】(2)
- 【shell脚本学习】
- 【sqlite高级进阶】(1)
- 【Volley学习和源码分析】(7)
- 【Web前端 -- JavaScript 学习和复习】(8)
- 【Web前端--Html&Css学习复习】(39)
- 【产品知识学习】
- 【计划】(1)
- 【剑指offer java版实现】(2)
- 【设计模式复习】(26)
- 【深入理解java虚拟机】(3)
- 【数据结构与算法】(6)
- 【移动支付】(3)
- 【重构-改善既有代码的设计】
- 【自定义控件】(7)
随笔档案
- 2018年7月 (4)
- 2018年6月 (2)
- 2018年5月 (6)
- 2018年4月 (1)
- 2018年3月 (3)
- 2018年2月 (2)
- 2017年11月 (3)
- 2017年10月 (8)
- 2017年9月 (9)
- 2017年8月 (11)
- 2017年7月 (4)
- 2017年6月 (26)
- 2017年5月 (22)
- 2017年4月 (40)
- 2017年3月 (18)
- 2017年2月 (11)
- 2017年1月 (9)
- 2016年9月 (5)
- 2016年8月 (6)
- 2016年7月 (2)
- 2016年6月 (4)
- 2016年5月 (7)
- 2016年4月 (8)
- 2016年3月 (2)
- 2016年2月 (2)
- 2016年1月 (2)
- 2015年12月 (6)
- 2015年11月 (10)
- 2015年10月 (10)
- 2015年9月 (11)
- 2015年8月 (5)
- 2015年7月 (13)
- 2015年6月 (6)
- 2015年5月 (17)
- 2015年4月 (10)
- 2015年3月 (6)
- 2015年2月 (4)
- 2015年1月 (19)
- 2014年12月 (15)
- 2014年11月 (11)
- 2014年10月 (1)
- 2014年9月 (2)
- 2014年8月 (4)
- 2014年7月 (2)
- 2014年6月 (2)
- 2014年5月 (17)
- 2014年4月 (11)
- 2014年3月 (6)
- 2014年2月 (4)
- 2014年1月 (17)
- 2013年12月 (38)
- 2013年11月 (21)
- 2013年10月 (2)
- 2013年9月 (1)
- 2013年8月 (7)
My github
我的个人博客站点
积分与排名
- 积分 - 135775
- 排名 - 2344
最新评论
- 1. Re:编写高质量代码:改善Java程序的151个建议 --[0~25]
- 期待后续。。。
- --夜里挑灯看剑
- 2. Re:Android开发之adb无法连接
- 感谢楼主,这问题我搞了两天了,重装过两次AS,下过模拟器,网上说的各种adb的方法都试过结果都不行,结果在防火墙里添加了个信任就好了,总之非常感谢!!!
- --D_aisy
- 3. Re:Android开发之adb无法连接
- 为什么能和防火墙扯上关系?
- --那个人是否
- 4. Re:Android开发之adb无法连接
- 感谢楼主,找了一天的错误,总算成功了
- --无所有
- 5. Re:J2EE--常见面试题总结 -- 一
- mark
- --Jason928
阅读排行榜
- 1. Glide加载圆形图片(15249)
- 2. androidstudio--gsonformat--超爽的数据解析方式(10746)
- 3. android app 集成 支付宝支付 微信支付(7130)
- 4. 自定义控件之圆形颜色渐变进度条--SweepGradient(5998)
- 5. Activity生命周期方法调用finish后的不同表现(5341)
评论排行榜
- 1. material design 的android开源代码整理(4)
- 2. Android开发之adb无法连接(3)
- 3. LinkedHashMap 源码解析(2)
- 4. android使用shape做selector按钮按下和弹起的动画(2)
- 5. java泛型操作复习,以及讲解在android中使用的场景(2)
推荐排行榜
- 1. material design 的android开源代码整理(8)
- 2. Android开发之adb无法连接(2)
- 3. J2EE--常见面试题总结 -- ( 一)(1)
- 4. LinkedHashMap 源码解析(1)
- 5. Ajax跨域问题的出现和解决(1)