从一个实际案例说起

  国庆长假前一个礼拜,老大给我分配了这么一个bug,就是打印出来的报表数量为整数的,有的带小数位,有的不带,毫无规律。

 

  根据短短的两个多月的工作经验以及猜测,最终把范围缩小到以下这段代码块(伪代码)

String output(double num){//double类型的参数num由DAO层提供
String result=null;
if(num等于num的整数部分)//例如12.0000等于12,13.0001不等于13
result=(将num的小数位全部删去,返回相应的字符串,例如12.0000经过处理后返回12);
else
result=(将num的小数位保留4位,返回相应的字符串,例如12.0010经过处理后返回12.0010);
return result;//字符串类型的返回值将直接输出到报表
}

  double类型的传参让我想起了老大一直在向我强调说不要在存储过程中使用double类型的参数,因为可能会出现12.000000001这样的不精确数值,所以我在想问题应该是出现在这里。可是由于本地的数据没有出现这样的问题,所以我无法重现这个故障。于是就我将上面的代码做了小小的修改,问题就算是解决,更新到客户那里之后故障就再也没有出现过了。

String output(double num){//double类型的参数num由DAO层提供
String result=null;
num=(num取四位小数四舍五入返回,例如12.00000001返回12.0000)
if(num等于num的整数部分)//例如12.0000等于12,13.0001不等于13
result=(将num的小数位全部删去,返回相应的字符串,例如12.0000经过处理后返回12);
else
result=(将num的小数位保留4位,返回相应的字符串,例如12.0010经过处理后返回12.0010);
return result;//字符串类型的返回值将直接输出到报表
}

  这就说明了工作经验的重要性。如果没有老大之前的提醒,我恐怕很难想到原因是出在这里(尤其是在故障无法在本地重现,用不了断点测试错误数据的情况下)。年轻人嘛,作为新手,好好积累经验,以后做起工作来就会越来越得心应手。同时,如果花了很多时间都没能解决某个问题,就要适当地问问自己的导师或者经验比自己丰富的同事,向他们求助。

  过了几天任务没那么紧张闲了下来,翻开买了很久的《Effective Java》,惊奇地发现里面有这样的内容:

第48条:如果需要精确的答案,请避免使用float和double

  书中写道:“float和doubble类型主要是为了科学计算和工程计算而设计的。它们执行二进制浮点运算(binary floating-point arithmetic),这是为了在广泛的数值范围上提供较为精确的快速近似计算而精心设计的。然而,它们并没有提供完全精确的结果,所以不应该被用于需要精确结果的场合。float和double类型尤其不适合用于货币计算,因为要让一个float或者double精确地表示0.1(或者10的任何其他负数次方值)是不可能的。”

  假设我们口袋里有一块五,花掉三毛两分之后剩多少钱呢?写个程序试试看

  工作经验需要一天天得积累,急不来,就算急也没有用。但是,我们可以通过看书,照样可以一定程度上弥补作为新人工作经验不足的短处。

看书的时候做实验会很有趣

  (第51条)字符串连接操作符(+,string concatenation operator)是把多个字符串合并为一个字符串的便利途径。要想产生单独一行的输出,或者构造一个字符串来表示一个较小的、大小固定的对象,使用连接操作符是非常合适的,但是它不适合运用在大规模的场景中。为连接n个字符串而重复地使用字符串连接操作符,需要n的平方级的时间。这是由于字符串不可变而导致的不幸结果。当两个字符串被连接在一起时,它们的内容都要被copy。我们先来看一段代码

 private static String statement() {
String result = "";
for (int i = 0; i < 20000; i++)
result += i;
return result;
}

  如果运行的场景使得运算规模更大,这个方法执行时间就难以估算了。为了保证性能,该书作者建议我们使用StringBuilder替代String,来存储建造中的字符串。我们可以做一个实验看看

 package org;

 public class Testing {
public static void main(String[] args) {
long startMili=System.currentTimeMillis();//开始时刻对应的毫秒数
statement();
long endMili = System.currentTimeMillis();//结束时刻对应的毫秒数
System.out.println("实验1所用的时间是:"+(endMili-startMili)+"毫秒"); long startMili2=System.currentTimeMillis();
statement2();
long endMili2 = System.currentTimeMillis();
System.out.println("实验2所用的时间是:"+(endMili2-startMili2)+"毫秒"); } private static String statement() {
String result = "";
for (int i = 0; i < 20000; i++)
result += i;
return result;
} private static String statement2() {
StringBuilder result = new StringBuilder();
for (int i = 0; i < 20000; i++)
result.append(i);
return result.toString();
} }

  运行结果如下(对比相当惊人):

实验1所用的时间是:1627毫秒
实验2所用的时间是:2毫秒

  想象一下,如果工作中遇到这样的问题,恰好被所学过的知识解决了,这是一件多么痛快的事情。不仅大量地节省摸索的时间,还能够激励你花更多的精力投入到自学当中去。

(如果喜欢我写的东西,那就关注我的个人微信公众账号“华工小y”。每天都有好玩有趣的内容与你分享)

