Java語(yǔ)法糖系列一:可變長(zhǎng)度參數(shù)和foreach循環(huán)

目錄:
Java語(yǔ)法糖系列一:可變長(zhǎng)度參數(shù)和foreach循環(huán)
http://www.reibang.com/p/628568f94ef8

Java語(yǔ)法糖系列二:自動(dòng)裝箱/拆箱和條件編譯
http://www.reibang.com/p/946b3c4a5db6

Java語(yǔ)法糖系列三:泛型與類(lèi)型擦除
http://www.reibang.com/p/4de08deb6ba4

Java語(yǔ)法糖系列四:枚舉類(lèi)型
http://www.reibang.com/p/ae09363fe734

Java語(yǔ)法糖系列五:內(nèi)部類(lèi)和閉包
http://www.reibang.com/p/f55b11a4cec2


好久沒(méi)做總結(jié),打算挖個(gè)坑整理一下Java語(yǔ)法糖相關(guān)的知識(shí)扰她。文字邀层、說(shuō)明等知識(shí)均來(lái)源于互聯(lián)網(wǎng)和自己的見(jiàn)解,例子都是自己寫(xiě)的摄狱,侵刪,歡迎討論~

語(yǔ)法糖

語(yǔ)法糖(Syntactic Sugar),也叫糖衣語(yǔ)法,是英國(guó)計(jì)算機(jī)科學(xué)家彼得·約翰·蘭達(dá)(Peter J. Landin)發(fā)明的一個(gè)術(shù)語(yǔ)低淡。指的是,在計(jì)算機(jī)語(yǔ)言中添加某種語(yǔ)法瞬项,這種語(yǔ)法能使程序員更方便的使用語(yǔ)言開(kāi)發(fā)程序蔗蹋,同時(shí)增強(qiáng)程序代碼的可讀性,避免出錯(cuò)的機(jī)會(huì)囱淋。

幾乎每種語(yǔ)言都提供語(yǔ)法糖猪杭,它只是編譯器實(shí)現(xiàn)的一些小把戲罷了,編譯期間以特定的字節(jié)碼或者特定的方式對(duì)這些語(yǔ)法做一些處理妥衣,開(kāi)發(fā)者就可以直接方便地使用了皂吮。這些語(yǔ)法糖雖然不會(huì)提供實(shí)質(zhì)性的功能改進(jìn),但是它們或能提高性能称鳞、或能提升語(yǔ)法的嚴(yán)謹(jǐn)性涮较、或能減少編碼出錯(cuò)的機(jī)會(huì)稠鼻。Java提供給了用戶(hù)大量的語(yǔ)法糖冈止,比如泛型、自動(dòng)裝箱候齿、自動(dòng)拆箱熙暴、foreach循環(huán)闺属、變長(zhǎng)參數(shù)、內(nèi)部類(lèi)周霉、枚舉類(lèi)掂器、斷言(assert)等

學(xué)習(xí)語(yǔ)法糖原理最好的辦法就是反編譯看源碼~

可變長(zhǎng)度參數(shù)

看以下代碼

public static void main(String[] args){
    String [] params=new String[]{
            "111","222","333","444"
    };
    print("AAA","BBB","CCC","DDD");
    print(params);
}

 
public static void print(String... params)
{
    System.out.println();
    for (int i = 0; i < params.length; i++)
    {
        System.out.print(params[i]+"~");
    }
}

print方法的參數(shù)的意思是表示傳入的params個(gè)數(shù)是不定的俱箱,代碼的運(yùn)行結(jié)果:

AAA~BBB~CCC~DDD~
111~222~333~444~

我用數(shù)組遍歷的方式把參數(shù)遍歷出來(lái)了国瓮,同時(shí)print方法也接受數(shù)組參數(shù),這說(shuō)明了可變參數(shù)是利用數(shù)組實(shí)現(xiàn)的狞谱。查看編譯出來(lái)的源碼:

public static void main(String[] paramArrayOfString)
 {
    String[] arrayOfString = { "111", "222", "333", "444" };

    print(new String[] { "AAA", "BBB", "CCC", "DDD" });
    print(arrayOfString);
  }

  public static void print(String[] paramArrayOfString)
  {
    System.out.println();
    for (int i = 0; i < paramArrayOfString.length; ++i)
    {
      System.out.print(paramArrayOfString[i] + "~");
    }
 }

