日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢(xún)
選擇下列產(chǎn)品馬上在線(xiàn)溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
for循環(huán)為何可恨?

Java的閉包(Closure)特征最近成為了一個(gè)熱門(mén)話(huà)題。一些精英正在起草一份議案,要在Java將來(lái)的版本中加入閉包特征。然而,提議中的閉包語(yǔ)法以及語(yǔ)言上的這種擴(kuò)充受到了眾多Java程序員的猛烈抨擊。

專(zhuān)注于為中小企業(yè)提供成都做網(wǎng)站、成都網(wǎng)站設(shè)計(jì)服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)七臺(tái)河免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動(dòng)了上千家企業(yè)的穩(wěn)健成長(zhǎng),幫助中小企業(yè)通過(guò)網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。

不久前,出版過(guò)數(shù)十本編程書(shū)籍的大作家Elliotte Rusty Harold發(fā)表了對(duì)Java中閉包的價(jià)值的質(zhì)疑。尤其是他問(wèn)道“ for 循環(huán)為何可恨?”:

我不知道,有些人這么著急的要把 for 循環(huán)消滅掉,他們反對(duì)的究竟是什么?這已經(jīng)不是第一次或第二次計(jì)算機(jī)學(xué)界的理論家們起來(lái)反對(duì) for 循環(huán)(或類(lèi)似的東西)了。
 

如果只說(shuō)Elliotte質(zhì)疑不起眼的閉包的價(jià)值,這是不公平的。他主要抱怨是,在讀了另一位著名人物、獲得過(guò)Jolt 大獎(jiǎng)并創(chuàng)造過(guò)最高銷(xiāo)售記錄的《Better, Faster, Lighter Java》的作者Bruce Tate的最近的關(guān)于此主題的專(zhuān)題后,他看不出閉包在Java中有什么價(jià)值。(Bruce用Ruby做的例證):

表 1. 最簡(jiǎn)單的閉包

 
 
 
  1. 3.times {puts "Inside the times method."}  
  2.  
  3. 結(jié)果:  
  4. Inside the times method.  
  5. Inside the times method.  
  6. Inside the times method. 

times是3這個(gè)對(duì)象上的一個(gè)方法。它把閉包中的代碼執(zhí)行了3次。{puts "Inside the times method."}是閉包。它是一個(gè)匿名函數(shù),把它傳入times方法,打印出靜態(tài)句子。相比起傳統(tǒng)的for循環(huán)語(yǔ)句,這樣的代碼顯得更緊湊,更簡(jiǎn)單,如表2中所示:

表 2: 非閉包的循環(huán)

 
 
 
  1. for i in 1..3 
  2. puts "Inside the times method." 
  3. end 

由于這種毫無(wú)生氣的對(duì)閉包的介紹,我也很難看出它的真正價(jià)值。這首個(gè)比較,充其量也就能體現(xiàn)出一種微妙的差別。Bruce在developerWorks上的文章里的其它的例子也大多是價(jià)值不大的,要么含糊不清,要么缺乏啟發(fā)意義。

對(duì)于這種Ruby風(fēng)格的閉包給Elliotte帶來(lái)的困惑,我不打算進(jìn)一步評(píng)論;對(duì)這種問(wèn)題過(guò)于挑剔毫無(wú)意義。我也不想討論目前的關(guān)于Java中的閉包的語(yǔ)法的提議的爭(zhēng)論,包括Java中是否應(yīng)該有閉包這樣的大問(wèn)題。在這樣的爭(zhēng)論中我沒(méi)有立場(chǎng),說(shuō)實(shí)話(huà),我是不在乎這些問(wèn)題如何或何時(shí)被解決。

雖然如此,Elliotte卻提出了一個(gè)重要的問(wèn)題:for 循環(huán)為什么可恨?

