1. 程式人生 > 實用技巧 >Lambda表示式、函數語言程式設計思想概述

Lambda表示式、函數語言程式設計思想概述

Lambda表示式

  y = x + 1,在數學中,函式就是有輸入量,輸出量的一套計算方案;也就是“拿什麼東西,做什麼事情”。相對而言,面向物件過程過分強調“必須通過物件的形式來做事情”,而函數語言程式設計思想則儘量忽略面向物件的複雜語法---強調做什麼,而不是以什麼方式來做。

面向物件的思想:

  做一件事情,找一個能解決這個事情的物件,呼叫物件的方法來完成事情。

函數語言程式設計的思想:

  只要能獲得這個事情的結果,誰去做的,怎麼做的都不重要,重視的是結果,不重視過程。

冗餘的Runnable程式碼

  當需要啟動一個執行緒去完成項任務時,通常會通過Runnable介面來定義任務內容,並且使用Thread類來啟動執行緒。

程式碼如下:

 public static void main(String[] args) {       
        // 簡化程式碼
		new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println(Thread.currentThread().getName() + "----->新執行緒被建立了!");
			}
		}).start();
 }   

函數語言程式設計思想

  強調的是做什麼,而不是以什麼樣的方式來做,它忽略了面向物件的複雜語法,只要能夠獲取到結果,誰去做的,怎麼做的,
都不重要,重要的是結果,不重視過程。

冗餘的Runnable程式碼

傳統的寫法

public class Demo01Runnable {
      public static void main(String[] args) {
            //匿名內部類的方式
                  new Thread(new Runnable() {
                        @Override
                        public void run(){
                              System.out . println("開啟了一個新的執行緒任務");
                        }
                  }).start();//啟動新執行緒
            }
     }

程式碼分析:

對於Runnable的匿名內部類用法,可以分析出一下內容:

  • Thread類需要Runnable介面作為引數,其中抽象方法run用來指定執行緒任務內容的核心。

  • 為了指定run方法的方法體,不得不需要Runnable介面的實現類

  • 為了省去對義一個Runnablelmpl實現類的麻煩,不得不使用匿名內部類。

  • 必須重寫抽象方法run方法,所以方法的名稱、方法的引數、方法的返回值不得不再寫一遍,且不能寫錯。

  • 從這裡面可以,只有方法體才是執行緒任務的關鍵性內容

以程式設計思想的轉換

做什麼,而不是怎麼做

我們真正希望做的事情是:將run方法體的程式碼傳遞給Thread類知曉能夠載入到即可。

傳遞一段程式碼---這是我們真正的目的。

我們需要將程式關注的重點從怎麼做迴歸到做什麼,過程和形式並不重要。

體驗Lambda表示式的更優寫法

Java8的新特性,優化剛才的程式碼


public class Demo01Runnable {
      public static void main(String[] args) {
            //使用Lambda表示式的方式
            new Thread(() -> {
                  System.out.println("開啟了一個新的執行緒任務");
              }
            ).start();//啟動新執行緒
      }
}

從上面的程式碼可以看出:沒有建立介面實現類物件的操作,也不再有抽象方法覆蓋重寫的操作,只寫了執行緒任務的內容。

從上面的程式碼能夠推匯出Lambda的語法:

() -> System.out.println("開啟了一個新的執行緒任務")
  • 前面的一對小括號即run方法, 引數為無,裡面是空的,此時需要任何的條件

  • 中間的一個箭頭代表將前面的引數傳遞給後面的程式碼

  • 後面的輸出語句即業務邏輯程式碼(執行緒任務內容)

Lambda的標準格式

格式由三個部分組成:

  • 一些引數

  • 一個箭頭

  • 一段程式碼

Lambda表示式的標準格式:

