从一个实际案例说起

  国庆长假前一个礼拜,老大给我分配了这么一个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. 关于.NET异常处理的思考

    年关将至,对于大部分程序员来说,马上就可以闲下来一段时间了,然而在这个闲暇的时间里,唯有争论哪门语言更好可以消磨时光,估计最近会有很多关于java与.net的博文出现,我表示要作为一个吃瓜群众,静静的 ...

  2. 微软.NET Core RC2正式发布,横跨所有平台

    .NET官方博客宣布了<Announcing .NET Core RC2 and .NET Core SDK Preview 1>,正式如期发布了.NET Core RC2, 现在可以放心 ...

  3. 采用MiniProfiler监控EF与.NET MVC项目(Entity Framework 延伸系列1)

    前言 Entity Framework 延伸系列目录 今天来说说EF与MVC项目的性能检测和监控 首先,先介绍一下今天我们使用的工具吧. MiniProfiler~ 这个东西的介绍如下: MVC Mi ...

  4. 浅谈WEB页面提速(前端向)

    记得面试现在这份工作的时候,一位领导语重心长地谈道——当今的世界是互联网的世界,IT企业之间的竞争是很激烈的,如果一个网页的加载和显示速度,相比别人的站点页面有那么0.1秒的提升,那也是很大的一个成就 ...

  5. LeetCode-4MedianofTwoSortedArrays(C#)

    # 题目 4. Median of Two Sorted Arrays There are two sorted arrays nums1 and nums2 of size m and n resp ...

  6. 奇葩问题-TextView无法获取值

    问题场景 前几天写一个界面的时候,遇到一个非常奇葩的问题.app第一次安装的时候,这里针对用户第一次安装的时候,后来是不会出现这个问题了.我明明是对某个界面的一个textview赋值了,而且服务端也返 ...

  7. zookeeper源码分析之四服务端(单机)处理请求流程

    上文: zookeeper源码分析之一服务端启动过程 中,我们介绍了zookeeper服务器的启动过程,其中单机是ZookeeperServer启动,集群使用QuorumPeer启动,那么这次我们分析 ...

  8. ASP.NET MVC一次删除多笔记录

    批量删除数据记录,如下面的截屏: 先选中想删除的记录,然后点一下删除铵钮,系统将把选中的记录一次性删除.在此,Insus.NET不想每删除一笔记录连接一次数据库. 因此需要把选择的记录一次上传至服务器 ...

  9. angular2之前端篇—1(node服务器分支)

    上一篇.net core和angular2之前端篇-1 使用的是dotnet模板.之所以用它,因为想用他写webapi,但是写道下一篇的时候遇到点问题,所以先写个分支测试一下.这次是用Node作为服务 ...

  10. Raspberry Pi(树莓派)上安装Raspbian(无路由器,无显示器)

    一. 准备工作 1. 树莓派主板 型号:树莓派3 B型 处理器:四核64位ARM Cortex-A53 CPU 内核架构:ARMv8 2. 一张大于8G的TF卡(本人用的是32G的,也作为PiLFS用 ...