Java计时新姿势

为获得更好的阅读体验,请访问原文:传送门
前言: 最近公司来了个大佬,从他那里学到不少东西,其中一个就是计时
的新姿势「StopWatch」,赶紧来一起了解了解吧!

一、最简单的计时



在我们的程序中不免需要对某一个运算或者方法进行计时,以便我们来观察该运算或方法是否符合我们的预期,所以在我们刚开始接触 Java 的时候都能写出类似下面这样的代码来计时:

public static void main(String[] args) {
    Long startTime = System.currentTimeMillis();

    doSomeThing();

    Long endTime = System.currentTimeMillis();
    Long elapsedTime = (endTime - startTime) / 1000;
    System.out.println("总共耗时:" + elapsedTime + "s");
}
// 用于模拟一些操作
private static void doSomeThing()  {
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

事实上这样也并没有什么问题,并且也能够运行的很好,但是有一点不太好的就是,自己关注了太多输出的信息,下面我们来认识一种更优雅的一种计时方式;

二、StopWatch 类



想要使用它,首先你需要在你的 Maven 中引入 Spring 核心包,当然 Spring MVC 和 Spring Boot 都已经自动引入了该包:

<!-- spring核心包 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>${spring.version}</version>
</dependency>

现在我们计时的姿势或许就会变成以下这样:

public static void main(String[] args) {
    StopWatch clock = new StopWatch();

    clock.start("开始任务一");
    doSomeThing();
    clock.stop();

    clock.start("开始任务二");
    doSomeThing();
    clock.stop();

    System.out.println(clock.prettyPrint());
}

// 用于模拟一些操作
private static void doSomeThing() {
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

在最后我们使用 StopWatch 类自带的 prettyPrint() 方法类格式化我们的输出,运行程序你会发现你的程序输出了这样的东西:

StopWatch '': running time (millis) = 2009
-----------------------------------------
ms     %     Task name
-----------------------------------------
01005  050%  开始任务一
01004  050%  开始任务二

不仅有总用时,还有每个任务分别的占用时间和占用时间的百分比,这或许就会比我们自己输出要优雅那么一些;

StopWatch 类是怎么实现的呢?

当你戳开 StopWatch 的源码,你会在总共不到 200 行的代码里看到熟悉的东西:

    public void start(String taskName) throws IllegalStateException {
        if (this.currentTaskName != null) {
            throw new IllegalStateException("Can't start StopWatch: it's already running");
        } else {
            this.currentTaskName = taskName;
            this.startTimeMillis = System.currentTimeMillis();
        }
    }

    public void stop() throws IllegalStateException {
        if (this.currentTaskName == null) {
            throw new IllegalStateException("Can't stop StopWatch: it's not running");
        } else {
            long lastTime = System.currentTimeMillis() - this.startTimeMillis;
            this.totalTimeMillis += lastTime;
            this.lastTaskInfo = new StopWatch.TaskInfo(this.currentTaskName, lastTime);
            if (this.keepTaskList) {
                this.taskList.add(this.lastTaskInfo);
            }

            ++this.taskCount;
            this.currentTaskName = null;
        }
    }

你会发现该类使用 LinkedList 实现了一个叫做 taskList 的队列,然后每一次开始同样也是使用 System.currentTimeMillis() 方法来获取时间,每次除了计算耗时也会构建一个描述当前任务的 TaskInfo 对象,并把它放入 taskList 队列中。

当执行 prettyPrint() 方法的时候,就从 taskList 队列中依次取出任务,然后做些格式化的操作:

    public String shortSummary() {
        return "StopWatch '" + this.getId() + "': running time (millis) = " + this.getTotalTimeMillis();
    }

    public String prettyPrint() {
        StringBuilder sb = new StringBuilder(this.shortSummary());
        sb.append('\n');
        if (!this.keepTaskList) {
            sb.append("No task info kept");
        } else {
            sb.append("-----------------------------------------\n");
            sb.append("ms     %     Task name\n");
            sb.append("-----------------------------------------\n");
            NumberFormat nf = NumberFormat.getNumberInstance();
            nf.setMinimumIntegerDigits(5);
            nf.setGroupingUsed(false);
            NumberFormat pf = NumberFormat.getPercentInstance();
            pf.setMinimumIntegerDigits(3);
            pf.setGroupingUsed(false);
            StopWatch.TaskInfo[] var4 = this.getTaskInfo();
            int var5 = var4.length;

            for(int var6 = 0; var6 < var5; ++var6) {
                StopWatch.TaskInfo task = var4[var6];
                sb.append(nf.format(task.getTimeMillis())).append("  ");
                sb.append(pf.format(task.getTimeSeconds() / this.getTotalTimeSeconds())).append("  ");
                sb.append(task.getTaskName()).append("\n");
            }
        }

        return sb.toString();
    }

摁,新姿势 get √。



按照惯例黏一个尾巴:

欢迎转载,转载请注明出处!
独立域名博客:wmyskxz.com
简书ID:@我没有三颗心脏
github:wmyskxz
欢迎关注公众微信号:wmyskxz
分享自己的学习 & 学习资料 & 生活
想要交流的朋友也可以加qq群:3382693

原文地址:https://www.cnblogs.com/wmyskxz/p/11273490.html

时间: 2024-11-13 10:02:35

Java计时新姿势的相关文章

Java 8新特性之旅:使用Stream API处理集合

在这篇“Java 8新特性教程”系列文章中,我们会深入解释,并通过代码来展示,如何通过流来遍历集合,如何从集合和数组来创建流,以及怎么聚合流的值. 在之前的文章“遍历.过滤.处理集合及使用Lambda表达式增强方法”中,我已经深入解释并演示了通过lambda表达式和方法引用来遍历集合,使用predicate接口来过滤集合,实现接口的默认方法,最后还演示了接口静态方法的实现. 源代码都在我的Github上:可以从 这里克隆. 内容列表 使用流来遍历集合. 从集合或数组创建流. 聚合流中的值. 1.

Android实战——RxJava2+Retrofit+RxBinding解锁各种新姿势

RxJava2+Retrofit+RxBinding解锁各种新姿势 本篇文章内容包含以下内容 前言 RxJava2的基本介绍 RxJava2观察者模式的介绍 RxJava2观察者模式的使用 RxJava2的基本使用 模拟发送验证码 RxJava2与Retrofit的使用 模拟用户登陆获取用户数据 合并本地与服务器购物车列表 RxJava2与RxBinding的使用 优化搜索请求 优化点击请求 源码下载 结语 前言 作为主流的第三方框架Rx系列,不学习也不行啊,对于初学者来说,可能RxJava看起

网秦Q3财报现新姿势 老司机发力移动娱乐竟成网红

文/张书乐 日前,网秦公布了截至2016年9月30日的第三季度未经审计财务业绩.移动增值服务以同比增长74.6%至5,490万美元的成绩成为网秦营收贡献的最大板块. 老司机网秦作为国内最老牌的移动互联网"巨鳄"之一,竟然依靠移动娱乐实现了全面转型,而且网秦首席执行官许泽民更表示:"我们对移动娱乐业务领域取得的持续进展感到满意,随着2016年进入最后一个季度,我们会继续专注于执行我们的战略." 真的简单就是一个战略而已?网秦怎么就突然成了"网红"呢

Java 5/Java 6/Java7/Java 8新特性收集

前言: Java 8对应的JDK版本为JDK8,而官网下载回来安装的时候,文件夹上写的是JDK1.8,同一个意思.(而这个版本命名也是有规律的,以此类推) 一.Java 5 1.https://segmentfault.com/a/1190000004417288 二.Java 6 2.https://segmentfault.com/a/1190000004417536 三.Java 7 1.http://www.eclipse.org/jdt/ui/r3_8/Java7news/whats-

Java 8新特性

现在,是时候把所有Java8的重要特性收集整理成一篇单独的文章了,希望这篇文章能给你带来阅读上的乐趣.开始吧! 目录结构 介绍 Java语言的新特性 2.1 Lambdas表达式与Functional接口 2.2 接口的默认与静态方法 2.3 方法引用 2.4 重复注解 2.5 更好的类型推测机制 2.6 扩展注解的支持 Java编译器的新特性 3.1 参数名字 Java 类库的新特性 4.1 Optional 4.2 Streams 4.3 Date/Time API (JSR 310) 4.

bzoj1656: [Usaco2006 Jan] The Grove 树木 (bfs+新姿势)

题目大意:一个n*m的图中,“.”可走,“X”不可走,“*”为起点,问从起点开始绕所有X一圈回到起点最少需要走多少步. 一开始看到这题,自己脑洞了下怎么写,应该是可过,然后跑去看了题解,又学会了一个新姿势... 上图是样例,红色笔迹是走法,需要走13步. 这显然是bfs题,问题是怎么让bfs绕这坨东西一圈,非常巧妙的思路,从任意一个X节点画一条射线与边界垂直,如下图所示. 当我们从右向左bfs的时候碰到这条线,就停止bfs:当我们绕了一圈从左向右bfs的时候碰到这条线,我们就继续走. dist[

Java 8 新特性1-函数式接口

Java 8 新特性1-函数式接口 (原) Lambda表达式基本结构: (param1,param2,param3) -> {代码块} 例1: package com.demo.jdk8; import java.util.Arrays; import java.util.List; import java.util.function.Consumer; public class Test2 { public static void main(String[] args) { for_test

Java 5/Java 6/Java7/Java 8新特性收集(转载)

Java 8对应的JDK版本为JDK8,而官网下载回来安装的时候,文件夹上写的是JDK1.8,同一个意思.(而这个版本命名也是有规律的,以此类推) 一.Java 5 1.https://segmentfault.com/a/1190000004417288 二.Java 6 2.https://segmentfault.com/a/1190000004417536 三.Java 7 1.http://www.eclipse.org/jdt/ui/r3_8/Java7news/whats-new-

Java 8新特性终极指南

目录结构 介绍 Java语言的新特性 2.1 Lambdas表达式与Functional接口 2.2 接口的默认与静态方法 2.3 方法引用 2.4 重复注解 2.5 更好的类型推测机制 2.6 扩展注解的支持 Java编译器的新特性 3.1 参数名字 Java 类库的新特性 4.1 Optional 4.2 Streams 4.3 Date/Time API (JSR 310) 4.4 JavaScript引擎Nashorn 4.5 Base64 4.6 并行(parallel)数组 4.7