从一个实际案例说起

  国庆长假前一个礼拜,老大给我分配了这么一个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 4.6.2正式发布带来众多特性

    虽然大多数人的注意力都集中在.NET Core上,但与原来的.NET Framework相关的工作还在继续..NET Framework 4.6.2正式版已于近日发布,其重点是安全和WinForms/ ...

  2. 前端学HTTP之实体和编码

    前面的话 每天都有各种媒体对象经由HTTP传送,如图像.文本.影片以及软件程序等.HTTP要确保它的报文被正确传送,识别.提取以及适当处理.为了实现这些目标,HTTP使用了完善的标签来描述承载内容的实 ...

  3. mybatis plugins实现项目【全局】读写分离

    在之前的文章中讲述过数据库主从同步和通过注解来为部分方法切换数据源实现读写分离 注解实现读写分离: http://www.cnblogs.com/xiaochangwei/p/4961807.html ...

  4. AFNetworking 3.0 源码解读(十)之 UIActivityIndicatorView/UIRefreshControl/UIImageView + AFNetworking

    我们应该看到过很多类似这样的例子:某个控件拥有加载网络图片的能力.但这究竟是怎么做到的呢?看完这篇文章就明白了. 前言 这篇我们会介绍 AFNetworking 中的3个UIKit中的分类.UIAct ...

  5. JavaScript基础知识总结(三)

    JavaScript语法 七.循环语句 1.while 语法: while (exp) { //statements; } 说明:while (变量<=结束值) { 需执行的代码 } 例子: / ...

  6. MEF学习

    一.   什么是MEF MEF(Managed Extensibility Framework)是一个用于创建可扩展的轻型应用程序的库. 应用程序开发人员可利用该库发现并使用扩展,而无需进行配置. 扩 ...

  7. Linux上运行NET

    今天尝试了下Ubuntu上运行NET程序,按照 https://github.com/aspnet/Home 的指引,一步一步来: 1.安装DNVM(原名KVM) Linux控制台下输入 curl - ...

  8. 分享一个与ABP配套使用的代码生成器源码

    点这里进入ABP系列文章总目录 分享一个与ABP配套使用的代码生成器源码 真对不起关注我博客的朋友, 因最近工作很忙, 很久没有更新博客了.以前答应把自用的代码生成器源码共享出来, 也一直没有时间整理 ...

  9. maven archetype二三事

    maven plugin 创建maven archetype 骨架的plugin是 <plugin> <groupId>org.apache.maven.plugins< ...

  10. C# 仿刷-框架MvcThrottle的使用

    1.介绍 1)用MvcThrottle你能保护你的网站不受攻击.刷. 2)你可以限制与设置多个不同场景允许的IP,设置 每秒/分/天 允许访问IP. 3)你可以定义限制,来处理所有请求.或者某个Con ...