下面是一個(gè)常見(jiàn)的例子:

 
 
 
  1. double sum = 0;  
  2. for (int i = 0; i < array.length; i++) {  
  3. sum += array[i];  

這有什么問(wèn)題?我編了很多年的程序,我對(duì)這種語(yǔ)法一眼掃過(guò)去很舒服;很顯然,它是把一個(gè)數(shù)組里的值加到一起。但當(dāng)去真正的閱讀這段代碼時(shí),這四行代碼里大概散布著30多個(gè)標(biāo)記符號(hào)需要我去分析處理。不錯(cuò),有些字符可以通過(guò)語(yǔ)法簡(jiǎn)寫(xiě)方式來(lái)縮減。但為了這樣一個(gè)簡(jiǎn)單的加法,你需要寫(xiě)出一堆東西,還要保證寫(xiě)的正確。

憑什么這樣說(shuō)?下面是Elliotte的文章里另外一個(gè)例子,原文拷貝:

 
 
 
  1. String s = "";  
  2. for (int i = 0; i < args.length; i++) {  
  3. s += array[i];  

看見(jiàn)了里面的錯(cuò)誤嗎?如果這代碼編譯通過(guò),并通過(guò)的代碼審查,你可能需要數(shù)周才會(huì)發(fā)現(xiàn)這樣的bug,再數(shù)周才能制作出補(bǔ)丁。這些只是簡(jiǎn)單的for循環(huán)。想象一下,當(dāng)for循環(huán)體變得越來(lái)越大,甚至有嵌套時(shí),事情會(huì)變得多么的復(fù)雜。(如果你仍舊不擔(dān)心這樣的bug,認(rèn)為這只是拼寫(xiě)錯(cuò)誤,那么你就想想有多少次在for循環(huán)里你是這樣的。)

如果你能夠把一個(gè)簡(jiǎn)單的for循環(huán)寫(xiě)成一行,帶有更少的重復(fù)和更少的字符,這樣不僅更容易閱讀,也更容易書(shū)寫(xiě)。因?yàn)檫@樣更簡(jiǎn)潔,引入bug的機(jī)會(huì)就更少,當(dāng)bug出現(xiàn)時(shí),也更容易被發(fā)現(xiàn)。

那閉包對(duì)此有何幫助?下面是第一個(gè)例子,用Haskell語(yǔ)言寫(xiě)成的:

 
 
 
  1. total = sum array 

哈哈,我是在說(shuō)謊。sum函數(shù)并沒(méi)有使用閉包。它是按照f(shuō)old的方式定義的,而fold是接受閉包的:

 
 
 
  1. total = foldl (+) 0 array 

下面是第二個(gè)例子,很常見(jiàn),而且使用了閉包:

 
 
 
  1. s = concat array  
  2. s = foldr (++) [] array 

我承認(rèn),使用這些叫做foldl 和 foldr 樣子古怪的函數(shù)來(lái)解釋閉包的作用,這對(duì)那些更熟悉for循環(huán)的程序員來(lái)說(shuō)沒(méi)有多大意義。但是,這幾個(gè)函數(shù)卻能突出for循環(huán)的關(guān)鍵弊端:它把三種獨(dú)立不同的操作合并到一起了——過(guò)濾,歸納和轉(zhuǎn)換。

上面的這兩種for循環(huán),它們的目標(biāo)是接收一個(gè)數(shù)值列表,把它們歸納成一個(gè)值。函數(shù)式編程的程序員稱(chēng)這些操作為“folds(合并)”。一個(gè)fold運(yùn)算的過(guò)程是,首先要有一個(gè)操作(一個(gè)閉包)和一個(gè)種子值,還有使用list里的第一個(gè)元素。這個(gè)操作被施加到種子值和list里的第一個(gè)元素上,產(chǎn)生出一個(gè)新的種子值。fold運(yùn)算然后把這個(gè)操作運(yùn)用到新種子值和list里的下一個(gè)元素上,一直這樣,直到最后一個(gè)值,最后一次操作的結(jié)果成為fold運(yùn)算的結(jié)果。

下面是一個(gè)演示:

 
 
 
  1. s = foldl (+) 0 [1, 2, 3]  
  2. = foldl (+) (0 + 1) [2, 3]  
  3. = foldl (+) 1 [2, 3]  
  4. = foldl (+) (1 + 2) [3]  
  5. = foldl (+) 3 [3]  
  6. = foldl (+) (3 + 3) []  
  7. = foldl (+) 6 []  
  8. = 6 

Haskell語(yǔ)言里提供了很多fold函數(shù);foldl函數(shù)從list的第一位開(kāi)始運(yùn)算,依次反復(fù)到最后一個(gè),而foldr函數(shù),它從list的最后一個(gè)函數(shù)開(kāi)始運(yùn)算,從后往前。還有很多其它相似的函數(shù),但這兩個(gè)是最基本的。

當(dāng)然,folds是一些非?;镜倪\(yùn)算,如果拋棄for循環(huán)而以各種形式的foldl 和 foldr 咒符來(lái)替換,你會(huì)很困惑。事實(shí)上,更高級(jí)的操作,例如sum, prod 和 concat都是以各種folds定義的。當(dāng)你的代碼以這種高級(jí)的歸納操作運(yùn)算來(lái)編寫(xiě)時(shí),代碼會(huì)變得更簡(jiǎn)潔,更易讀,更易寫(xiě),更易懂。

當(dāng)然,并不是所有的for循環(huán)都是歸納操作。看看下面這個(gè):

 
 
 
  1. for (int i = 0; i < array.length; i++) {  
  2. array[i] *= 2;  

這是一個(gè)轉(zhuǎn)換操作,函數(shù)式編程的程序員稱(chēng)之為map操作:

 
 
 
  1. new_array = map (*2) array 

map函數(shù)的工作方式是,它會(huì)檢查list里的每個(gè)元素,將一個(gè)函數(shù)應(yīng)用到每個(gè)元素上,形成一個(gè)新的list,里面是新的元素。(有些語(yǔ)言里的這種操作是原位替換)。這是一個(gè)很容易理解的操作。sort函數(shù)的功能相似,它接受一個(gè)list,返回(或修改)一個(gè)list。

第三種類(lèi)型的for循環(huán)是過(guò)濾。下面是個(gè)例子。

 
 
 
  1. int tmp[] = new int[nums.length];  
  2. int j = 0;  
  3. for (int i = 0; i < nums.length; i++) {  
  4. if ((nums[i] % 2) == 1) {  
  5. tmp[j] = nums[i];  
  6. j++;  
  7. }  

這是一個(gè)非常簡(jiǎn)單的操作,但使用了for循環(huán)和兩個(gè)獨(dú)立的計(jì)數(shù)器后,毫無(wú)必要的復(fù)雜表現(xiàn)把事實(shí)真相完全掩蓋了。如果過(guò)濾是一種基本的操作,它應(yīng)該像一個(gè)fold或一個(gè)map那樣,而事實(shí)上,它是的:

 
 
 
  1. odds = filter (\i => (i `mod` 2) == 1) nums  
  2. odds = filter isOdd nums -- 更常用的形式 

從核心上講,這就是為什么for循環(huán)有問(wèn)題:它把(至少)三種獨(dú)立的操作合并到了一起,但重點(diǎn)卻關(guān)注了一個(gè)次要細(xì)節(jié)問(wèn)題:遍歷一系列的值。而事實(shí)上,fold,map 和 filter是處理一個(gè)數(shù)據(jù)list的三種不同的操作,它們應(yīng)該被分別處理。采用把閉包傳入循環(huán)內(nèi)的方式,我們能更容易的把what 從 how 中分離出來(lái)。每次遍歷一個(gè)list時(shí)我都會(huì)使用一個(gè)匿名函數(shù),或復(fù)用通用的函數(shù)(例如 isOdd, (+) 或 sqrt)。

雖然閉包并不是一個(gè)很深?yuàn)W的概念,但當(dāng)它深深的烙進(jìn)了一種語(yǔ)言和它的標(biāo)準(zhǔn)庫(kù)中時(shí),我們不需要使用這些低級(jí)的操作搞的代碼混亂不堪。相反,我們可以創(chuàng)建更高級(jí)的運(yùn)算,做我們想要的事,比如sum and prod。

更重要的,以這些概念思考問(wèn)題會(huì)使我們更容易思考更復(fù)雜的操作,比如變換一個(gè)tree,過(guò)濾一個(gè)vector,或把一個(gè)list合并成一個(gè)hash。

在最后,Elliotte還提到了一些關(guān)于在多核處理器上并行執(zhí)行的問(wèn)題,說(shuō)像3.times {...}這樣的代碼會(huì)比 for 循環(huán)效率“差”。不幸的是,我想他沒(méi)說(shuō)到點(diǎn)上。不錯(cuò),有一些運(yùn)算需要序列化,有一些可以并行。但是如果你只基于一個(gè)for循環(huán),很難判斷出哪些歸為哪類(lèi),這是一個(gè)復(fù)雜的編譯器優(yōu)化問(wèn)題。如果你把一個(gè)可能進(jìn)行并行運(yùn)算的操作(例如map 和 filter)分解成連續(xù)的運(yùn)算(例如foldl 和 foldr),編譯器更容易從中做出判斷。不僅如此,如果你比編譯器更了解你的數(shù)據(jù),你可以顯式的要求一個(gè)map操作被順序執(zhí)行或并行執(zhí)行。

英文原文鏈接:What's Wrong with the For Loop

本文轉(zhuǎn)自:http://www.aqee.net/whats-wrong-with-the-for-loop/


本文名稱(chēng):for循環(huán)為何可恨?
新聞來(lái)源:http://m.5511xx.com/article/cdheeds.html