国产精品色哟哟_男男激情3p互攻_色偷偷影院_和女同学厕所做了四次

當(dāng)前位置: 首頁 / 技術(shù)干貨 / 正文
好程序員Java培訓(xùn)分享Java函數(shù)式編碼結(jié)構(gòu)

2020-10-12

Java培訓(xùn)

  好程序員Java培訓(xùn)分享Java函數(shù)式編碼結(jié)構(gòu),本文將探討三種下一代JVM語言:GroovyScalaClojure,比較并對比新的功能和范例,讓Java開發(fā)人員對自己近期的未來發(fā)展有大體的認(rèn)識,下面我們一起來看一下吧。

好程序員

  當(dāng)垃圾回收成為主流時,它消除了所有類別的難以調(diào)試的問題,使運(yùn)行時能夠為開發(fā)人員管理復(fù)雜的、容易出錯的進(jìn)程。函數(shù)式編程旨在為你編寫的算法實現(xiàn)同樣的優(yōu)化,這樣你就可以從一個更高的抽象層面開展工作,同時運(yùn)行時執(zhí)行復(fù)雜的優(yōu)化。

  Java下一代語言并不都占用從命令式到函數(shù)式的語言頻譜的同一位置,但都展現(xiàn)出函數(shù)功能和習(xí)語。函數(shù)式編程技術(shù)有明確定義,但語言有時為相同的函數(shù)式概念使用不同的術(shù)語,使得我們很難看到相似之處。在本期文章中,我比較了ScalaGroovyClojure的函數(shù)式編碼風(fēng)格并討論了它們的優(yōu)勢。

  命令式處理

  我要首先探討一個常見問題及其命令式解決方案。假如給定一個名稱列表,其中一些名稱包含一個字符。系統(tǒng)會要求你在一個逗號分隔的字符串中返回名稱,該字符串中不包含單字母的名稱,每個名稱的首字母都大寫。實現(xiàn)該算法的Java代碼如清單1所示。

  清單1.命令式處理

  public class TheCompanyProcess {

  public String cleanNames(List<String> listOfNames) {

  StringBuilder result = new StringBuilder();

  for(int i = 0; i < listOfNames.size(); i++) {

  if (listOfNames.get(i).length() > 1) {

  result.append(capitalizeString(listOfNames.get(i))).append(",");

  }

  }

  return result.substring(0, result.length() - 1).toString();

  }

  public String capitalizeString(String s) {

  return s.substring(0, 1).toUpperCase() + s.substring(1, s.length());

  }

  }

  由于你必須處理整個列表,解決清單1中問題最簡單的方式是使用一個命令式循環(huán)。對于每個名稱,都需要進(jìn)行檢查,確認(rèn)其長度是否大于1,然后(如果長度大于1)將首字母大寫的名稱附加到result字符串,并在后面加逗號。最終字符串中的最后一個名稱不應(yīng)包含逗號,所以我將它從最后返回值中移走。

  在命令式編程中,建議你在較低級上別執(zhí)行操作。在清單1中的cleanNames()方法中,我執(zhí)行了三個任務(wù):我篩選列表以消除單字符,將列表中每個名稱的首字母變換為大寫,然后將列表轉(zhuǎn)化為一個字符串。在命令式語言中,我不得不為三個任務(wù)都使用同一低級機(jī)制(對列表進(jìn)行迭代)。函數(shù)式語言將篩選、變換和轉(zhuǎn)化視為常見操作,因此它們提供給你從不同視角解決問題的方式。

  函數(shù)式處理

  函數(shù)編程語言與命令式語言的問題分類方式不同。篩選、變換和轉(zhuǎn)化邏輯類別表現(xiàn)為函數(shù)。那些函數(shù)實現(xiàn)低級變換并依賴于開發(fā)人員來編寫作為參數(shù)傳遞的函數(shù),進(jìn)而定制函數(shù)的行為。我可以用偽代碼將清單1中的問題概念化為:

  listOfEmps -> filter(x.length > 1) -> transform(x.capitalize) ->

  convert(x, y -> x + "," + y)

  利用函數(shù)式語言,你可以建模這一概念性解決方案,無需擔(dān)心實現(xiàn)細(xì)節(jié)。

  Scala實現(xiàn)

  清單2使用Scala實現(xiàn)清單1中的處理示例。它看起來就像是前面的偽代碼,包含必要的實現(xiàn)細(xì)節(jié)。

  清單2.Scala處理

  val employees = List("neal", "s", "stu", "j", "rich", "bob")

  val result = employees

  .filter(_.length() > 1)

  .map(_.capitalize)

  .reduce(_ + "," + _)

  對于給定的名稱列表,我首先篩選它,剔除長度不大于1的所有名稱。然后將該操作的輸出提供給map()函數(shù),該函數(shù)對集合的每個元素執(zhí)行所提供的代碼塊,返回變換后的集合。最后,來自map()的輸出集合流向reduce()函數(shù),該函數(shù)基于代碼塊中提供的規(guī)則將每個元素結(jié)合起來。

  在本例中,我將每對元素結(jié)合起來,用插入的逗號連接它們。我不必考慮三個函數(shù)調(diào)用中參數(shù)的名稱是什么,所以我可以使用方便的Scala快捷方式,也就是說,使用_跳過名稱。reduce()函數(shù)從前兩個元素入手,將它們結(jié)合成一個元素,成為下一個串接中的diyi個元素。在“瀏覽”列表的同時,reduce()構(gòu)建了所需的逗號分隔的字符串。

  我首先展示Scala實現(xiàn)是因為我對它的語法比較熟悉,而且Scala分別為篩選、變換和轉(zhuǎn)化概念使用了行業(yè)通用的名稱,即filtermapreduce

  Groovy實現(xiàn)

  Groovy擁有相同的功能,但對它們進(jìn)行命名的方式與腳本語言(比如Ruby)更加一致。清單1中處理示例的Groovy版本如清單3所示。

  清單3.Groovy處理

  class TheCompanyProcess {

  public static String cleanUpNames(List listOfNames) {

  listOfNames

  .findAll {it.length() > 1}

  .collect {it.capitalize()}

  .join(',')

  }

  }

  盡管清單3在結(jié)構(gòu)上類似于清單2中的Scala示例,但方法名稱不同。GroovyfindAll集合方法應(yīng)用所提供的代碼塊,保留代碼塊為true的元素。如同ScalaGroovy包含一個隱式參數(shù)機(jī)制,為單參數(shù)代碼塊使用預(yù)定義的it隱式參數(shù)。collect方法(Groovymap版本)對集合的每個元素執(zhí)行所提供的代碼塊。Groovy提供一個函數(shù)(join()),使用所提供的分隔符將字符串集合串聯(lián)為單一字符串,這正是本示例中所需要的。

  Clojure實現(xiàn)

  Clojure是一個使用reducemapfilter函數(shù)名的函數(shù)式語言,如清單4所示。

  清單4.Clojure處理示例

  (defn process [list-of-emps]

  (reduce str (interpose ","

  (map clojure.string/capitalize

  (filter #(< 1 (count %)) list-of-emps)))))

  Clojurethread-first

  thread-last宏使集合的處理變得更加簡單。類似的Clojurethread-first可簡化與JavaAPI的交互。例如普遍的Java代碼語句person.getInformation().

  getAddress().getPostalCode(),這體現(xiàn)了Java違反迪米特法則的傾向。這種類型的語句給Clojure編程帶來一些煩惱,迫使使用JavaAPI的開發(fā)人員不得不構(gòu)建由內(nèi)而外的語句,比如(getPostalCode(getAddress(getInformationperson)))thread-first宏消除了這一語法困擾。你可以使用宏將嵌套調(diào)用編寫為(->persongetInformationgetAddressgetPostalCode),想嵌套多少層都可以。

  如果你不習(xí)慣查看Clojure,可以使用清單4中的代碼,其結(jié)構(gòu)可能不夠清晰。Clojure這樣的Lisp是“由內(nèi)而外”進(jìn)行工作的,所以必須從最后的參數(shù)值list-of-emps著手。Clojure(filter)函數(shù)接受兩個參數(shù):用于進(jìn)行篩選的函數(shù)(本例中為匿名函數(shù))和要篩選的集合。

  你可以為diyi個參數(shù)編寫一個正式函數(shù)定義,比如(fn[x](<1(countx))),但使用Clojure可以更簡潔地編寫匿名函數(shù)。與前面的示例一樣,篩選操作的結(jié)果是一個較少的集合。(map)函數(shù)將變換函數(shù)接受為diyi個參數(shù),將集合(本例中是(filter)操作的返回值)作為第二個參數(shù)。Clojure(map)函數(shù)的diyi個參數(shù)通常是開發(fā)人員提供的函數(shù),但接受單一參數(shù)的任何函數(shù)都有效;內(nèi)置capitalize函數(shù)也符合要求。

  最后,(map)操作的結(jié)果成為了(reduce)的集合參數(shù)。(reduce)的diyi個參數(shù)是組合函數(shù)(應(yīng)用于(interpose)的返回的(str))。(interpose)在集合的每個元素之間(除了最后一個)插入其diyi個參數(shù)。

  當(dāng)函數(shù)嵌套過多時,即使最有經(jīng)驗的開發(fā)人員也會倍感頭疼,如清單4中的(process)函數(shù)所示。所幸的是,Clojure包含的宏支持你將結(jié)構(gòu)“調(diào)整”為更可讀的順序。清單5中的功能與清單4中的功能一樣。

  清單5.使用Clojurethread-last

  (defn process2 [list-of-emps]

  (->> list-of-emps

  (filter #(< 1 (count %)))

  (map clojure.string/capitalize)

  (interpose ",")

  (reduce str)))

  Clojurethread-last宏采取對集合應(yīng)用各種變換的常見操作并顛倒典型的Lisp的順序,恢復(fù)了從左到右的更自然的閱讀方式。在清單5中,首先是(list-of-emps)集合。代碼塊中每個隨后的表單被應(yīng)用于前一個表單。Lisp的優(yōu)勢之一在于其語法靈活性:任何時候代碼的可讀性變得很差時,你都可以將代碼調(diào)整回具有較高可讀性。

好程序員公眾號

  • · 剖析行業(yè)發(fā)展趨勢
  • · 匯聚企業(yè)項目源碼

好程序員開班動態(tài)

More+
  • HTML5大前端 <高端班>

    開班時間:2021-04-12(深圳)

    開班盛況

    開班時間:2021-05-17(北京)

    開班盛況
  • 大數(shù)據(jù)+人工智能 <高端班>

    開班時間:2021-03-22(杭州)

    開班盛況

    開班時間:2021-04-26(北京)

    開班盛況
  • JavaEE分布式開發(fā) <高端班>

    開班時間:2021-05-10(北京)

    開班盛況

    開班時間:2021-02-22(北京)

    開班盛況
  • Python人工智能+數(shù)據(jù)分析 <高端班>

    開班時間:2021-07-12(北京)

    預(yù)約報名

    開班時間:2020-09-21(上海)

    開班盛況
  • 云計算開發(fā) <高端班>

    開班時間:2021-07-12(北京)

    預(yù)約報名

    開班時間:2019-07-22(北京)

    開班盛況
IT培訓(xùn)IT培訓(xùn)
在線咨詢
IT培訓(xùn)IT培訓(xùn)
試聽
IT培訓(xùn)IT培訓(xùn)
入學(xué)教程
IT培訓(xùn)IT培訓(xùn)
立即報名
IT培訓(xùn)

Copyright 2011-2023 北京千鋒互聯(lián)科技有限公司 .All Right 京ICP備12003911號-5 京公網(wǎng)安備 11010802035720號