查看原文
其他

这种方式更优雅,秒表计时!

flyhero 码上实战 2023-01-29

你有看过学校百米赛跑时,体育老师手里的秒表吗?老师是怎么记八个跑道中的学生跑了多少时间的呢?


今天我们要做的就是实现老师手中的秒表,但是我们是没有办法同时跑N个任务的,只能一个跑完继续下一个。

许多人统计用时会向下面这样,但方式并不优雅!现在我们来一起实现一个秒表让统计更加优雅吧。

  1. public class Test{


  2. public static void main(String[] args) {

  3. long s = System.currentTimeMillis();

  4. // 算法1

  5. // do something

  6. long s1 = System.currentTimeMillis() - s;

  7. System.out.println("第一段代码执行时间:"+s1);

  8. // 算法2

  9. // do something

  10. long s2 = System.currentTimeMillis() - s1;

  11. System.out.println("第二段代码执行时间:"+s2);

  12. }

  13. }

看完这段代码就问你,烦不烦?

问题所在

那么我们烦在哪里?

1. 每次都要获取获取时间代码

2. 每次都要主动打印

3. 无关紧要的计时打印代码占据了视线

4. 如果n段代码统计对比,需要人工对比或硬编码对比


好了,问题知道了,来想想解决方案吧。

解决方案

1. 封装一个方法代替每次时间相减的代替

2. 将打印最后统一输出

3. 统计每段用时,排序或对比


开始实现我们的秒表类 StopWatch 吧

  • 每段计时任务要有一个唯一标识和一个最终用时

  • 需要一个容器来存储每个计时任务

  • 需要记录总时长和任务数量

具体实现

  • 每个计时任务类


  1. public class Task {

  2. private String name;

  3. private long timeMillis;


  4. public Task(String name, long timeMillis) {

  5. this.name = name;

  6. this.timeMillis = timeMillis;

  7. }

  8. }

  • 秒表类


  1. public class StopWatch {

  2. /*

  3. * 存储执行或的任务容器

  4. */

  5. private List<Task> tasks = new ArrayList<>();

  6. /*

  7. * 当前执行的任务

  8. */

  9. private String currentName;

  10. /*

  11. * 当前任务的开始时间

  12. */

  13. private long startMillis;

  14. /*

  15. * 总用时

  16. */

  17. private long totalMillis;


  18. public StopWatch() {

  19. }

  20. /**

  21. * 开始任务

  22. * @param taskName 任务名

  23. */

  24. public void start(String taskName) {

  25. if (currentName != null){

  26. stop();

  27. }

  28. this.currentName = taskName;

  29. this.startMillis = System.currentTimeMillis();

  30. }

  31. /**

  32. * 停止任务

  33. */

  34. public void stop() {

  35. if (null == currentName) {

  36. throw new RuntimeException("");

  37. }

  38. long spend = System.currentTimeMillis() - startMillis;

  39. totalMillis += spend;

  40. Task task = new Task(currentName, spend);

  41. tasks.add(task);

  42. }


  43. public int size() {

  44. return tasks.size();

  45. }


  46. /**

  47. * 打印结果

  48. */

  49. public void print() {

  50. if (currentName != null){

  51. stop();

  52. }

  53. StringBuilder s = new StringBuilder();

  54. s.append("任务名称\t用时\t占比\t\n");

  55. for (Task task : tasks) {

  56. s.append(task.getName() + "\t");

  57. s.append(task.getTimeMillis() + "\t");

  58. double l = task.getTimeMillis() / (double)totalMillis;

  59. s.append(String.format("%.2f",l) + "\t\n");

  60. }

  61. s.append("总用时:" + totalMillis);

  62. System.out.println(s.toString());

  63. }

  64. }

  • 那么看看现在如何做


  1. public class Test {


  2. public static void main(String[] args){

  3. StopWatch stopWatch = new StopWatch();


  4. stopWatch.start("任务1");

  5. TimeUnit.SECONDS.sleep(1);


  6. stopWatch.start("任务2");

  7. TimeUnit.SECONDS.sleep(2);


  8. stopWatch.print();

  9. }

  10. }

此时我露出了满意的笑容!

最后告诉你个消息:Apache commons , Spring core , Google guava 都给我们实现了稍有不同的StopWatch类!

如果你跟随我一块实现了StopWatch,那去看看这三个提供的,应该 so easy!

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存