字符串對我編程人員來講是字符串時天天見面的常客,你不認識不熟悉他都不得行,字符串的拼接更是屢見不鮮,那麼在實際開發過程當中實現字符串的拼接有哪一些方式呢?我們一塊兒來聊聊,來交流溝通,學習一波。也許你會說,那也太簡單了嘛,誰不會啊,哈哈,使用起來確實簡單,可是不必定咱們都使用的方式還有優秀的方式嗎?html
在文章前,咱們先簡單聊聊關於string的數據類型存儲必須瞭解概念:程序員
string是一個引用類型,是一個sealed類,存儲在堆內存上,每一次修改都會重新建立一個新的string來存儲,原始的會自動被回收。這個是不感受是廢話,人人都知道嘛,哈哈哈。編程
下面以c#爲開發語言來講明:實現字符串的拼接經常使用的方式有以下四種c#
其1、直接經過+拼接數組
直接經過+拼接是咱們在代碼中最多見的一種方式,下面以一個簡單的代碼段來分析分析ide
1 string str="1"; 2 3 str=str+"2";
第一段代碼,首先分配了一個內存空間來存儲str變量,其值爲「1」函數
第二段代碼,從新分配了一個新的內存空間來存儲「12」,並將str指向新地址性能
經過分析,其實咱們不難發現,兩端就簡單的代碼,就會有兩次內存地址操做,隨着拼接字符串的個數地址,分配內存地址的次數也遞增,當幾個簡單的字符串經過該方式拼接時,其實咱們仍是感受不到性能的影響,可是當字符串數量大時,你都會有感受了,那樣不只僅形成內存的浪費,還直接影響性能。學習
因此在實際開發工程中,經過+拼接字符串比較常見,可是若是隻是見到這種方式也就不那麼友好了,既然不友好,那麼顯然就會有比較友好的方式啦,下面咱們就分析分析經過StringBuilder來實現字符串的拼接。測試
其2、經過StringBuilder拼接字符串
StringBuilder其實內部至關因而維護的一個字符數組,是一個能夠動態增長自身數據長度,其默認長度爲16,當存儲的字符串超出其長度是,會自動擴容2倍長度。
哈哈,說到這兒,估計你看出了問題,那就是超出長度自動擴容,自動擴容是否是也須要犧牲性能,固然在幾回擴容你還感受不到性能的影響,可是若是詞數多了,你就會感受很明顯,這也是對StringBuilder的一些使用技巧。
咱們去看不一樣小夥伴的代碼,你就會發現,技術老鳥,在初始化StringBuilder的時候會根據預估將要存儲的字符串大小,給StringBuilder初始化一個長度,這也就是細節上的差距體現。
說了半天的廢話,是否是要來的實際的代碼來證實說的不是廢話呢?不急不急,在文章最後,我會專門寫測試代碼對比分析的。
其3、string.Format不陌生吧
對於一些格式的數據拼接填充,string.Format也是常常看見的,他的一個很大好處就是,看上去比較清晰
其實咱們看過string的底層實現咱們會發現,其底層本質仍是StringBuilder來實現的
下面就是string.format的源碼實現
public static String Format(IFormatProvider provider, String format, params Object[] args) <br>{ if (format == null || args == null) throw new ArgumentNullException((format==null)?"format":"args"); StringBuilder sb = new StringBuilder(format.Length + args.Length * 8); sb.AppendFormat(provider,format,args); return sb.ToString(); }
其實string.Format使用起來很簡單,我就不在囉嗦介紹了,省得你們以爲煩,哈哈哈
string result=string.Format("你們好,我叫{0},今年{1}","程序員修煉之旅",1);
其4、$方式拼接字符串
C#6.0出現了$方式拼接字符串,其實簡單說就是string.Format簡化操做版,string.Format若是拼接的字符串太多,估計本身都懵逼的分不清對應關係了,不知道大家遇到過沒有,反正我原來是遇到過的。$就很好的規避了該問題,那麼下 面來一個例子說明一切:
string name = "程序員修煉之旅"; int age = 1; string str = string.Format("my name is{0}, I'm {1} years old",name,age); string str2 = $"my name is{name}, I'm {age} years old";
最終結果是:str=str1
其五,固然還有其餘方式,不在此囉嗦了,後續在討論
測試分析
說了半天,不拿點實際東西來測試,我知道你是不會信服的,下面就直接上測試代碼:
using System; using System.Diagnostics; using System.Text; namespace stringSplicingTest { /// <summary> /// 字符串拼接練習 /// </summary> public class Program { /// <summary> /// 主函數入口 /// </summary> /// <param name="args"></param> static void Main(string[] args) { // 測試分別經過+ 和 StringBuilder 來鏈接 0 之100的數字 Console.WriteLine("測試分別經過+ 和 StringBuilder 來鏈接"); Console.WriteLine(""); Console.WriteLine("測試鏈接 0 - 100 的數字"); Console.WriteLine(""); PlusString(100); StringBuilderString2(100); Console.WriteLine(""); Console.WriteLine(""); Console.WriteLine("測試鏈接 0 - 10000 的數字"); PlusString(10000); StringBuilderString2(10000); Console.WriteLine(""); Console.WriteLine(""); // 下面測試一下一樣是StringBuilder鏈接字符串,一個是定義吃指定長度,一個是不指定長度對比 Console.WriteLine(@"下面測試一下一樣是StringBuilder鏈接字符串, 一個是定義並指定長度,一個是不指定長度對比"); Console.WriteLine(""); Console.WriteLine("測試鏈接 0 - 1000000 的數字"); Console.WriteLine("不初始化長度"); StringBuilderString(1000000); Console.WriteLine("初始化長度"); StringBuilderString2(1000000); Console.WriteLine(""); Console.WriteLine(""); Console.WriteLine("測試鏈接 0 - 10000000 的數字"); Console.WriteLine("不初始化長度"); StringBuilderString(10000000); Console.WriteLine("初始化長度"); StringBuilderString2(10000000); Console.ReadLine(); } /// <summary> /// 經過+拼接字符串 /// </summary> /// <param name="totalNum"></param> private static void PlusString(int totalNum) { //// 定義一個秒錶,執行獲取執行時間 Stopwatch st = new Stopwatch();//實例化類 st.Start();//開始計時 Console.WriteLine("開始執行,經過+鏈接字符串:"); string result = ""; //// 定義一個數組 for (int i = 0; i < totalNum; i++) { result = result + i.ToString(); } //須要統計時間的代碼段 st.Stop();//終止計時 Console.WriteLine(string.Format("執行完畢,經過+鏈接字符串!總耗時{0}毫秒", st.ElapsedMilliseconds.ToString())); } /// <summary> /// 經過s拼接字符串 /// </summary> /// <param name="totalNum"></param> private static void StringBuilderString(int totalNum) { //// 定義一個秒錶,執行獲取執行時間 Stopwatch st = new Stopwatch();//實例化類 st.Start();//開始計時 Console.WriteLine("開始執行,經過 StringBuilder 鏈接字符串:"); StringBuilder result = new StringBuilder(); //// 定義一個數組 for (int i = 0; i < totalNum; i++) { result.Append(i.ToString()); } string result2 = result.ToString(); //須要統計時間的代碼段 st.Stop();//終止計時 Console.WriteLine(string.Format("執行完畢,經過 StringBuilder 鏈接字符串!總耗時{0}毫秒", st.ElapsedMilliseconds.ToString())); } /// <summary> /// 經過StringBuilder拼接字符串,初始化時指定一個長度 /// </summary> /// <param name="totalNum"></param> private static void StringBuilderString2(int totalNum) { //// 定義一個秒錶,執行獲取執行時間 Stopwatch st = new Stopwatch();//實例化類 st.Start();//開始計時 Console.WriteLine("開始執行,經過 StringBuilder 鏈接字符串:"); StringBuilder result = new StringBuilder(totalNum * 6); //// 定義一個數組 for (int i = 0; i < totalNum; i++) { result.Append(i.ToString()); } string result2 = result.ToString(); //須要統計時間的代碼段 st.Stop();//終止計時 Console.WriteLine(string.Format("執行完畢,經過 StringBuilder 鏈接字符串!總耗時{0}毫秒", st.ElapsedMilliseconds.ToString())); } } }
結果分析總結:
測試分兩個點:
其一測試的是:經過+和StringBuilder拼接字符串的性能比較哦
其二測試的是:StringBuilder初始化長度和不初始化長度的性能比較
大概得出如下幾點結論
一、在待拼接的字符串少的時,+和StringBuilder沒有明顯的性能差距
二、當拼接的字符串多時,StringBuilder的優點愈來愈明顯
三、一樣是StringBuilder拼接字符串,預估初始化長度的效率比不初始化指定長度的效率高
說到此,我相信你們都知道該怎麼使用了。好了,時間不早了,趕忙洗洗睡了,明天還得上班呢?
END
原文地址:https://www.cnblogs.com/xiaoXuZhi/p/XYH_String2.html