JDK 1.8(Java 8)里新增String.join()方法用于字符串连接。本文基于《Java实现String.join()和效率比较》一文,分析和比较四种自定义实现与String.join()方法的效率,并纠正原文的一些错误。

代码示例如下:

  1. public class Test {
  2. public static void main(String[] args) {
  3. String[] strOri = {"a","b","c","d","e","f","g","h"}; //同new string[]{"a","b","c","d","e","f","g","h"}
  4. String strRes = ""; int loops = 100000;
  5.  
  6. Date date = new Date();
  7.  
  8. for(int i = 0; i < loops; i++) {strRes = join1(strOri, ":");} date = recordTime(date, 1); //
  9. for(int i = 0; i < loops; i++) {strRes = join2(strOri, ":");} date = recordTime(date, 2);
  10. for(int i = 0; i < loops; i++) {strRes = join3(strOri, ":");} date = recordTime(date, 3);
  11. for(int i = 0; i < loops; i++) {strRes = join4(strOri, ":");} date = recordTime(date, 4);
  12. for(int i = 0; i < loops; i++) {strRes = join5(strOri, ":");} date = recordTime(date, 5);
  13.  
  14. long startTime = System.currentTimeMillis(); //
  15. for(int i = 0; i < loops; i++) {strRes = join5(strOri, ":");}
  16. long endTime = System.currentTimeMillis(); System.out.println("5c:{" + strRes + "} costs " + (endTime-startTime) + "ms");
  17.  
  18. startTime = System.nanoTime();
  19. for(int i = 0; i < loops; i++) {strRes = join5(strOri, ":");}
  20. endTime = System.nanoTime(); System.out.println("5n:{" + strRes + "} costs " + (endTime-startTime) + "ns");
  21. }
  22.  
  23. private static void recordTime_Wrong(Date date, int no) {
  24. System.out.println(no + ": costs " + (new Date().getTime()-date.getTime()) + "ms");
  25. date = new Date();
  26. }
  27. private static Date recordTime(Date date, int no) {
  28. System.out.println(no + ": costs " + (new Date().getTime()-date.getTime()) + "ms");
  29. return new Date();
  30. }
  31.  
  32. private static String join1(String[] strOri, String delimiter) {
  33. StringBuffer sb = new StringBuffer(); //
  34. for(String s : strOri) {
  35. sb.append(s+delimiter); //
  36. }
  37. return sb.toString().substring(0, sb.toString().length()-1);
  38. }
  39.  
  40. private static String join2(String[] strOri, String delimiter) {
  41. StringBuffer sb = new StringBuffer();
  42. for(String s : strOri) {
  43. sb.append(s+delimiter);
  44. }
  45. String s = sb.toString();
  46. return s.substring(0, s.length()-1);
  47. }
  48.  
  49. private static String join3(String[] strOri, String delimiter) {
  50. StringBuffer sb = new StringBuffer();
  51. for(int i = 0; i < strOri.length; i++) {
  52. if (i != strOri.length-1) {
  53. sb.append(strOri[i]+delimiter);
  54. } else {
  55. sb.append(strOri[i]);
  56. }
  57. }
  58. return sb.toString();
  59. }
  60.  
  61. private static String join4(String[] strOri, String delimiter) {
  62. StringBuilder stringBuilder = new StringBuilder();
  63. for (int i = 0; i < strOri.length-1; i++) {
  64. stringBuilder.append(strOri[i]).append(delimiter);
  65. }
  66. stringBuilder.append(strOri[strOri.length-1]);
  67. return stringBuilder.toString();
  68. }
  69.  
  70. private static String join5(String[] strOri, String delimiter) {
  71. return String.join(delimiter, strOri); //
  72. }
  73. }

选取三次运行输出结果如下:

  1. 1: costs 930ms
  2. 2: costs 902ms
  3. 3: costs 637ms
  4. 4: costs 230ms
  5. 5: costs 364ms
  6. 5c:{a:b:c:d:e:f:g:h} costs 413ms
  7. 5n:{a:b:c:d:e:f:g:h} costs 286466296ns
  1. 1: costs 834ms
  2. 2: costs 788ms
  3. 3: costs 576ms
  4. 4: costs 248ms
  5. 5: costs 350ms
  6. 5c:{a:b:c:d:e:f:g:h} costs 384ms
  7. 5n:{a:b:c:d:e:f:g:h} costs 283256112ns
  1. 1: costs 774ms
  2. 2: costs 728ms
  3. 3: costs 605ms
  4. 4: costs 297ms
  5. 5: costs 417ms
  6. 5c:{a:b:c:d:e:f:g:h} costs 280ms
  7. 5n:{a:b:c:d:e:f:g:h} costs 279838638ns

可见,join4()执行最快,其次是join5()。join1()和join2()执行效率接近,前者调用两次toString(),故效率略低。

总结如下:
    1. 原文recordTime(即本文recordTime_Wrong)方法中,无法通过"date = new Date()"修改外部的date引用(根因详见《java中的传值与传引用》)。这会导致每次调用recordTime()时,起始时间始终是"Date date = new Date()"获得的对象(表现为join*耗时递增)。
    2. 查看Java源码可知,new Date()其实就是调用System.currentTimeMillis():

  1. public Date() {
  2. this(System.currentTimeMillis()); //相当于Date(System.currentTimeMillis())
  3. }