《Effective Java》学习笔记——积累和激励的更多相关文章

  1. Effective Java 学习笔记之第七条——避免使用终结(finalizer)方法

    避免使用终结方法(finalizer) 终结方法(finalizer)通常是不可预测的,也是很危险的,一般情况下是不必要的. 不要把finalizer当成C++中析构函数的对应物.java中,当对象不 ...

  2. Effective Java学习笔记

    创建和销毁对象 第一条:考虑用静态工厂方法替代构造器 For example: public static Boolean valueOf(boolean b){ return b ? Boolean ...

  3. Effective Java 学习笔记之所有对象都通用的方法

    一.覆盖equals时请遵守通用约定 1.满足下列任何一个条件时,不需要覆盖equals方法 a.类的每个实例本质上都是唯一的.此时就是Object中equals方法所表达的含义. b.不关心类是否提 ...

  4. Effective Java 学习笔记之创建和销毁对象

    一.考虑用静态工厂方法代替构造器 1.此处的静态工厂方法是指返回指为类的对象的静态方法,而不是设计模式中的静态工厂方法. 2.静态工厂方法的优势有: a.使用不同的方法名称可显著地表明两个静态工厂方法 ...

  5. Effective Java 学习笔记----第7章 通用程序设计

    第7章 通用程序设计 第29条 将局部变量的作用域最小化     使一个局部变量的作用域最小化,最有力的技术室在第一次使用它的地方声明.   第30条 了解和使用库      效率提高.如果你不知道库 ...

  6. effective java学习笔记之不可实例化的类

    在没有显式声明一个类的构造方法时,编译器会生成默认的无参构造方法,在设计工具类时,我们通常将方法设置成静态方法,以类名.方法名的形式调用,此时这个类就没有必要创建实例,我们知道抽象类不可以被实例化,但 ...

  7. Effective Java学习笔记--创建和销毁对象

    创建和销毁对象 一.静态工厂方法代替构造器 静态工厂方法的优缺点 优点: 1.可以自定义名称(可以将功能表述的更加清晰) 2.不必每次调用都创建新的对象(同一对象重复使用) 3.返回的类型可以是原返回 ...

  8. 0037 Java学习笔记-多线程-同步代码块、同步方法、同步锁

    什么是同步 在上一篇0036 Java学习笔记-多线程-创建线程的三种方式示例代码中,实现Runnable创建多条线程,输出中的结果中会有错误,比如一张票卖了两次,有的票没卖的情况,因为线程对象被多条 ...

  9. 0035 Java学习笔记-注解

    什么是注解 注解可以看作类的第6大要素(成员变量.构造器.方法.代码块.内部类) 注解有点像修饰符,可以修饰一些程序要素:类.接口.变量.方法.局部变量等等 注解要和对应的配套工具(APT:Annot ...

随机推荐

  1. Unity3d学习 制作地形

    这周学习了如何在unity中制作地形,就是在一个Terrain的对象上盖几座小山,在山底种几棵树,那就讲一下如何完成上述内容. 1.在新键得项目的游戏的Hierarchy目录中新键一个Terrain对 ...

  2. Jquery 搭配 css 使用,简单有效

    前几篇博客中讲了Jquery的基础和点击实际,下面来说一下和css搭配着来怎么做 还是和往常一样,举个例子 好几个方块,然后设置颜色 <!DOCTYPE html PUBLIC "-/ ...

  3. hash表长度优化证明

    hash表冲突的解决方法一般有两个方向: 一个是倾向于空间换时间,使用向量加链表可以最大程度的在节省空间的前提下解决冲突. 另外一个倾向于时间换空间,下面是关于这种思路的一种合适表长度的证明过程: 这 ...

  4. Laravel 5.x 请求的生命周期(附源码)

    Laravel最早接触是刚开始实习的时候,那时通过网上的学习资料很快便上手,开发模块接口.后来没有什么深入和总结,但是当我刚开始学Laravel的时候,我对Laravel最大的认识就是,框架除了路由. ...

  5. Android Studio —— 重装 HAXM

    Android Studio -- 重装 HAXM 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 文中如有纰漏,欢迎大家留言指出. Android SDK 自带模拟器一直以慢.卡 ...

  6. 说一说python的牛比与不爽

    本人写了10年php了.今年开始改写python了.不是说php有什么不好,php在自己的势力范围内还是很牛比的.只是我已经不能满足于php那两亩地了. 习惯了脚本,所以很自然就过度到python了. ...

  7. JAVA装饰者模式(从现实生活角度理解代码原理)

    装饰者模式可以动态地给一个对象添加一些额外的职责.就增加功能来说,Decorator模式相比生成子类更为灵活. 该模式的适用环境为: (1)在不影响其他对象的情况下,以动态.透明的方式给单个对象添加职 ...

  8. SSH免手动输入密码和设置代理

    通过使用sshpass将密码写入命令里,直接执行,免去手动密码输入的步骤命令如下: sshpass -p password_abc ssh user_abc@ssh_host -p ssh_port ...

  9. 简述我的SOA服务治理

    SOA服务治理 1.解决业务部门服务冲突和纠纷2.版本定义与版本管理3.服务备案与服务管理4.业务监督与服务监控 SOA的战略目的 一.业务价值胜过技术策略 二.战略目标胜过具体项目的效益 三.内置的 ...

  10. 打开程序总是会提示“Enter password to unlock your login keyring” ,如何成功关掉?

    p { margin-bottom: 0.1in; line-height: 120% } 一.一开始我是按照网友所说的 : rm -f ~/.gnome2/keyrings/login.keyrin ...