(引數型別1多數名稱1,引數型別2引數名稱.... ->{程式碼語句}

格式說明:

  • 小括號的語法與傳統方法引數列表一致,無引數則置空,多個引數則用逗號隔開

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

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

練習:

定義一段廚子介面,該介面內內建了一個做飯的方法(抽象的方法),且無引數,無返回值,使用Lambda表示式,列印輸出“我今天吃的是紅燒茄子,吃的好開心”

public interface Chuzi {
	//定義一個無參二u返回的方法
	public abstract void zuofan() ;
	
}

public class TestChuzi {
	
	  public static void main(String[] args) {
	    	  
	    	invokeFood(() -> {
	    	     System.out.println( "我今天吃的是紅燒茄子,吃的好開心");
	    	  });
	  }
	
	   //定義一個方法, 引數的型別Cook介面,方法內部做- -個呼叫makeFood()
	   public static void invokeFood(Chuzi cook) {
		   cook.zuofan();
	   }

}

練習2:使用陣列儲存多個學生物件,對陣列中的學生物件使用Arrays的sort方法通過年齡進行升序排序。使用L ambda表示式來實現以上需求。

public class Student {

	private String name;
	private Integer age;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + "]";
	}
	public Student(String name, Integer age) {
		super();
		this.name = name;
		this.age = age;
	}
	
}

//第二個類
public class Demo01Student{
      public static void main(String[] args){
            //使用陣列儲存多個學生物件
            Student[] students = {new Student("小孫",20),new Student("小劉",18),new Student("小王",25),new Student("小趙",15)}
            //1.傳統的寫法 匿名內部類方式
            Arrays.sort(students,new Comparator<>(Student){
                  @Override
                  public int compare(Student s1,Student s2){
                        return s1.getAge()-s2.getAge();
                  }
            });

            //2.使用Lambda表示式 簡化匿名內部類
            Arrats.sort(students,(Student s1,Student s2)->{
                  return s1.getAge()-s2.getAge(); 
           });

            //3.使用Lambda表示式的省略寫法
            Arrays.sort(students,(s1,s2)->s1.getAge()-s2.getAge());

            for(Student student : students){
                  System.out.println(student);
            }
      }
}

練習3:給定一個計算器介面, 內建了一個抽象方法計算的方法,可以將兩個double型別的數字相加得到和值。使用.ambda表達
式來實現以上需求。(有參有返回)

public interface Jisuanj{
      double sum(double a,double b);
}

public class Jisuan{
      public static void main(String[] args){
            invokeSum(3.14,3.15,(double a,double b)->{
                  return a+b;
            });
      }
      //定義一個方法
	/*
	 * 引數傳遞兩個double值,再傳遞一個介面
	 * 方法內呼叫方法
	 */
      public static void invokeSum(double a,double b,Jisuanj ji){
            double sum = ji.sum(a,b);
            System.out.println("a+b="+sum);
      }
}

Lambda省略格式

可推導即可省略

Lambda強詢的是“做什麼”,而不是“怎麼做”,所以凡是可以根據上下文推導得知的資訊,都可以省略。比如:

invokeSum(3.14, 3.15, (double d1,double d2) -> {
            return d1 + d2;
      });
//省略格式表達
invokeSum(3.14,3.15, (d1,d2) -> d1 + d2);

省略的規則:

在Lambda標準格式的表示式的基礎上,使用省略寫法的規則是:

  1. 小括號內參數的型別可以省略。

  2. 如果小括號內有且只有一個引數,則小括號也可以省略。

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

Lambda的使用前提

Lambda的語法非常的簡潔,使用非常的簡單,但是有以下注意事項:

  1. 使用L ambda必須具有介面,且要求介面中有且僅有一個抽象方法
      無論JDK內建的Runnable、Comparator介面還是自定 義的介面,只有當介面中的抽象方法存在且唯一, 才可以使用Lambda

  2. 使用Lambda必須具有上下文推斷。
      也就是方法的引數或器區域性變數型別必須為Lambda對應的介面型別,才能使用Lambda作為該介面的例項。

備註:有且僅有一個抽象方法的介面,稱為函式的介面