有效的 Java - 尽管创建了多个实例,但方法调用时间相同

2023-12-15

我正在学习《Effective Java》,在本书的第 5 条中,Joshua Bloch 谈到了避免创建不必要的对象。一个示例演示了可变的 Date 对象,一旦计算出它们的值就永远不会被修改。

这是“不好的做法”:

public Person(Date birthDate) {
    this.birthDate = new Date(birthDate.getTime());
}

// DON'T DO THIS!
public boolean isBabyBoomer() {
    // Unnecessary allocation of expensive object
    Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
    gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
    Date boomStart = gmtCal.getTime();
    gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
    Date boomEnd = gmtCal.getTime();
    return birthDate.compareTo(boomStart) >= 0
            && birthDate.compareTo(boomEnd) < 0;
}

isBabyBoomer 方法每次调用时都会不必要地创建一个新的 Calendar、TimeZone 和两个 Date 实例 - 这对我来说显然是有意义的。

这是改进的代码:

public Person(Date birthDate) {
    this.birthDate = new Date(birthDate.getTime());
}

/**
 * The starting and ending dates of the baby boom.
 */
private static final Date BOOM_START;
private static final Date BOOM_END;

static {
    Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
    gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
    BOOM_START = gmtCal.getTime();
    gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
    BOOM_END = gmtCal.getTime();
}

public boolean isBabyBoomer() {
    return birthDate.compareTo(BOOM_START) >= 0
            && birthDate.compareTo(BOOM_END) < 0;
}

Calendar、TimeZone 和 Date 实例仅在初始化时创建一次。 Bloch 解释说,如果该方法能够显着提高性能isBabyBoomer()被频繁调用。

在他的机器上:
错误版本:1000 万次调用需要 32,000 毫秒
改进版本:1000万次调用130ms

但是当我在我的系统上运行这些示例时,性能完全相同(14 毫秒)。 这是编译器功能,实例仅创建一次吗?

Edit:
这是我的基准:

    public static void main(String[] args) {
    Calendar cal = Calendar.getInstance();
    cal.set(1960, Calendar.JANUARY, 1, 1, 1, 0);
    Person p = new Person(cal.getTime());
    long startTime = System.nanoTime();
    for (int i = 0; i < 10000000; i++) {
        p.isBabyBoomer();
    }
    long stopTime = System.nanoTime();
    long elapsedTime = stopTime - startTime;
    double mseconds = (double) elapsedTime / 1000000.0;
    System.out.println(mseconds);
}

干杯,马库斯


你的基准是错误的。通过最新的 Java 7 和适当的预热,我发现这两种方法之间存在显着差异:

Person::main: estimatedSeconds 1 = '8,42'
Person::main: estimatedSeconds 2 = '0,01'

这是完整的可运行代码:

import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

public class Person {
    private Date birthDate;
    static Date BOOM_START;
    static Date BOOM_END;

    public Person(Date birthDate) {
        this.birthDate = new Date(birthDate.getTime());
    }

    static {
        Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
        gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
        BOOM_START = gmtCal.getTime();
        gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
        BOOM_END = gmtCal.getTime();
    }

    public boolean isBabyBoomerWrong() {
        // Unnecessary allocation of expensive object
        Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
        gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
        Date boomStart = gmtCal.getTime();
        gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
        Date boomEnd = gmtCal.getTime();
        return birthDate.compareTo(boomStart) >= 0
                && birthDate.compareTo(boomEnd) < 0;
    }

    public boolean isBabyBoomer() {
        return birthDate.compareTo(BOOM_START) >= 0
                && birthDate.compareTo(BOOM_END) < 0;
    }