可以使用new Date().getTime()获取当前时间戳(毫秒)。注意,该毫秒数一般以1970-01-01 00:00:00为参考点,但东八区要加上时区,即以1970-01-01 08:00:00为参考时间。此外,通过getTime()获取毫秒数效率不如System.currentTimeMillis(),后者返回自1970年1月1日0时起的毫秒数。

System.nanoTime()的计时精度不保证一定高于System.currentTimeMillis(),但可保证数值递增(后者相减时可能产生负值)。

若要对代码进行更准确的计时,可参考《How do I write a correct micro-benchmark in Java?》一文。
    3. StringBuffer对象是线程安全的,其方法都是同步的(synchronized)。临时变量应使用StringBuilder(效率更高),避用StringBuffer。
    4. 在循环内部,不要使用append(a+b)的形式,而应改为append(a).append(b)。
    5. String.join()内部使用StringBuilder实现,因此join5()性能接近join4()。当然,String.join()的功能比join4()更多。

Java字符串连接的多种实现方法及效率对比的更多相关文章

  1. python字符串连接的三种方法及其效率、适用场景详解

    python字符串连接的方法,一般有以下三种:方法1:直接通过加号(+)操作符连接website=& 39;python& 39;+& 39;tab& 39;+& ...

  2. Java字符串比较(3种方法)以及对比 C++ 时的注意项

    字符串比较是常见的操作,包括比较相等.比较大小.比较前缀和后缀串等.在 Java 中,比较字符串的常用方法有 3 个:equals() 方法.equalsIgnoreCase() 方法. compar ...

  3. Python字符串连接的5种方法

    总结了一下Python字符串连接的5种方法: 加号 第一种,有编程经验的人,估计都知道很多语言里面是用加号连接两个字符串,Python里面也是如此直接用 "+" 来连接两个字符串: ...

  4. java字符串格式化:String.format()方法的使用

    转自:http://kgd1120.iteye.com/blog/1293633 常规类型的格式化 String类的format()方法用于创建格式化的字符串以及连接多个字符串对象.熟悉C语言的读者应 ...

  5. Java字符串连接操作的性能问题

    首先,看一段实验程序: package com.test; class StringTest { public static void main(String[] args) { long start ...

  6. C#三种字符串拼接方法的效率对比

    C#字符串拼接的方法常用的有:StringBuilder.+.string.Format.List<string>.使用情况不同,效率不同. 1.+的方式 string sql = &qu ...

  7. Java字符串连接最佳实践

    一个小问题,分享给大家. + 操作和 StringBuilder 都能连接字符串,使用+来拼接字符串,使用javap命令来反编译代码,可以看出实际上编译器会自动创建StringBuilder,调用它的 ...

  8. 理解Java字符串常量池与intern()方法

    String s1 = "Hello"; String s2 = "Hello"; String s3 = "Hel" + "lo ...

  9. Java字符串的split(String str)方法空串的问题

    String strs[] = "SS1BB2CC3".split("\\D+"); public static String Test(){ Date d = ...

随机推荐

  1. c# js 删除table原行数据

    function addtreetotable(obj){ var table1 =  document.getElementById("Table1"); var hang =  ...

  2. weblogic 下异常 org.hibernate.QueryException: ClassNotFoundException: org.hibernate.hql.ast.HqlToken

    项目之前在 Tomcat 环境下一直都正常运行,今天应客户要求需要迁移到 webLogic 10.3.6 下, 部署后竟然抛出了 org.hibernate.QueryException: Class ...

  3. Linux进程管理学习资料

    下面是一些Linux进程管理相关的资料. 博客 Process Creation(一) Process Creation(二) 进程切换分析(1):基本框架 进程切换分析(2):TLB处理 When ...

  4. 近期 Unity 提交苹果审核被拒的问题

    游戏提交苹果审核,被打回.在 bugly 上没有查到崩溃信息,苹果给了 crash 日志也说明. 拒绝原因如下: Your app crashed on iPad or iPhone running ...

  5. Glide4 用法总结 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  6. MFC中使用ATL报错:error C4430: missing type specifier - int assumed. Note: C++ does not support default-int

    我在MFC中使用ATL函数A2W的时候报如下的错误: error C4430: missing type specifier - int assumed. Note: C++ does not sup ...

  7. 修改MySql数据库的默认时

    MySql数据库创建后,默认的时区比东八区少了八个小时.如果Sql语句中使用到MySql的时间的话就会比正常时间少了八个小时.所以需要修改MySql的系统时区,使其显示的时间和我们现在的时间一致. 1 ...

  8. Exception thrown on Scheduler.Worker thread. Add `onError` handling

    <html> <head></head> <body> java.lang.IllegalStateException: Exception throw ...

  9. VS2015 ionic 开发环境配置纪要

    1)第一次安装Tools for Apache Cordova不成功,到Options检查依赖项,缺少Node等,重新下载了32为的nodeJs安装.然后运行VS安装程序,卸载Tools for Ap ...

  10. MySQL技术内幕读书笔记(四)——表

    目录 表 索引组织表 InnoDB逻辑存储结构 INNODB行记录格式 INNODB数据页结构 约束 视图 分区表 表 ​ 表就是关于特定实体的数据集合,是关系型数据库模型的核心. 索引组织表 ​ 在 ...