發(fā)現(xiàn)print方法的參數(shù)部分由String... params 變成了 String[] paramArrayOfString
數(shù)組參數(shù)乃摹,說(shuō)明可變長(zhǎng)度參數(shù)是用數(shù)組實(shí)現(xiàn)的。

最后跟衅,注意一點(diǎn)孵睬,可變長(zhǎng)度參數(shù)必須作為方法參數(shù)列表中的的最后一個(gè)參數(shù)且方法參數(shù)列表中只能有一個(gè)可變長(zhǎng)度參數(shù)。

foreach循環(huán)原理

public static void print(String... params)
{
    System.out.println();
    for (String s:params)
    {
        System.out.print(s+"~");
    }
}

把上面的print函數(shù)換成foreach循環(huán)伶跷,查看編譯出來(lái)的源碼

 public static void print(String[] paramArrayOfString)
  {
        System.out.println();
        String[] arrayOfString = paramArrayOfString; 
     int i = arrayOfString.length; 
     for (int j = 0; j < i; ++j) { 
        String str = arrayOfString[j];
          System.out.print(str + "~");
        }
  }

發(fā)現(xiàn)foreach部分被替換成了普通的for循環(huán)掰读,說(shuō)明對(duì)于數(shù)組,foreach是用普通for循環(huán)實(shí)現(xiàn)的叭莫。

如果遍歷的對(duì)象不是數(shù)組蹈集,而是List、Map等有實(shí)現(xiàn)迭代器Iterable接口的容器又是怎么實(shí)現(xiàn)的呢雇初?再看一個(gè)例子

public static void main(String[] args){
    // TODO Auto-generated method stub
    List<String> list = new ArrayList<String>();
    list.add("AAA");
    list.add("BBB");
    
    for(String l : list)
    {
        System.out.print(l+"~");
    }
    
    Set<String> set=new HashSet<String>();
    set.add("CCC");
    set.add("DDD");

    for(String s : set)
    {
        System.out.print(s+"~");
    }
}
}

查看編譯出來(lái)的源碼

public static void main(String[] paramArrayOfString)
{

    ArrayList localArrayList = new ArrayList();
        localArrayList.add("AAA");
    localArrayList.add("BBB");
    localArrayList.add("CCC");
    localArrayList.add("DDD");

for (Object localObject1 = localArrayList.iterator();
 ((Iterator)localObject1).hasNext(); ) 
{ 
      localObject2 = (String)((Iterator)localObject1).next();
      System.out.print(((String)localObject2) + "~");
}

    localObject1 = new HashSet();
    ((Set)localObject1).add("AAA");
    ((Set)localObject1).add("BBB");
    ((Set)localObject1).add("CCC");
    ((Set)localObject1).add("DDD");

for (Object localObject2 = ((Set)localObject1).iterator(); 
((Iterator)localObject2).hasNext(); )
 { 
    String str = (String)((Iterator)localObject2).next();
    System.out.print(str + "~");
}
}

List和Set的foreach都被編譯成用迭代器遍歷的形式了雾狈,說(shuō)明在對(duì)有實(shí)現(xiàn)Iterable接口的對(duì)象采用foreach語(yǔ)法糖的話(huà),編譯器會(huì)將這個(gè)for關(guān)鍵字轉(zhuǎn)化為對(duì)目標(biāo)的迭代器使用抵皱。
所以如果想要自己自定義的類(lèi)可以采用foreach語(yǔ)法糖就要實(shí)現(xiàn)Iterable接口了善榛。

一點(diǎn)拓展

ArrayList除了支持線(xiàn)性訪(fǎng)問(wèn)(sequential access)外還支持隨機(jī)訪(fǎng)問(wèn)外(random access)

這是因?yàn)閍rrayList還實(shí)現(xiàn)了RandomAccess接口,而Map呻畸、Set等沒(méi)有移盆。
查看JDK關(guān)于RandomAccess接口的說(shuō)明如下,版本是JDK1.8

