Java 如何高效打印ByteArray的內(nèi)容

在使用TCP協(xié)議作為傳輸協(xié)議時(shí)笨忌,很多時(shí)候都需要輸出原始報(bào)文用來查看傳輸數(shù)據(jù)是否正確冬殃。特別是在物聯(lián)網(wǎng)中的硬件服務(wù)器魂角,上下行的數(shù)據(jù)量非常大,任何關(guān)于報(bào)文的處理的開銷都會(huì)因?yàn)橄⒌脑黾佣杀斗糯蟆?/p>

不管使用ByteArray或者ByteBuffer當(dāng)做數(shù)據(jù)容器赡茸,輸出日志時(shí)夭禽,都需要進(jìn)行兩步城菊,第一步:把字節(jié)數(shù)組的字節(jié)轉(zhuǎn)成字符;第二步:在拼接字符形成字符串。

一般的處理方式

迭代拼接字符串

創(chuàng)建StringBuilder顶考,迭代ByteArray赁还,格式化每個(gè)byte后,追加到StringBuilder中驹沿,最后使用StringBuilder.toString()方法輸出完整字符串艘策。

    /**
     * 根據(jù)字節(jié)數(shù)組,輸出對(duì)應(yīng)的格式化字符串
     * @param bytes 字節(jié)數(shù)組
     * @return 字節(jié)數(shù)組字符串
     */
    public static String printBytesByStringBuilder(byte[] bytes){
        StringBuilder stringBuilder = new StringBuilder();

        for (byte aByte : bytes) {
            stringBuilder.append(byte2String(aByte));
        }

        return stringBuilder.toString();

    }

    public static String byte2String(byte b){

        return String.format("%02x ",b);
    }

特定優(yōu)化處理

預(yù)分配字符數(shù)組渊季,使用常量池來實(shí)現(xiàn)字節(jié)到字符的轉(zhuǎn)換朋蔫。填充提前預(yù)分配好的字符數(shù)組。輸出字符串却汉!
第一步:窮舉所有byte對(duì)應(yīng)的字符數(shù)組


窮舉所有的byte對(duì)應(yīng)的兩位字符

第二步:使用索引的方式進(jìn)行字符串拼接


    /**
     * 使用字符數(shù)組進(jìn)行byte字節(jié)信息的輸出 如果默認(rèn)進(jìn)制標(biāo)識(shí)的話驯妄,不打印'0x',一個(gè)byte只需要兩個(gè)char 例如: 0x9  = '0' + '9' 0xAF = 'A' + 'F'
     * 0x9 0xAF = > '0'+'9'+' '+'A'+'F'
     * <p>
     * 一個(gè)byte需要2個(gè)字符標(biāo)識(shí),外加一個(gè)空格字符
     *
     * @param bytes 需要格式化的byte
     * @return 字節(jié)數(shù)組 字符串
     */
    public static String printBytesByCharPool(byte[] bytes) {
        int byteLength = bytes.length;
        int charLength = byteLength * 3;


        char[] content = new char[charLength];
        int unsignedByte = 0;
        int startIndex = 0;
        for (int i = 0; i < byteLength; i++) {
            // 使byte變?yōu)闊o符號(hào)的byte
            // b2u
            unsignedByte = ((int) bytes[i]) & 0xFF;

            char[] chars = BYTE_CHARS[unsignedByte];
            startIndex = i * 3;
            // byte的第一位字符
            content[startIndex] = chars[0];
            // byte格式化的第二位字符
            content[startIndex + 1] = chars[1];
            // 尾隨的空格字符
            content[startIndex + 2] = WHITE_CHAR;
        }

        return new String(content);
    }

分別使用1024長(zhǎng)度的byteArray進(jìn)行循環(huán)1200次打印結(jié)果:

# 使用stringBuilder
printBytesByStringBuilder useTime=1070
# 使用字符池
printBytesByCharPool useTime=4

可以看出來速度差別在兩個(gè)數(shù)量級(jí)

其他開銷分析

分析這兩種方法存在的性能開銷點(diǎn)有:String.format的性能合砂,StringBuilder的性能

String.format

String.format方法用來格式化代碼青扔,進(jìn)入源碼可以看到,每次都會(huì)創(chuàng)建一個(gè)模板對(duì)象翩伪,不能復(fù)用微猖,這個(gè)必然存在一定的性能開銷

 public static String format(String format, Object... args) {
        return new Formatter().format(format, args).toString();
    }

StringBuilder的性能