    public static void main(String[] args) {
        Person p = new Person(new Date());

        for (int i = 0; i < 10_000_000; i++) {
            p.isBabyBoomerWrong();
            p.isBabyBoomer();
        }

        long startTime = System.nanoTime();

        for (int i = 0; i < 10_000_000; i++) {
            p.isBabyBoomerWrong();
        }

        double estimatedSeconds = (System.nanoTime() - startTime) / 1000000000.0;
        System.out.println(String.format("Person::main: estimatedSeconds 1 = '%.2f'", estimatedSeconds));

        startTime = System.nanoTime();

        for (int i = 0; i < 10_000_000; i++) {
            p.isBabyBoomer();
        }

        estimatedSeconds = (System.nanoTime() - startTime) / 1000000000.0;
        System.out.println(String.format("Person::main: estimatedSeconds 2 = '%.2f'", estimatedSeconds));

    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

有效的 Java - 尽管创建了多个实例,但方法调用时间相同 的相关文章

  • Mockito:如何通过模拟测试我的服务?

    我是模拟测试新手 我想测试我的服务方法CorrectionService correctPerson Long personId 实现尚未编写 但这就是它将执行的操作 CorrectionService将调用一个方法AddressDAO这将
  • 在内存中使用 byte[] 创建 zip 文件。 Zip 文件总是损坏

    我创建的 zip 文件有问题 我正在使用 Java 7 我尝试从字节数组创建一个 zip 文件 其中包含两个或多个 Excel 文件 应用程序始终完成 没有任何异常 所以 我以为一切都好 当我尝试打开 zip 文件后 Windows 7 出
  • 使用 LinkedList 实现下一个和上一个按钮

    这可能是一个愚蠢的问题 但我很难思考清楚 我编写了一个使用 LinkedList 来移动加载的 MIDI 乐器的方法 我想制作一个下一个和一个上一个按钮 以便每次单击该按钮时都会遍历 LinkedList 如果我硬编码itr next or
  • jQuery AJAX 调用 Java 方法

    使用 jQuery AJAX 我们可以调用特定的 JAVA 方法 例如从 Action 类 该 Java 方法返回的数据将用于填充一些 HTML 代码 请告诉我是否可以使用 jQuery 轻松完成此操作 就像在 DWR 中一样 此外 对于
  • 在 Jar 文件中运行 ANT build.xml 文件

    我需要使用存储在 jar 文件中的 build xml 文件运行 ANT 构建 该 jar 文件在类路径中可用 是否可以在不分解 jar 文件并将 build xml 保存到本地目录的情况下做到这一点 如果是的话我该怎么办呢 Update
  • 谷歌应用程序引擎会话

    什么是java应用程序引擎 默认会话超时 如果我们将会话超时设置为非常非常长的时间 会不会产生不良影响 因为谷歌应用程序引擎会话默认情况下仅存储在数据存储中 就像facebook一样 每次访问该页面时 会话仍然永远存在 默认会话超时设置为
  • 如何知道Matlab中系统命令执行过程中经过的时间?

    我有一个运行系统脚本的 Matlab 代码 该脚本可能会因命令运行而停止 我想知道是否有一种方法可以让程序知道它是否花费了很长时间并执行其他操作 这是代码 tic status cmdout system iperfcmd The prog
  • 检测并缩短字符串中的所有网址

    假设我有一条字符串消息 您应该将 file zip 上传到http google com extremelylonglink zip http google com extremelylonglink zip not https stack
  • 在 junit 测试中获取 javax.lang.model.element.Element 类

    我想测试我的实用程序类 ElementUtils 但我不知道如何将类作为元素获取 在 AnnotationProcessors 中 我使用以下代码获取元素 Set
  • 帮助将图像从 Servlet 获取到 JSP 页面 [重复]

    这个问题在这里已经有答案了 我目前必须生成一个显示字符串文本的图像 我需要在 Servlet 上制作此图像 然后以某种方式将图像传递到 JSP 页面 以便它可以显示它 我试图避免保存图像 而是以某种方式将图像流式传输到 JSP 自从我开始寻
  • 如何在用户输入数据后重新运行java代码

    嘿 我有一个基本的java 应用程序 显示人们是成年人还是青少年等 我从java开始 在用户输入年龄和字符串后我找不到如何制作它它们被归类为 我希望它重新运行整个过程 以便其他人可以尝试 的节目 我一直在考虑做一个循环 但这对我来说没有用
  • Spring Boot Data JPA 从存储过程接收多个输出参数

    我尝试通过 Spring Boot Data JPA v2 2 6 调用具有多个输出参数的存储过程 但收到错误 DEBUG http nio 8080 exec 1 org hibernate engine jdbc spi SqlStat
  • tomcat 中受密码保护的应用程序

    我正在使用 JSP Servlet 开发一个Web应用程序 并且我使用了Tomcat 7 0 33 as a web container 所以我的要求是tomcat中的每个应用程序都会password像受保护的manager applica
  • 如何在谷歌地图android上显示多个标记

    我想在谷歌地图android上显示带有多个标记的位置 问题是当我运行我的应用程序时 它只显示一个位置 标记 这是我的代码 public class koordinatTask extends AsyncTask
  • 计算 Richtextbox 中所有单词的最有效方法是什么?

    我正在编写一个文本编辑器 需要提供实时字数统计 现在我正在使用这个扩展方法 public static int WordCount this string s s s TrimEnd if String IsNullOrEmpty s re
  • Eclipse 选项卡宽度不变

    我浏览了一些与此相关的帖子 但它们似乎并不能帮助我解决我的问题 我有一个项目 其中 java 文件以 2 个空格的宽度缩进 我想将所有内容更改为 4 空格宽度 我尝试了 正确的缩进 选项 但当我将几行修改为 4 空格缩进时 它只是将所有内容
  • Android:无法使用 DbHelper 和 Contract 类将数据插入 SQLite

    public class Main2Activity extends AppCompatActivity private EditText editText1 editText2 editText3 editText4 private Bu
  • 我如何在java中读取二进制数据文件

    因此 我正在为学校做一个项目 我需要读取二进制数据文件并使用它来生成角色的统计数据 例如力量和智慧 它的设置是让前 8 位组成一个统计数据 我想知道执行此操作的实际语法是什么 是不是就像读文本文件一样 这样 File file new Fi
  • 如何将双精度/浮点四舍五入为二进制精度?

    我正在编写对浮点数执行计算的代码的测试 不出所料 结果很少是准确的 我想在计算结果和预期结果之间设置一个容差 我已经证实 在实践中 使用双精度 在对最后两位有效小数进行四舍五入后 结果始终是正确的 但是usually四舍五入最后一位小数后
  • 双枢轴快速排序和快速排序有什么区别?

    我以前从未见过双枢轴快速排序 是快速排序的升级版吗 双枢轴快速排序和快速排序有什么区别 我在 Java 文档中找到了这个 排序算法是双枢轴快速排序 作者 弗拉基米尔 雅罗斯拉夫斯基 乔恩 本特利和约书亚 布洛赫 这个算法 在许多数据集上提供

随机推荐

  • 将 MemoryStream 写入响应对象

    我正在使用以下代码来传输 MemoryStream 对象中的 pptx 但是当我打开它时 我在 PowerPoint 中收到修复消息 将 MemoryStream 写入响应对象的正确方法是什么 HttpResponse response H
  • 根据日期和时区计算 tm_isdst

    当我运行线路时 time strptime 2012 06 01 12 00 00 time strftime Z Y m d H M S Z 它为我创建了一个结构 但标志tm isdst是错的 六月初 DST 已生效 但无论我在哪一天输入
  • 如何在Access表中插入列描述?

    如何使用 SQL 在 Access 表中插入列的描述 I do CREATE TABLE TAB A COLUMN1 TEXT 30 COLUMN2 REAL PRIMARY KEY COLUMN1 但如何为每列插入描述 你不能用 SQL
  • 我的不和谐机器人代码正在运行,但没有响应我的命令[重复]

    这个问题在这里已经有答案了 我是一名编程大三学生 我了解 Node js 并且想编写自己的 Discord 机器人 我下面写的代码不起作用 你能帮我解决这个问题吗 const Client Intents require discord j
  • Powershell 在空文件夹上比较对象

    我正在编写一个简单的 DLL 复制脚本来帮助我的开发团队设置他们的本地环境 我检查 build devdrop 文件夹并获取 DLL 文件列表 然后 我查看本地文件夹并复制所有较新的 DLL 我的问题是当本地文件夹为空时 即脚本第一次运行
  • Scala Akka HTTP 转换参数为 java.time.ZonedDateTime

    我正在使用 Akka HTTP 在 Scala 中 开发 REST 服务 我希望将传入 http get 请求的参数转换为 ZonedDateTime 类型 如果我尝试使用 String 或 Int 但使用 ZonedDateTime 类型
  • 从 NetworkStream 读取特定数量的字节

    我正在尝试从网络流中读取已知长度的消息 我有点期待NetworkStream Read 将等待返回 直到我给它的缓冲区数组已满 如果不是 那么这样做的意义何在 ReadTimeout财产 我用来测试我的理论的示例代码 public stat
  • Haskell 打印字符串标准输出

    我需要打印 powerset 中的元素 现在我的代码的输出是这样的 a ab b x xy xyz xz y yz z 但是 我需要输出不带引号 如下所示 a ab b x xy xyz xz y yz z 这就是我所拥有的 我该如何修复它
  • Rails:如何在 Heroku 上使用系统 zip 从 xml 模板制作 docx?

    我在本地工作 将模板文件存储在 Rails root tmp using system cd tmp template zip r filename 压缩文件 将 docx zip 存档 发送到 S3 然后发送到浏览器 问题是 Heroku
  • 页眉/页脚终端显示[重复]

    这个问题在这里已经有答案了 如何创建一个包含静态页眉和页脚的 python 脚本 如下图所示 您可以使用curses对于蟒蛇 例子 import curses myscreen curses initscr curses start col
  • 从 ASP.Net MVC Ajax 请求服务器重定向到新页面

    我正在尝试使用另一个控制器调用方法RedirectToAction 但这不起作用 你能解释一下我做错了什么吗 HttpPost public ActionResult AddToWishList int id bool check var
  • JS 对象中的键(字符串)长度有限制吗?

    因此 我们有一个对象 其中键是 id int 值是字符串 但我们注意到 大多数时候 我们是根据字符串来查找 id 的 所以我们决定反转它 让字符串作为键 值作为 id 因为这样我们就不用遍历每个项目并比较值 而是可以这样做var id st
  • iOS 调试构建安装失败

    我有一个 CN1 测试项目 最后一次构建并成功安装在各种测试设备上是在 2017 年 1 月中旬 在使用具有相同证书 配置文件和设备的当前 CN1 版本重建此项目时 它现在无法安装 并显示 无法下载应用程序 此时无法安装 信息 关于可能出现
  • 使用 WebView Xamarin 表单加载本地 HTML

    我正在尝试使用 Xamarin 表单在 Web 视图中加载本地 HTML 页面 我正在使用开发文档中的基本示例 尽管我可以获取要加载的 URL 但无法加载我自己的 HTML 页面 只需要通过 Android 即可完成此操作 因此无需担心 I
  • 附加 .mdf 文件时数据库“无法打开,因为它是版本 661”

    我正在尝试将 MvcMusicStore mdf 附加到 sql server 2008 R2 Management Studio 中的 SQLEXPRESS 实例 sql server 版本 10 0 2531 我从这个项目中得到了数据库
  • 滚动笔记本选项卡 Tkinter

    我想制作很多笔记本选项卡 我想将它们放在画布中并添加水平滚动条 以便我可以滚动它们 我设置了画布大小 但当我添加新选项卡时画布大小不断变化 另外 滚动条不起作用 你能告诉我我做错了什么吗 该程序没有向我显示任何错误 这是代码 from tk
  • .ajaxform 不在验证提交处理程序内工作?

    我在提交之前使用 jquery 验证插件来验证表单 在submitHandler中我使用ajax请求通过ajax发布表单 在我使用 ajax 发送请求之前 但现在表单有图像 而且很难 通过普通的ajax请求序列化文件元素 因此我使用了这个插
  • 子集和的动态规划方法

    给定以下输入 10 4 3 5 5 7 Where 10 Total Score 4 4 players 3 Score by player 1 5 Score by player 2 5 Score by player 3 7 Score
  • java.lang.ClassNotFoundException:org.apache.xmlbeans.XmlOptions

    我正在尝试在 servlet 中使用 POI 将上传的文件处理为 Excel 文件 public static String readExcel InputStream inp InputStream inp null StringBuil
  • 有效的 Java - 尽管创建了多个实例,但方法调用时间相同

    我正在学习 Effective Java 在本书的第 5 条中 Joshua Bloch 谈到了避免创建不必要的对象 一个示例演示了可变的 Date 对象 一旦计算出它们的值就永远不会被修改 这是 不好的做法 public Person D