It is recognized that the distinction between random and sequential

  • access is often fuzzy. For example, some <tt>List</tt> implementations
  • provide asymptotically linear access times if they get huge, but constant
  • access times in practice. Such a <tt>List</tt> implementation
  • should generally implement this interface. As a rule of thumb, a
  • <tt>List</tt> implementation should implement this interface if,
  • for typical instances of the class, this loop:
  • for (int i=0, n=list.size(); i < n; i++)
    
  •     list.get(i);
    
  • runs faster than this loop:
  • for (Iterator i=list.iterator(); i.hasNext(); )
    
  •     i.next();
    
  • @since 1.4

我們直接看最重要的部分伤为,從JDK1.4開(kāi)始咒循,根據(jù)經(jīng)驗(yàn),對(duì)于實(shí)現(xiàn)了RandomAccess接口的List绞愚,如ArrayList叙甸、CopyOnWriteArrayList, RoleList, RoleUnresolvedList, Stack, Vector,直接使用for循環(huán)遍歷runs faster than 迭代器遍歷位衩。

其實(shí)如果看過(guò)ArrayList源碼的同學(xué)也可以注意到:ArrayList底層是采用數(shù)組實(shí)現(xiàn)的裆蒸,如果采用Iterator遍歷,那么還要?jiǎng)?chuàng)建許多指針去執(zhí)行這些值(比如next();hasNext())等糖驴,這樣必然會(huì)增加內(nèi)存開(kāi)銷(xiāo)以及執(zhí)行效率僚祷。

簡(jiǎn)單測(cè)試了一下佛致,空遍歷10萬(wàn)條數(shù)據(jù)不做其他任何操作,對(duì)于A(yíng)rrayList用foreach遍歷和for遍歷耗時(shí)分別是5ms和1ms辙谜。例子都好簡(jiǎn)單就不貼出來(lái)了俺榆。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市装哆,隨后出現(xiàn)的幾起案子罐脊,更是在濱河造成了極大的恐慌,老刑警劉巖蜕琴,帶你破解...
    沈念sama閱讀 217,185評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件爹殊,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡奸绷,警方通過(guò)查閱死者的電腦和手機(jī)梗夸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)号醉,“玉大人反症,你說(shuō)我怎么就攤上這事∨吓桑” “怎么了铅碍?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,524評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)线椰。 經(jīng)常有香客問(wèn)我胞谈,道長(zhǎng),這世上最難降的妖魔是什么憨愉? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,339評(píng)論 1 293
  • 正文 為了忘掉前任烦绳,我火速辦了婚禮,結(jié)果婚禮上配紫,老公的妹妹穿的比我還像新娘径密。我一直安慰自己,他們只是感情好躺孝,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評(píng)論 6 391
  • 文/花漫 我一把揭開(kāi)白布享扔。 她就那樣靜靜地躺著,像睡著了一般植袍。 火紅的嫁衣襯著肌膚如雪惧眠。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,287評(píng)論 1 301
  • 那天于个,我揣著相機(jī)與錄音氛魁,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛呆盖,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播贷笛,決...
    沈念sama閱讀 40,130評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼应又,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼骇扇!你這毒婦竟也來(lái)了派阱?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,985評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤诉探,失蹤者是張志新(化名)和其女友劉穎汇荐,沒(méi)想到半個(gè)月后洞就,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,420評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡掀淘,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評(píng)論 3 334
  • 正文 我和宋清朗相戀三年旬蟋,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片革娄。...
    茶點(diǎn)故事閱讀 39,779評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡倾贰,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出拦惋,到底是詐尸還是另有隱情匆浙,我是刑警寧澤,帶...
    沈念sama閱讀 35,477評(píng)論 5 345
  • 正文 年R本政府宣布厕妖,位于F島的核電站首尼,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏言秸。R本人自食惡果不足惜软能,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望举畸。 院中可真熱鬧埋嵌,春花似錦、人聲如沸俱恶。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,716評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)合是。三九已至了罪,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間聪全,已是汗流浹背泊藕。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,857評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留难礼,地道東北人娃圆。 一個(gè)月前我還...
    沈念sama閱讀 47,876評(píng)論 2 370
  • 正文 我出身青樓玫锋,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親讼呢。 傳聞我的和親對(duì)象是個(gè)殘疾皇子撩鹿,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評(píng)論 2 354

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