淺談函數式編程

1. 前言

最近開始忙起來了,寫東西的時間愈來愈少了。這幾天開始在 Java 開發中嘗試函數式編程風格。因此就寫點小東西來分享一下。數據庫

2. 什麼是函數式編程?

在我看來函數式編程就是把函數做爲一等公民來使用。日常咱們開發都是在處理數據。面向對象中都在處理類。而函數式編程不是在寫函數就是在寫函數的路上。咱們來看看 Java 中函數式編程的演進之路。我小時候玩過一種廉價的黑白屏遊戲機,只能玩俄羅斯方塊。這種是不可擴展的。編程

public void playGame(){
         //  只能玩俄羅斯方塊
  }複製代碼

這種機器給童年帶來了很多的樂趣。後來小夥伴有了一臺gameboy,這種掌機的好處在於它能夠插卡。一張卡一個遊戲,最有名的莫過於 《超級馬里奧》 和《打磚塊》了。這時候機器是徹底可擴展的了。性能優化

public void  playGameboy(GameboyCard card){
            card.getGame().run()
      }
複製代碼

雖然能夠擴展可是卡的價格很是貴,當時買卡的渠道還不多。那時候其實就想若是能本身造 gameboy 遊戲就行了(而後我就來搞編程?)。理想中的遊戲機是咱們不關心你什麼風格的遊戲,只要你能放入符合接口的遊戲卡中而且在我這個遊戲機中跑就行。閉包

因此咱們定義了一個固定的遊戲卡接口:app

/**
 * @author Felordcn
 * @since 2019/10/31 22:13
 */
@FunctionalInterface
public interface Card {

    Game  apply();

}複製代碼

只要符合這種接口的遊戲卡都能插到機器中玩:分佈式

/**
     * Fun.
     *
     * @param card the card
     */
    void fun(Card card) {
        Game game = card.apply();
        game.run();
    }複製代碼

熟練面向對象的同窗們會說這不就是面向接口編程嗎?是的你說的沒有問題。可是這裏 Card 接口只幹一件事就是提供遊戲。咱們的重心是遊戲卡嗎?顯然不是!有趣好玩的遊戲纔是咱們的目的所在。因而咱們無論他是卡仍是光碟甚至網路,只要能提供遊戲給咱們娛樂都符合咱們的須要。函數式編程

// 玩插卡遊戲機
  fun(() -> new CardGame());
   // 玩 PSP
   fun(() -> new PSPGame());
   // more複製代碼

做爲一名碼農,日常咱們都在寫 SQL。 不管大廠小廠,無論單體仍是分佈式。SQL 總能幫咱們解決不少業務關係處理。SELECTINSERTUPDATEDELETE 每一種命令只要是 SQL 規範數據庫,不論是什麼表都會是一致的操做。你聲明瞭什麼命令就執行什麼操做。這時數據與函數是鬆耦合的。正是這樣的特色讓咱們實現了「萬變不離其宗」。這也是一種另類的函數式編程。函數

3. 面向對象和函數式編程衝突嗎?

面向對象一直處於我能操做什麼數據、這種數據我該怎麼操做的範式中。而函數式編程一直沉浸於給我操做數據的方法中。面向對象最大優勢是多態性和封裝;函數式編程優點是抽象化和聲明式命令風格,二者實際上是正交,可互補的,可在同一程序中共存。爭論是面向對象好仍是面向函數好跟爭論哪門語言好同樣都是很是極端的。對於面向對象來說:存在的並不必定都是對象,函數就是對象;對於函數式編程來講:存在的並不老是純粹的,反作用老是真實存在的。總之,面向對象側重於分解,函數編程側重於組合。性能

4. 函數式編程特色

函數風格的編程擁有本身的一些特色:學習

  • 函數做爲一等公民。 能夠做爲參數傳遞、從函數裏返回、能夠賦值給變量。
  • 帶有閉包的 Lambda 表達式和匿名函數,這是普遍的多態。
  • 不變性,大部分無態處理,在函數式程序中,變量是經過外部傳入或者申明得到值的。變量不能被改變
  • 基於不可變進而能夠無反作用的調用。
  • 經過 tail call 實現遞歸的性能優化。
  • 提供動態的、可組合的開發思路。

5. 總結

今天簡單表達了我對函數式編程的一些理解,對於習慣了面向對象的 Java 開發者來講,理解函數式編程並不容易。它不只僅有 Lambda 和匿名函數!更多的是一種思想。這裏推薦一個很好的 Java 函數式編程庫 vavr 。有興趣的同窗能夠學習下。

關注公衆號:Felordcn獲取更多資訊

我的博客:https://felord.cn

相關文章
相關標籤/搜索