java函數式編程
JAVA如果真的這么完美無缺,那為什麼還會有其他語言的興盛呢?所以說,沒有一樣東西是絕對完美的,JDK8包括之後的版本,就是不斷的完善JAVA語言,讓它往更好的方向上去走,面向過程有它的缺點,然而無疑也有它的優點,在JAVA8 之前,JAVA欠缺了高效的並行操作,寫一個並行程序代碼往往是費事費力又不討好,然而在JAVA8之上,只需要簡單的修改幾行代碼,就可以讓代碼在多核CPU上完美運行,所以為了達到這個效果,編寫這樣的JDK類庫,就需要在語言層次上修改現有的JAVA,因此,在JAVA中增加Lambda表達式就是刻不容緩的任務了--事實上在2011年的JDK7版本中預計就要引入Lambda,但是因為種種原因,計劃最終推遲到了2014年的JDK8。
為了達到高效操作集合類,實現並行計算或者操作的目的,你得要學習來自JDK8的新的語法,並且要從面相對象編程的局限中稍微跳出來一些,但是比起之前手寫一大段代碼,我覺得這樣的學習是十分值得也是十分必要的,節省了時間與成本,同時也更不容易出錯!站在巨人的肩膀上,這是任何一個人都需要借鑒的方法,為什麼每次JDK版本的變更都歷時幾年?oracle的工程師並不是傻瓜,尤其是在編寫JDK類庫上,借用他人的代碼並不是可恥的行為,新的代碼更加高效,並且更讓人容易閱讀,這種新代碼更加關注的它所實現的業務邏輯,而並非實現機制,所以你看即使是引入了Lambda,從某種意義上來說,這依舊是面向對象的一種實現方法--關注的並非實現機制,這樣的代碼更容易維護,也更不容易出錯。
B. java8 函數式編程和lambda的區別
很多編程語言早就引入了Lambda表達式而java語法又比較繁瑣,被很多人嫌棄.於是java8新增了特性支持Lambda表達式.例如:不用Lambda表達式寫的匿名內部類List names = Arrays.asList("jack", "tom", "jerry");Collections.sort(names, new Comparator() { @Override public int compare(String s1, String s2) { return s2.compareTo(s1); }});採用Lambda表達式簡化上面的代碼List names = Arrays.asList("jack", "tom", "jerry");Collections.sort(names, (s1, s2) -> s2.compareTo(s1));當然了java8中Lambda表達式還有其他用法,但我比較喜歡它的簡潔
C. java8 函數式編程是什麼
java8完全顛覆我們對java的認識了 函數式編程裡面有一點就是 把一段函數當作是一個參數來進行傳遞
D. Java8的函數式編程怎麼樣
使用函數式代碼的好處:
減少了可變數(Immutable Variable)的聲明
能夠更好的利用並行(Parallelism)
代碼更加簡潔和可讀
函數式介面
函數式介面就是僅聲明了一個方法的介面,比如我們熟悉的Runnable,Callable,Comparable等都可以作為函數式介面。當然,在Java 8中,新添加了一類函數式介面,如Function,Predicate,Consumer,Supplier等。
E. 求java8函數式編程pdf
java8完全顛覆我們對java的認識了函數式編程裡面有一點就是把一段函數當作是一個參數來進行傳遞
F. 為什麼函數式編程在Java中很危險
在許多的項目中,純函數編程,會造成一片混亂 。。。。。。。。。。
G. 函數式編程(Functional Programming)相比面向對象編程(Object
函數作為一等公民和 closure capture 好處大家都知道, 傳統語言都在想方設法集成這些特性. map, filter, rece 等等東西寫代碼處理集合真是非常舒爽, 一眼就能看懂干什麼, 又不用擔心循環中的邊界條件.
- 函數式語言中的另一個利器是 pattern match, 很多費腦子的復雜操作一下就搞定了... 為什麼 Thinking in Java 這么大這么厚一本書, 學完了你基本幹不了啥事情? 因為在 Java 的思維世界裡, 你要和概念的海洋作斗爭, 而命名恰恰就是編程的兩大難題之一. 如果有 pattern match, 哪用想這么多沒意義的中間變數名?
- 什麼是 immutability? 其實細分起來有語法上的 immutable (例如 Java 里的 final 關鍵字), 和運行時對象的 immutable (一個變數名可以修改指向不同對象, 但對象的內容不可變). 兩者的聯系是: 如果語法上規定所有變數都是 "final" 的, 那麼運行時對象就相當於都 immutable 了. 但如果語法上部分變數是 final, 部分不是, 那麼就不能得出運行時對象全都 immutable 的結論.
而在運行時對象都是 immutable 的情形下, 很多優勢才會顯現出來.
- "immutability 會拖慢程序" 略扯淡, 應用了 immutability 的 VM 實現可以去掉很多情況的 lock, 並發處理速度會更快.
就算不是並發處理的情況, 如果所有對象都 immutable, 手動的保護性拷貝都可以去掉, 處理復雜業務會更簡單快速.
其實編譯器可以把很多 immutable 的操作改寫成 mutable 的操作, RAM 能不能擦寫沒什麼影響的. LLVM 中間語言就是個變數名 immutable 的語言, 但是編譯出來的代碼效率很高 --- 編譯器就是這么賤, 你明明為了提高性能重復利用同一個變數, 但是它卻偏偏要先把你寫的單個變數改成多個變數單次賦值再去做優化...
對象實例 immutable 了 GC 能更簡化. 因為只有新對象指向老對象, 老對象不能指向新對象, 對實現分代 GC 的人來說真是一個天堂! Haskell 和 Erlang 的分代 GC 實現都不復雜而且效率很高 (但 Clojure 因為是 JVM 上的二奶語言享受不到這個優惠, Scala 不是所有對象都 immutable, 只能起用介面限製程序員的效果了...)
在 immutable 的環境里還有什麼好處? 就是沒有環引用! 不用做環檢測不用加弱引用, 那引用計數還不爽翻了? 是的... 有人用引用計數實現 Erlang 的, 寫得非常爽... 我也在寫一個語言, 所有變數 immutable, 就用引用計數做內存管理, 當引用數為 1 的時候還能做 destructive update, 節省一次內存分配釋放, 也不損害 immutable 的語義哦 (巨坑中, stay tuned...).
immutable 的環境還能輕易實現 debug step back. 至今大部分語言和環境的 debugger 都沒有後退功能, 而後退功能的實現難點主要是要保存對象變化的歷史記錄, mutable 的對象系統就得復制或者深復制對象才能恢復歷史. 而 immutable 的環境里, 只要保留之前的對象的引用, 就能直接恢復.
immutability 至今表現還不太好的地方是哈希表, 例如 Haskell 的哈希表實現就一片混亂... 如果要實現一個高效的 immutable 並且保持插入順序的哈希表... 你會比較蛋疼. 現在做得比較好的是 HAMT 或者 RRB tree, 但也沒有 mutable 的哈希錶快.
- immutable 會造成代碼比較難寫嗎? 事實上就是思維方式要改變, 用更高階的操作就好了, 然後你會發現經常變得更好寫了. 而且 state monad + do notation 可以讓你退回去用 mutable 的思維方式想問題, 而且, 這個 state 是嚴格控制在 local 的不會攪亂你其他部分的程序.
如果所有對象都 immutable, 那程序根本就沒有傳值和傳引用的區別了, 學習起來更簡單, 語義更一致 (但一心要當大雜燴的 Scala 反而變得很復雜...)
- 組件和對象會不會比 immutable 更適合 GUI 編程? 現狀是 functional language 在 GUI 庫上面還不夠成熟, 但應用 functional 概念架構的 GUI 反而速度更快更穩定, 在 web 前端框架上面已經逐漸體現了, 例如 swannodette/om · GitHub 和 Raynos/mercury · GitHub. 用 Om 實現一個歷史後退的功能真的清爽容易到了極點.
- 函數式語言中常用的 list 也受限於當前的 CPU 架構體系, locality 沒有 array 好, 不過很多 list 中使用的 idiom 也可以直接應用到 array 上, 問題不大.
- 某些面向對象的方法論使用大量的隱喻, 使得不懂的人都可以以為自己懂了, 也許才是其最重要的優勢吧.
H. 什麼是函數式編程思維
1.表達式化
在
最初的時候,需要轉變觀念,去可變數,去循環,把命令式改成表達式,注意,這只是把你丟在荒山野嶺讓你感受一下,離開熟悉的環境,地球依然在轉,但是有個
重點,那就是一切都是表達式; 為什麼是表達式呢?這個問題就像為什麼魚在水裡?
因為函數式建立在lambda演算之上而非圖靈機,只不過兩者被證明等價,所以你可以在你的機器上跑全是表達式的代碼,就如有人證明天空適合魚生存,所以
魚可以在天上游
當你接受了魚可以在天上游之後,就該上正餐了
1.5 數據與行為分離
這也是和面向對象不一致的地方,面向對象強調數據與行為綁定,但函數式不是,確切的說函數式 函數與數據等價,所以你才可以將函數當參數與返回值,你在設計時,切勿讓數據自己長腿能跑,其次,行為必須消除副作用,不可以偷偷把數據改了,習慣第一條後,應該不會的
2.高階邏輯
用
了函數式,就不要在想循環,賦值這些低階邏輯了,而應該更高階的思考問題,這比轉化表達式更難,函數式又叫聲明式,也就是你要做什麼,只要說一下就行,而
非寫個遍歷,做個狀態判斷,用函數式你不需要考慮這些,你不知道函數式的列表是怎麼遍歷的,中間向兩邊?
從後往前?這也是為何函數式適合並發的原因之一,你想知道列表中大於3的數有多少,只要,list.count(_ > 3)
而不是寫循環,你可以直接寫你的業務,不要拘泥於細節,有點像sql, 你需要什麼告訴電腦就行,你或許會問,count foreach filter
這些函數怎麼來的? 因為有了他們你才不需要寫循環,他們把你留在高階邏輯中,這個問題的答案請看下面
3.組合子邏輯 或又叫 自底向上的設計
函
數式和OO是反的,面向對象是自頂向下的設計,函數式是自底向上的設計,也就是先定義最基本的操作,然後不斷組合,不斷堆積以滿足你的所有需要,如sql
定義了select, from, where...這幾個組合子,來滿足你的查詢需求,同理函數式語言會提供foreach,
map等組合子(操作)來滿足你的需求,所以你必須自下而上的設計你的代碼結構,並且滿足你的需求,當你只用組合子寫代碼時,你會發現你寫的全是高階邏輯
如
果這些已有組合子滿足不了你,你就得自己寫,foreach不行,你就自己寫遞歸,我告訴你,遞歸背後也是組合子,這里一些'大神'應該不知道,在圖靈機
里,遞歸就是方法不斷調用自己沒什麼好說的,但是在lambda演算中,匿名函數是沒法調用自己的,所以遞歸是用Y組合子(又叫不動點組合子)把遞歸函數
自己求解出來再調用的,這才可以實現遞歸,並與圖靈機的循環等價,有點跑題了,總之要想順手的寫函數式,最好用面向組合子的設計,注意,不是必須,組合子
演算和lambda演算可以相互轉化,也就是,你完全可以寫一堆雜亂的表達式,但沒有組合子邏輯來得清爽,Haskell大規模使用monad這個特殊組
合子,始其變得統一整潔
好了,總結一下
函數式思維,其實就是組合子邏輯,用簡單的幾個函數組合來構建復雜邏輯,始終以高階的角度去表達問題,而非依賴副作用。
知道這點,你用java也可以寫函數式代碼了
I. Java函數式編程語言是什麼
函數式編程語言的核心是它以處理數據的方式處理代碼。這意味著函數應該是第一等級(First-class)的值,並且能夠被賦值給變數,傳遞給函數等等。
事實上,很多函數式語言比這走得更遠,將計算和演算法看得比它們操作的數據更重要。其中有些語言想分離程序狀態和函數(以一種看起來有點對立的方式,使用面向對象的語言,這通常會將它們聯系得更緊密)。
Clojure編程語言就是一個這樣的例子,盡管它運行於基於類的Java虛擬機,Clojure的本質是函數式語言,並且在高級語言源程序中不直接公布類和對象(盡管提供了與Java良好的互操作性)。
J. java 為什麼引入函數式介面而不是委託
一、Lambda表達式Lambda表達式可以說是Java 8最大的賣點,她將函數式編程引入了Java。Lambda允許把函數作為一個方法的參數,或者把代碼看成數據。一個Lambda表達式可以由用逗號分隔的參數列表、–符號與函數體三部分表示。例如:Arrays.asList( "p", "k", "u","f", "o", "r","k").forEach( e - System.out.println( e ) ); 1 Arrays.asList( "p", "k", "u","f", "o", "r","k").forEach( e - System.out.println( e ) ); 為了使現有函數更好的支持Lambda表達式,Java 8引入了函數式介面的概念。函數式介面就是只有一個方法的普通介面。java.lang.Runnable與java.util.concurrent.Callable是函數式介面最典型的例子。為此,Java 8增加了一種特殊的註解@FunctionalInterface:1 @FunctionalInterface2 public interface Functional {3 void method();4 }二、介面的默認方法與靜態方法我們可以在介面中定義默認方法,使用default關鍵字,並提供默認的實現。所有實現這個介面的類都會接受默認方法的實現,除非子類提供的自己的實現。例如:1 public interface DefaultFunctionInterface {2 default String defaultFunction() {3 return "default function";4 }5 }我們還可以在介面中定義靜態方法,使用static關鍵字,也可以提供實現。例如:1 public interface StaticFunctionInterface {2 static String staticFunction() {3 return "static function";4 }5 }介面的默認方法和靜態方法的引入,其實可以認為引入了C++中抽象類的理念,以後我們再也不用在每個實現類中都寫重復的代碼了。三、方法引用通常與Lambda表達式聯合使用,可以直接引用已有Java類或對象的方法。一般有四種不同的方法引用:構造器引用。語法是Class::new,或者更一般的Class T ::new,要求構造器方法是沒有參數;靜態方法引用。語法是Class::static_method,要求接受一個Class類型的參數;特定類的任意對象方法引用。它的語法是Class::method。要求方法是沒有參數的;特定對象的方法引用,它的語法是instance::method。要求方法接受一個參數,與3不同的地方在於,3是在列表元素上分別調用方法,而4是在某個對象上調用方法,將列表元素作為參數傳入;四、重復註解在Java 5中使用註解有一個限制,即相同的註解在同一位置只能聲明一次。Java 8引入重復註解,這樣相同的註解在同一地方也可以聲明多次。重復註解機制本身需要用@Repeatable註解。Java 8在編譯器層做了優化,相同註解會以集合的方式保存,因此底層的原理並沒有變化。五、擴展註解的支持Java 8擴展了註解的上下文,幾乎可以為任何東西添加註解,包括局部變數、泛型類、父類與介面的實現,連方法的異常也能添加註解。六、OptionalJava 8引入Optional類來防止空指針異常,Optional類最先是由Google的Guava項目引入的。Optional類實際上是個容器:它可以保存類型T的值,或者保存null。使用Optional類我們就不用顯式進行空指針檢查了。七、StreamStream API是把真正的函數式編程風格引入到Java中。其實簡單來說可以把Stream理解為MapRece,當然Google的MapRece的靈感也是來自函數式編程。她其實是一連串支持連續、並行聚集操作的元素。從語法上看,也很像linux的管道、或者鏈式編程,代碼寫起來簡潔明了,非常酷帥!八、Date/Time API (JSR 310)Java 8新的Date-Time API (JSR 310)受Joda-Time的影響,提供了新的java.time包,可以用來替代 java.util.Date和java.util.Calendar。一般會用到Clock、LocaleDate、LocalTime、LocaleDateTime、ZonedDateTime、Duration這些類,對於時間日期的改進還是非常不錯的。九、JavaScript引擎NashornNashorn允許在JVM上開發運行JavaScript應用,允許Java與JavaScript相互調用。十、Base64在Java 8中,Base64編碼成為了Java類庫的標准。Base64類同時還提供了對URL、MIME友好的編碼器與解碼器。除了這十大新特性之外,還有另外的一些新特性:更好的類型推測機制:Java 8在類型推測方面有了很大的提高,這就使代碼更整潔,不需要太多的強制類型轉換了。編譯器優化:Java 8將方法的參數名加入了位元組碼中,這樣在運行時通過反射就能獲取到參數名,只需要在編譯時使用-parameters參數。並行(parallel)數組:支持對數組進行並行處理,主要是parallelSort()方法,它可以在多核機器上極大提高數組排序的速度。並發(Concurrency):在新增Stream機制與Lambda的基礎之上,加入了一些新方法來支持聚集操作。Nashorn引擎jjs:基於Nashorn引擎的命令行工具。它接受一些JavaScript源代碼為參數,並且執行這些源代碼。類依賴分析器jdeps:可以顯示Java類的包級別或類級別的依賴。JVM的PermGen空間被移除:取代它的是Metaspace(JEP 122)。