java進階知識--Lambda表達式、遞歸


一、Lambda表達式

 1.1 概述

  Lambda表達式是JDK 1.8的重量級新特性,它強調做什么,而不是以什么形式去做,或者說它強調結果,而不是過程。而這種思想我們稱之為函數式編程思想。

  函數式編程思想與面向對象思想的對比:

  •  面向對象的思想: 做一件事情,找一個能解決這個事情的對象,調用對象的方法,完成事情。
  •  函數式編程思想: 只要能獲取到結果,誰去做的,怎么做的都不重要,重視的是結果,不重視過程。

  Lambda的使用前提

    1. 使用Lambda必須具有接口,且要求接口中有且僅有一個抽象方法。(有且僅有一個抽象方法的接口,稱為“函數式接口”。
      無論是JDK內置的RunnableComparator接口還是自定義的接口,只有當接口中的抽象方法存在且唯一時,才可以使用Lambda。

    2. 使用Lambda必須具有上下文推斷
      也就是方法的參數或局部變量類型必須為Lambda對應的接口類型,才能使用Lambda作為該接口的實例。

 1.2 體驗Lambda的更優寫法

  傳統寫法

    當需要啟動一個線程去完成任務時,通常會通過java.lang.Runnable接口來定義任務內容,並使用java.lang.Thread類來啟動該線程。

    代碼如下:

public class DemoRunnable {
  public static void main(String[] args) {
    // 匿名內部類
    Runnable task = new Runnable() {
      @Override
      public void run() { // 覆蓋重寫抽象方法
        System.out.println("多線程任務執行!");
      }
    };
    new Thread(task).start(); // 啟動線程
  }
}

  Lambda的更優寫法

    借助Java 8的全新語法,上述Runnable接口的匿名內部類寫法可以通過更簡單的Lambda表達式達到等效:

public class DemoLambdaRunnable {
  public static void main(String[] args) {
    new Thread(() -> System.out.println("多線程任務執行!")).start(); // 啟動線程
  }
}

    這兩段代碼的執行效果是完全一樣的,可以在1.8或更高的編譯級別下通過。

    從Lambda寫法的代碼語義中可以看出:我們啟動了一個線程,而線程任務的內容以一種更加簡潔的形式被指定。

  語義分析 

    仔細分析該代碼中的語義,Runnable接口只有一個run方法的定義:

    • public abstract void run();

    即制定了一種做事情的方案(其實就是一個函數):

    • 無參數:不需要任何條件即可執行該方案。

    • 無返回值:該方案不產生任何結果。

    • 代碼塊(方法體):該方案的具體執行步驟。

    同樣的語義體現在Lambda語法中,要更加簡單:

    () -> System.out.println("多線程任務執行!")
    • 前面的一對小括號即run方法的參數(無),代表不需要任何條件;

    • 中間的一個箭頭代表將前面的參數傳遞給后面的代碼;

    • 后面的輸出語句即業務邏輯代碼。

 1.3 Lambda標准格式

  Lambda表達式的標准格式為:(參數類型 參數名稱) -> { 代碼語句 }

    格式說明:

    • 小括號內的語法與傳統方法參數列表一致:無參數則留空;多個參數則用逗號分隔。

    • ->是新引入的語法格式,代表指向動作。

    • 大括號內的語法與傳統方法體要求基本一致。

 1.4 Lambda省略格式

  省略規則

    在Lambda標准格式的基礎上,使用省略寫法的規則為:

    1. 小括號內參數的類型可以省略;

    2. 如果小括號內有且僅有一個參,則小括號可以省略;

    3. 如果大括號內有且僅有一個語句,則無論是否有返回值,都可以省略大括號、return關鍵字及語句分號。

  備注:a. 大括號、return關鍵字及語句分號要么一起省略,要么都不省略。

     b. 凡是根據上下文推導出來的內容,都可省略。

  如:對下面一段代碼進行省略寫法

//Lambda標准格式
public static void main(String[] args) {
    invokeCalc(120, 130, (int a, int b) -> {
      	return a + b;
    });
}

//Lambda省略格式
public static void main(String[] args) {
   invokeCalc(120, 130, (a, b) -> a + b);
}

 

二、遞歸

 2.1 概述

  • 遞歸:指在當前方法內調用自己的這種現象。

  • 遞歸的分類:

    • 直接遞歸:方法自身調用自己;

    • 間接遞歸:A方法調用B方法,B方法調用C方法,C方法調用A方法。

  • 注意事項

    • 遞歸一定要有條件限定,保證遞歸能夠停止下來,否則會發生棧內存溢出。

    • 在遞歸中雖然有限定條件,但是遞歸次數不能太多。否則也會發生棧內存溢出。

    • 構造方法,禁止遞歸。

 2.2 案例:遞歸求階乘

  階乘:所有小於及等於該數的正整數的積。

n的階乘:n! = n * (n-1) *...* 3 * 2 * 1

  分析:這與累和類似,只不過換成了乘法運算,學員可以自己練習,需要注意階乘值符合int類型的范圍。

推理得出:n! = n * (n-1)!

  代碼實現

public class DiGuiDemo {
  	//計算n的階乘,使用遞歸完成
    public static void main(String[] args) {
        int n = 3;
      	// 調用求階乘的方法
        int value = getValue(n);
      	// 輸出結果
        System.out.println("階乘為:"+ value);
    }
	/*
  	  通過遞歸算法實現.
  	  參數列表:int 
  	  返回值類型: int 
  	*/
    public static int getValue(int n) {
      	// 1的階乘為1
        if (n == 1) {
            return 1;
        }
      	/*
      	  n不為1時,方法返回 n! = n*(n-1)!
          遞歸調用getValue方法
      	*/
        return n * getValue(n - 1);
    }
}

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM