美文网首页
Effective Java(3rd)-Item59 知道并使用

Effective Java(3rd)-Item59 知道并使用

作者: 难以置信的优雅 | 来源:发表于2018-09-18 15:03 被阅读0次

      假设您想要生成0到某个上界之间的随机整数。面对这个共同的任务,许多程序员会编写一个类似这样的小方法:


    image.png

      这个方法看起来不错,但它有三个缺点。首先,如果n是2的小次方,随机数序列会在相当短的时间内重复。第二个缺陷是,如果n不是2的幂,那么平均而言,一些数字将比其他数字更频繁地返回。如果n很大,这种效果会很明显。下面的程序有力地证明了这一点,它在一个精心选择的范围内生成100万个随机数,然后打印出有多少个数字落在范围的下半部分:


    image.png

      如果随机方法工作正常,程序将输出一个接近50万的数字,但是如果运行它,您将发现它输出一个接近666666的数字。随机方法生成的数字中有三分之二落在其范围的下半部分!
      随机方法的第三个缺陷是,在极少数情况下,它可能会灾难性地失败,返回超出指定范围的数字。这是因为该方法试图通过调用Math.abs将rnd.nextInt()返回的值映射到非负整数。如果nextInt()返回Interger.MIN_VALUE,Math.abs也会返回Integer.MIN_VALUE,而余数运算符(%)将返回一个负数,假设n不是2的幂。这几乎肯定会导致您的程序失败,并且这种失败可能难以重现。
      要编写一个版本的随机方法来纠正这些缺陷,你必须知道伪随机数生成器,数论,2的补数运算的知识。幸运的是,你不必这样做——这已经为你做过了。它被称为Random.nextInt (int)。您不必关心它如何工作的细节(尽管如果您感兴趣,可以研究文档或源代码)。一位具有算法背景的高级工程师花了大量时间设计、实现和测试这种方法,然后将其展示给该领域的几位专家,以确保它是正确的。然后,这个库经过beta测试、发布,并被数百万程序员广泛使用了近20年。该方法还没有发现任何缺陷,但是如果发现了缺陷,将在下一个版本中进行修复。通过使用标准库,您可以利用编写它的专家的知识和以前使用它的人的经验。
      从Java 7开始,就不应该再使用Random。对于大多数用途,现在选择的随机数生成器是ThreadLocalRandom。它能产生更高质量的随机数,而且速度非常快。在我的机器上,它比Random快3.6倍。对于fork连接池和并行流,使用SplittableRandom。
      使用这些库的第二个好处是,您不必浪费时间为那些与您的工作无关的问题编写专门的解决方案。如果您像大多数程序员一样,那么您宁愿将时间花在应用程序上,而不是底层管道上。
      使用标准库的第三个优点是,随着时间的推移,它们的性能会不断提高,而您无需付出任何努力。由于许多人使用它们,而且它们是在行业标准基准中使用的,所以提供这些库的组织有很强的动机使它们运行得更快。多年来,许多Java平台库都被重新编写过,有时甚至是重复编写,从而带来了显著的性能改进。
      使用库的第四个好处是,随着时间的推移,它们往往会获得功能。如果一个库丢失了一些东西,开发人员社区会将其公布于众,并且丢失的功能可能会在后续版本中添加。
      使用标准库的最后一个好处是,可以将代码放在主流中。这样的代码更容易被开发人员阅读、维护和重用。
      考虑到所有这些优点,使用库工具而不是特殊实现似乎是合乎逻辑的,但许多程序员并不这样做。为什么不呢?也许他们不知道库设施的存在。在每个主要版本中,都会向库中添加许多特性,了解这些新增特性是值得的。每次有Java平台的主要版本发布时,都会发布一个web页面来描述它的新特性。这些页面非常值得一读[Java8-feat, Java9-feat]。为了加强这一点,假设你想写程序打印在命令行上指定的URL的内容(这大致是Linux curl命令所做的)。在Java 9之前,这段代码有点乏味,但是在Java 9中,transferTo方法被添加到InputStream中。这里是一个完整的程序来执行这项任务使用这个新方法:

    image.png

      库太大,无法学习所有文档[Java9-api],但是每个程序员都应该熟悉java的基础包如java.lang, java.util, java.io和它们的子包。可以根据需要获得其他库的知识。概述库的设施超出了本项目的范围,这些设施多年来已经发展得非常庞大。
      有几个库值得一提。collections 框架和streams库(项目45-48)应该是每个程序员基本工具包的一部分,java.util.concurrent中的部分并发实用程序也应该如此。这个包包含简化多线程编程任务的高级实用程序和允许专家编写自己的高级并发抽象的低级原语。 java.util.concurrent 高级部分在项目80和81中讨论。
      有时,库设施可能无法满足您的需求。您的需求越专门化,发生这种情况的可能性就越大。虽然您的第一个冲动应该是使用这些库,但是如果您已经了解了它们在某些领域提供的功能,而这些功能不能满足您的需求,那么可以使用另一种实现。任何有限的库集所提供的功能总是存在漏洞。如果你在Java平台库中找不到你需要的东西,你的下一个选择应该是寻找高质量的第三方库,比如谷歌的优秀的开源Guava库[Guava]。如果您无法在任何适当的库中找到所需的功能,您可能别无选择,只能自己实现它。
      总之,不要重复造轮子。如果您需要做一些看起来相当常见的事情,那么库中可能已经有一个工具可以做您想做的事情。如果有,使用它;如果你不知道,检查一下。一般来说,库代码可能比您自己编写的代码更好,并且随着时间的推移可能会得到改进。这并不反映你作为一个程序员的能力。规模经济决定了库代码得到的关注要远远超过大多数开发人员所能承担的相同功能。
    本文写于2019.7.18,历时1天

    相关文章

      网友评论

          本文标题:Effective Java(3rd)-Item59 知道并使用

          本文链接:https://www.haomeiwen.com/subject/qvtpnftx.html