金麟岂是池中物,一遇风云便化龙
Posts tagged tips
误区!double类型做加减法不会有误差?
Aug 25th
如果你跟我一样以为Java的double类型只有在作乘除法时才会出现误差,那试一下在Java里执行一下下面的代码:
public static void main(String[] args) { System.out.println(44.42 + 710.79 + 44.42 + 88.85); }
执行前先猜一下结果,是会输出888.48么?还是……?
建议:对于和钱有关的计算,不论加减乘除,统一使用 BigDecimal!
然而不多久之后同事告诉我另一个BigDecimal的问题,试一下下面的代码:
System.out.println(new BigDecimal(0.99).setScale(2, RoundingMode.DOWN).toString());
结果是令人发指的0.98!
看了一下 BigDecimal(double)的源码,其中使用位操作分别提取了0.99浮点值的整数部分和纯小数部分,或者说是2的正数次幂和负数次幂部分。而这样提取出来的值纯小数部分本身就是近似的,与直接使用double类型没有本质区别,这是浮点表示法决定的,再经过2位截取后就产生了误差
而当使用BigDecimal(String)的构造器时得到的是精确值,因为该构造器将数字使用科学计数法表示,即 0.99表示为99*10^-2,这样做运算时先对齐至相同的整数位再进行计算
因此,对上面的补充是:如果要获取最精确的结果,请使用BD+字符串类型的构造器
Spring之经验教训(一)
Jul 18th
在现在的项目中我们使用了spring + hibernate + struts的架构,在享受aop, orm, ioc, di带来的种种便利的同时,我们亦遇到了很多莫名其妙或者说刻骨铭心的教训,今天先整理两点,日后继续补充
经验一:时刻牢记,spring、hibernate对对象 进行了动态代理,尽量不要试图在动态代理后的对象上进行反射,尤其是field!
不管是hibernate的orm还是spring的声明式事务管理,都对原来的pojo、dao进行了动态代理。虽然s、h“号称”动态代理做得天衣无缝且无色无味,但是,那只是在“绝大多数情况下”,如果想对动态代理后的对象进行反射,麻烦便来了,代码片段:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public static void setCreditInfoStatus(CreditInfo info, CreditType type, CreditValidateStatus status) { ... Field[] fields = CreditInfo.class.getDeclaredFields(); for (Field f : fields) { if (f.isAnnotationPresent(Credit.class) && f.getAnnotation(Credit.class).value() == type) { PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(CreditInfo.class, f.getName()); if (pd != null) { ... } break; } } } |
原先第7行写为 info.getClass(),乍一看与现有的代码功能上是一样的,但是别忘了让人又恨又爱的动态代理!上面代码返回的是真正的CreditInfo class,而左边的返回的是动态代理后的class,即意味着,第一个“if”永远返回的是false,除非动态代理后的对象的field上附带了原有的annotation
经验二:spring的声明式事务管理确很强大,强大到可以支持多线程,但是,结合上一点,不要在线程中调用this中的事务方法
声明式事务,即spring中使用aop织入或 @Transactional标记的方法注入事务容器,码农们可以完全不用操心何时begin,何时commit,何时 rollback,有没有嵌套,绝对傻瓜级的编程模型。但是,牢记,spring中的aop、annotation都是使用动态代理实现的,即,如果没有经过动态代理便也没有了事务管理,代码片段:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | public class AutomatedService{ ... loanQueue.execute(new Runnable() { @Override public void run() { Thread thread = Thread.currentThread(); while (!thread.isInterrupted()) { try { loanService.checkNSetLoanStatus(); Thread.sleep(loanStatusCheckIntervalMinutes * Consts.ONE_MINUTE); } catch (InterruptedException ex) { thread.interrupt(); } } } }); ... } |
原先的checkNSetLoanStatus方法是定义在AutomatedService中的,且标记了@Transactional。 但是,令人发指的是,checkNSetLoanStatus中的事务没有被提交。在痛定思痛仔细回想了spring的声明式事务的本质后,豁然发现当调用this.checkNSetLoanStatus()时,并没有被织入事务管理。spring还没有霸道到或者说聪明到对this进行动态代理,于是将该方法移至其它service并注入,问题解决
有关64位Snow Leopard
Mar 30th
这篇小tip一直想写,却一直懒得写,今天补上
64位的好处?
谷歌一下你会知道得更多
SL的默认设置?
默认以64位兼容模式启动,即内核为32位,但兼容64位应用程序
如何获知你的内核是跑在32位还是64位下?
打开活动监视器,找到“kernal_task”,看“种类”一列(没有的话加上)是否是“Intel(64位)”
如何知道你的系统是否支持64位?
根据这篇post,可以使用如下命令:
ioreg -l -p IODeviceTree | grep firmware-abi
如何在启动时在32位与64位之间切换?
启动时按住“3”和“2”键或“6”和“4”键(超赞apple这种灵光),但是需要注意,只在本次启动有效,重启后将回到之前的模式
如何使内核一直以64位启动?
根据这篇post,使用如下命令:
nvram boot-args="arch=x86_64"








