Effective Java 第三版——59. 熟悉并使用Java类库
Tips
书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code
注意,书中的有些代码里方法是基于Java 9 API中的,所以JDK 最好下载 JDK 9以上的版本。
59. 熟悉并使用Java类库
假设想要生成0到某个上界之间的随机整数。对于这个常见的任务,许多程序员会编写一个类似这样的方法:
// Common but deeply flawed!
static Random rnd = new Random();
static int random(int n) {
return Math.abs(rnd.nextInt()) % n;
}
这个方法可能看起来不错,但它有三个缺陷。 首先,如果n是一个比较小的2的乘方,则随机数的序列将在相当短的时间段后开始重复。 第二个缺陷是,如果n不是2的乘方,平均而言,某些数字会比其他数字出现得更加频繁。 如果n很大,这种效果可能非常明显。 以下程序有力地证明了这一点,该程序在精心选择的范围内生成了100万个随机数,然后打印出有多少个数字落在范围的上半部分:
public static void main(String[] args) {
int n = 2 * (Integer.MAX_VALUE / 3);
int low = 0;
for (int i = 0; i < 1000000; i++)
if (random(n) < n/2)
low++;
System.out.println(low);
}
如果random方法正常工作,程序将打印接近50万的数字,但如果运行它,你会发现它打印的数字接近666,666。random方法生成的三分之二数字落在其范围的上半部分!
random方法的第三个缺陷是,在极少数情况下,它可能会灾难性地失败,返回超出指定范围之外的数字。 这是因为该方法尝试通过调用Math.abs
将rnd.nextInt()
返回的值映射到非负整数。 如果nextInt()
返回Integer.MIN_VALUE
,则Math.abs
也会返回Integer.MIN_VALUE
,假设n不是2的乘方,取模运算符(%)将返回负数。 这几乎肯定会导致程序失败,并且可能难以重现。
要编写一个纠正这些缺陷的random方法的版本,你必须知道关于伪随机数生成器,数论和二进制补码算法的知识。幸运的是,你不必这样做 —— 它已经为你完成了,就是Random.nextInt(int)
方法。你不必关心它如何完成其工作的细节(,如果您很好奇,可以研究文档或源代码)。一位具有算法背景的高级工程师花费了大量时间来设计,实现和测试这种方法,然后向该领域的几位专家展示,以确保其正确性。然后,这个类库经过了beta测试,发布,并被数百万程序员广泛使用了近二十年。该方法尚未发现任何缺陷,但如果发现了缺陷,将在下一个版本中修复。通过使用标准类库,可以利用编写类库专家的知识以及在前人使用它的经验。
从Java 7开始,就不应再使用Random了。 对于大多数用途,选择的随机数生成器现在是ThreadLocalRandom
。 它产生更高质量的随机数,而且速度非常快。 在我的机器上,它比Random快3.6倍。 对于fork-join池和并行流的应用,请使用SplittableRandoms
。
使用这些类库的第二个好处是,不必浪费时间为那些与你的工作关联不大的问题上,而去编写专门的解决方案。如果像大多数程序员一样,那么宁愿将时间花在应用程序上,而不是底层内容上。
使用标准类库的第三个优点是,它们的性能会随着时间的推移而不断提高,而你无需付出任何努力。 因为许多人使用它们并且因为它们被用于行业标准基准测试,所以提供这些类库的组织有强烈的动力使它们运行得更快。 多年来,许多Java平台类库都经过重写,有时甚至是重复编写,从而显着提升性能。
使用类库的第四个优点是它们倾向于随着时间的推移不断增加功能。 如果某个类库遗失了某些东西,开发人员社区就会知道它,并且可能会在后续版本中添加缺少的功能。
使用标准库的最后一个好处是,可以将代码放在主流中。这样的代码更容易被开发人员阅读、维护和重用。
鉴于所有这些优点,使用类库设施优先于专门实现似乎是合乎逻辑的,但许多程序员并不这样做。为什么不呢? 也许他们不知道类库工具设施的存在。 在每个主要版本中,都会向类库中添加许多特性,了解这些新增特性是非常值得的。每次有Java平台的主要版本发布时,都会发布一个web页面来描述它的新特性。这些页面非常值得一读[Java8-feat, Java9-feat]。为了强调这一点,假设你想编写一个程序来打印命令行中指定的URL的内容(这大致与Linux系统下curl命令相同)。 在Java 9之前,这段代码有点乏味,但在Java 9中,transferTo
方法被添加到InputStream中
。 以下是使用此新方法执行此任务的完整程序:
// Printing the contents of a URL with transferTo, added in Java 9
public static void main(String[] args) throws IOException {
try (InputStream in = new URL(args[0]).openStream()) {
in.transferTo(System.out);
}
}
这些类库太大了,以至于无法学习所有文档[Java9-api],但每个程序员都应该熟悉java.lang
,java.util
和java.io
及其子包的基础知识。 可以根据需要获取其他类库的知识。 总结类库设施超出了本条目的范围,这些设施多年来已经发展得非常庞大。
几个类库特别值得一提。 集合Collection框架和流Stream类库(条目4——-48)应该是每个程序员的基本工具包的一部分,java.util.concurrent中
的并发实用程序的也应如此。 该软件既包含了用于简化多线程编程任务的高级实用程序,还包括偏底层的原语,以允许专家编写自己的高级并发抽象。 条目 80和81会讨论java.util.concurrent
的高级部分。
有时,类库设施可能无法满足你的需求。需求越专门化,发生这种情况的可能性就越大。虽然第一个冲动应该是使用这些类库,但是如果已经了解了它们在某些领域提供的功能,而这些功能不能满足你的需求,那么可以使用另一种实现。任何有限的类库集所提供的功能总是存在漏洞。如果你在Java平台库中找不到你需要的东西,你的下一个选择应该是寻找高质量的第三方库,比如谷歌的优秀的开源Guava类库[Guava]。如果无法在任何适当的类库中找到所需的功能,可能别无选择,你只能自己实现了。
总而言之,不要重新发明轮子。 如果需要做一些似乎应该相当常见的事情,那么类库中可能已经有了一个可以满足你需求的工具。 如果有,请使用它; 如果不知道,请检查。 一般来说,类库代码可能比您自己编写的代码更好,并且可能会随着时间的推移而改进。 这并不反映你作为程序员的能力。 规模经济决定了类库代码得到的关注远远超过大多数开发人员可以承担的相同的功能。
Effective Java 第三版——59. 熟悉并使用Java类库的更多相关文章
- 《Effective Java 第三版》目录汇总
经过反复不断的拖延和坚持,所有条目已经翻译完成,供大家分享学习.时间有限,个别地方翻译得比较仓促,希望有疑虑的地方指出批评改正. 第一章简介 忽略 第二章 创建和销毁对象 1. 考虑使用静态工厂方法替 ...
- 《Effective Java 第三版》新条目介绍
版权声明:本文为博主原创文章,可以随意转载,不过请加上原文链接. https://blog.csdn.net/u014717036/article/details/80588806前言 从去年的3月份 ...
- Effective Java第三版(一) ——用静态工厂代替构造器
此文做为<Effective Java>系列的第一篇,所以有必要大概说下此书的特点,当然很多人可能都看过,毕竟是有着Java四大名著之一的大名在外,不过总会有萌新不了解,例如我!<E ...
- Effective Java 第三版——19. 如果使用继承则设计,并文档说明,否则不该使用
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- effective java(第三版)---读书笔记
第一章 引言 < Effective Java>这本书并不厚,而且并不适合初学者,适合有一定的工作经验的java攻城狮.这本书不是百科全书式的JAVA 手册,而是试图在讲述如何正确.高效地 ...
- C++学习书籍推荐《Effective C++ 第三版》下载
百度云及其他网盘下载地址:点我 编辑推荐 <Effective C++:改善程序与设计的55个具体做法(第3版)(中文版)(双色)>前两个版本抓住了全世界无数程序员的目光.原因十分明显:S ...
- Effective Java 第三版——1. 考虑使用静态工厂方法替代构造方法
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——30. 优先使用泛型方法
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——45. 明智审慎地使用Stream
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
随机推荐
- Confluence 6 使用 Apache 和 mod_proxy 的基本配置
在这些示例中,我们使用下面的信息: http://www.example.com/confluence - 你计划使用的 URL http://example:8090/ - Confluence 当 ...
- 设置 Confluence 6 外部索引站点
Confluence 并不能比较容易的对外部站点进行搜索,这个是因为 Confluence 使用的是 Lucene 内部查找,但是你还是有下面 2 个可选的方案: 嵌入外部页面到 Confluence ...
- Confluence 6 审查日志的对象
审查日志记录一下事件的信息,这个记录不是详细的信息列表.但是这些信息能够让你了解你能够在日志中看到些什么内容. 空间 创建和删除一个空间. 编辑空间细节,主题,配色方案或者样式表. 修改空间权限,包括 ...
- React基础知识备忘
section-1 //react组件 export class Halo extends React.Component{ constructor(...args){ super(...args); ...
- poj2836 状态压缩dp
自己的做法是枚举i,j作为顶点的矩形,然后再更新状态S,但是这种做法是错误的 正解是先把所有矩形对求出来,然后枚举状态S,每个处理每个状态时再枚举已经求出的矩形对,用旧状态更新新状态 #include ...
- hdu4009最小树形图板子题
/*调了一下午的最小树形图,昨天刚刚看懂模板..最小树形图,就是有向图的最小生成树,很神奇==*/ #include<iostream> #include<cstring> # ...
- 2017-2018-2 20165314实验二《Java面向对象程序设计》实验报告
实验报告封面 实验一 实验要求 参考 http://www.cnblogs.com/rocedu/p/6371315.html#SECUNITTEST 完成单元测试的学习提交最后三个JUnit测试用例 ...
- 10进制 VS 2进制
10进制 VS 2进制 时间限制: 1 Sec 内存限制: 32 MB 题目描述 样例输出 623 #include<stdio.h> #include<string.h> ...
- Git使用三:git的使用流程
先创建仓库 创建一个文件夹,作为仓库使用 初始化仓库,在仓库目录的命令行下输入:git init 第一步:创建一个文件,并写入内容,这里写入内容的时候,要把编码设置为utf-8 第二步:输入命令将文件 ...
- vue-cli3.0 使用postcss-plugin-px2rem(推荐)和 postcss-pxtorem(postcss-px2rem)自动转换px为rem 的配置方法;
如何在vue-cli3.0中使用postcss-plugin-px2rem 插件 插件的作用是 自动将vue项目中的px转换为rem . 为什么这三个中要推荐 postcss-plugin-px2r ...