雖然StringBuilder 已經(jīng)是最常用的字符串拼接方法,如果頻繁調(diào)用也會(huì)發(fā)現(xiàn)內(nèi)部其實(shí)也有動(dòng)態(tài)擴(kuò)容的機(jī)制缘屹,類似于hasmap的擴(kuò)容凛剥。當(dāng)容量沒有預(yù)估時(shí),會(huì)發(fā)生多次動(dòng)態(tài)擴(kuò)容轻姿。

使用場(chǎng)景

在用于做Tcp服務(wù)器時(shí)犁珠,客戶端與服務(wù)端使用Tcp長(zhǎng)連接進(jìn)行通訊,需要輸出原始報(bào)文進(jìn)行信息查看和追蹤互亮,這個(gè)時(shí)候輸出報(bào)文的開銷就伴隨這設(shè)備增多會(huì)成倍放大盲憎,關(guān)于輸出Tcp中報(bào)文字節(jié)的開銷就不能小視。
如果是次場(chǎng)景優(yōu)化胳挎,其他可以采取的方法有:

  1. 盡量使用定長(zhǎng)協(xié)議,可以提前分割定長(zhǎng)協(xié)議的格式化所需要內(nèi)存空間
  2. 如果在輸出字節(jié)數(shù)組時(shí)溺森,需要增加前綴或者后綴慕爬,也可以在申請(qǐng)字節(jié)數(shù)組對(duì)應(yīng)的字符數(shù)組時(shí)提前把前后綴的內(nèi)容對(duì)應(yīng)的空間一起創(chuàng)建出來
  3. 如果消息量特別大時(shí)也可以考慮使用隊(duì)列進(jìn)行延遲或異步打印,不影響網(wǎng)絡(luò)吞吐
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末屏积,一起剝皮案震驚了整個(gè)濱河市医窿,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌炊林,老刑警劉巖姥卢,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡独榴,警方通過查閱死者的電腦和手機(jī)僧叉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來棺榔,“玉大人瓶堕,你說我怎么就攤上這事≈⑿” “怎么了郎笆?”我有些...
    開封第一講書人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)忘晤。 經(jīng)常有香客問我宛蚓,道長(zhǎng),這世上最難降的妖魔是什么设塔? 我笑而不...
    開封第一講書人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任凄吏,我火速辦了婚禮,結(jié)果婚禮上壹置,老公的妹妹穿的比我還像新娘竞思。我一直安慰自己,他們只是感情好钞护,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開白布盖喷。 她就那樣靜靜地躺著,像睡著了一般难咕。 火紅的嫁衣襯著肌膚如雪课梳。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,007評(píng)論 1 284
  • 那天余佃,我揣著相機(jī)與錄音暮刃,去河邊找鬼。 笑死爆土,一個(gè)胖子當(dāng)著我的面吹牛椭懊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播步势,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼氧猬,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了坏瘩?” 一聲冷哼從身側(cè)響起盅抚,我...
    開封第一講書人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎倔矾,沒想到半個(gè)月后妄均,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體柱锹,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年丰包,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了禁熏。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡烫沙,死狀恐怖匹层,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情锌蓄,我是刑警寧澤升筏,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站瘸爽,受9級(jí)特大地震影響您访,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜剪决,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一灵汪、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧柑潦,春花似錦享言、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至譬胎,卻和暖如春差牛,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背堰乔。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來泰國(guó)打工偏化, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人镐侯。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓侦讨,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親苟翻。 傳聞我的和親對(duì)象是個(gè)殘疾皇子搭伤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 1.常量&變量 1.1.直接賦值常量值,禁止聲明新對(duì)象 直接賦值常量值身堡,只是創(chuàng)建了一個(gè)對(duì)象引用邓尤,而這個(gè)對(duì)象引用指向...
    非著名程序員i閱讀 217評(píng)論 0 0
  • Java繼承關(guān)系初始化順序 父類的靜態(tài)變量-->父類的靜態(tài)代碼塊-->子類的靜態(tài)變量-->子類的靜態(tài)代碼快-->父...
    第六象限閱讀 2,143評(píng)論 0 9
  • 表情是什么,我認(rèn)為表情就是表現(xiàn)出來的情緒。表情可以傳達(dá)很多信息汞扎。高興了當(dāng)然就笑了季稳,難過就哭了。兩者是相互影響密不可...
    Persistenc_6aea閱讀 124,166評(píng)論 2 7
  • 16宿命:用概率思維提高你的勝算 以前的我是風(fēng)險(xiǎn)厭惡者澈魄,不喜歡去冒險(xiǎn)景鼠,但是人生放棄了冒險(xiǎn),也就放棄了無數(shù)的可能痹扇。 ...
    yichen大刀閱讀 6,033評(píng)論 0 4