亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java中如何使用Lambda表達式和函數編程

發布時間:2021-10-08 15:22:45 來源:億速云 閱讀:134 作者:iii 欄目:開發技術

本篇內容主要講解“Java中如何使用Lambda表達式和函數編程”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Java中如何使用Lambda表達式和函數編程”吧!

目錄
  • 1、簡單介紹

  • 2、Lambdas和Scopes

  • 3、Lambdas與局部變量

  • 4、Lambda體與局部變量

  • 5、Lambdas和'This'和'Super'關鍵字

  • 6、Lambdas和Exceptions

  • 7、預定義的功能接口

1、簡單介紹

第一個示例演示變量聲明上下文中的lambda。它將lambda()->{System.out.println(“running”);}分配給可運行接口類型的變量r。

第二個示例類似,但演示了賦值上下文中的lambda(到先前聲明的變量r)。

第三個示例演示了return語句上下文中的lambda。它使用指定的文件擴展名參數調用getFilter()方法以返回java.io.FileFilter對象。該對象被傳遞給java.io.File的listFiles()方法,該方法為每個文件調用過濾器,忽略與擴展名不匹配的文件。getFilter()方法返回通過lambda表示的FileFilter對象。編譯器注意到lambda滿足此函數接口的boolean accept(文件路徑名)方法(兩者都有一個參數,lambda主體返回一個布爾值),并將lambda綁定到FileFilter。

第四個示例演示了lambda在數組初始值設定項上下文中的用法。基于lambdas創建了兩個java.nio.file.PathMatcher對象。每個PathMatcher對象根據其lambda主體指定的條件匹配文件。以下是相關代碼:

final PathMatcher matchers[] =
{
  (path) -> path.toString().endsWith("txt"),
  (path) -> path.toString().endsWith("java")
};

PathMatcher函數接口提供一個boolean matches(Path path)方法,該方法與lambda的參數列表及其主體的布爾返回類型一致。隨后調用此方法以確定在訪問當前目錄和子目錄期間遇到的每個文件的匹配項(基于文件擴展名)。

第五個示例演示線程構造函數上下文中的lambda

第六個示例演示了lambda上下文中的lambda,這表明lambda可以嵌套。

第七個示例演示了三元條件表達式(?:)上下文中的lambda:根據升序或降序排序從兩個lambda中選擇一個。

第八個(也是最后一個)示例演示了強制轉換表達式上下文中的lambda。()->System.getProperty(“user.name”)lambda被強制轉換為PrivilegedAction<String>函數接口類型。此強制轉換解決了java.security.AccessController類中的歧義,該類聲明了以下方法:

static <T> T doPrivileged(PrivilegedAction<T> action)
static <T> T doPrivileged(PrivilegedExceptionAction<T> action)

問題是PrivilegedActionPrivilegedExceptionAction的每個接口都聲明了相同的T run()方法。由于編譯器無法確定哪個接口是目標類型,因此在沒有強制轉換的情況下會報告錯誤。

編譯清單4并運行應用程序。您應該觀察以下輸出,該輸出假定LambdaDemo.java是當前目錄中唯一的.java文件,并且該目錄不包含.txt文件:

running
running
Found matched file: '.\LambdaDemo.java'.
running
called
Washington
Sydney
Rome
Ottawa
Moscow
London
Jerusalem
Berlin
jeffrey

2、Lambdas和Scopes

術語范圍是指程序中名稱與特定實體(例如變量)綁定的部分。在程序的另一部分中,名稱可能綁定到另一個實體。lambda主體不會引入新的作用域。相反,它的作用域是封閉作用域。

3、Lambdas與局部變量

lambda主體可以定義局部變量。因為這些變量被認為是封閉范圍的一部分,所以編譯器在檢測到lambda主體正在重新定義局部變量時將報告錯誤。清單5演示了這個問題。

清單5。LambdaDemo.java(版本5)

public class LambdaDemo
{
   public static void main(String[] args)
   {
      int limit = 10;
      Runnable r = () -> {
                           int limit = 5;
                           for (int i = 0; i < limit; i++)
                              System.out.println(i);
                         };
   }
}

因為limit已經存在于封閉范圍(main()方法)中,lambda主體對limit的重新定義(int limit=5;)會導致編譯器報告以下錯誤消息:錯誤:變量limit已經在方法main(字符串[])中定義。

4、Lambda體與局部變量

無論是源于lambda主體還是在封閉范圍內,局部變量在使用之前都必須初始化。否則,編譯器將報告錯誤。

在lambda主體外部定義并從主體引用的局部變量或參數必須標記為final或視為有效final(初始化后無法將該變量指定給)。試圖修改一個有效的最終變量會導致編譯器報告一個錯誤,如清單6所示。

清單6。LambdaDemo.java(版本6)

public class LambdaDemo
{
   public static void main(String[] args)
   {
      int limit = 10;
      Runnable r = () -> {
                           limit = 5;
                           for (int i = 0; i < limit; i++)
                              System.out.println(i);
                         };
   }
}

限制實際上是最終的。lambda主體試圖修改此變量會導致編譯器報告錯誤。這樣做是因為final/final變量需要掛起,直到lambda執行為止,這可能要在定義變量的代碼返回后很久才會發生。非最終/非有效最終變量不再存在。

5、Lambdas和'This'和'Super'關鍵字

lambda主體中使用的任何thissuper引用都被視為等同于其在封閉范圍中的用法(因為lambda不引入新范圍)。然而,匿名類的情況并非如此,如清單7所示。

清單7。LambdaDemo.java(版本7)

public class LambdaDemo
{
   public static void main(String[] args)
   {
      new LambdaDemo().doWork();
   }
   public void doWork()
   {
      System.out.printf("this = %s%n", this);
      Runnable r = new Runnable()
                       {
                          @Override
                          public void run()
                          {
                             System.out.printf("this = %s%n", this);
                          }
                       };
      new Thread(r).start();
      new Thread(() -> System.out.printf("this = %s%n", this)).start();
   }
}

清單7的main()方法實例化LambdaDemo并調用對象的doWork()方法來輸出對象的this引用,實例化一個實現Runnable的匿名類,創建一個線程對象,在其線程啟動時執行此Runnable,并創建另一個線程對象,其線程在啟動時執行lambda

編譯清單7并運行應用程序。您應該觀察與以下輸出類似的情況:

this = LambdaDemo@776ec8df
this = LambdaDemo$1@48766bb
this = LambdaDemo@776ec8df

第一行顯示LambdaDemo的this引用,第二行顯示新可運行范圍中不同的this引用,第三行顯示lambda上下文中的this引用。第三行和第一行匹配,因為lambda的作用域嵌套在doWork()方法中;這在整個方法中具有相同的含義。

6、Lambdas和Exceptions

lambda主體不允許拋出比函數接口方法的throws子句中指定的更多的異常。如果lambda主體拋出異常,則函數接口方法的throws子句必須聲明相同的異常類型或其超類型。考慮清單8。

清單8。LambdaDemo.java(版本8)

import java.awt.AWTException;
import java.io.IOException;
@FunctionalInterface
interface Work
{
   void doSomething() throws IOException;
}
public class LambdaDemo
{
   public static void main(String[] args) throws AWTException, IOException
   {
      Work work = () -> { throw new IOException(); };
      work.doSomething();
      work = () -> { throw new AWTException(""); };
   }
}

清單8聲明了一個工作函數接口,其doSomething()方法聲明為拋出java.io.IOException。main()方法將拋出IOExceptionlambda分配給work,這是正常的,因為IOException列在doSomething()的throws子句中。

main()接下來分配一個lambda,該lambda拋出java.awt.AWTException來工作。但是,編譯器不允許此賦值,因為AWTException不是doSomething()的throws子句的一部分(當然也不是IOException的子類型)。

7、預定義的功能接口

您可能會發現自己反復創建類似的功能接口。例如,您可以使用布爾IsConnection(連接c)方法創建CheckConnection函數接口,使用布爾isPositiveBalance(帳戶帳戶)方法創建CheckAccount函數接口。這是浪費。

前面的示例公開了謂詞(布爾值函數)的抽象概念。Oracle提供了常用功能接口的java.util.function包,以預測這些模式。例如,這個包的Predicate<T>功能接口可以用來代替CheckConnectionCheckAccount

Predicate<T>提供一個boolean test(T t)方法,該方法根據其argument (t)計算該謂詞,當T與predicate匹配時返回true,否則返回false。請注意,test()提供了與isConnected()isPositiveBalance()相同的參數列表。另外,請注意,它們都具有相同的返回類型(布爾值)。

清單9中的應用程序源代碼演示了謂詞<T>。

清單9。LambdaDemo.java(版本9)

import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
class Account
{
   private int id, balance;
   Account(int id, int balance)
   {
      this.balance = balance;
      this.id = id;
   }
   int getBalance()
   {
      return balance;
   }
   int getID()
   {
      return id;
   }
   void print()
   {
      System.out.printf("Account: [%d], Balance: [%d]%n", id, balance);
   }
}
public class LambdaDemo
{
   static List<Account> accounts;
   public static void main(String[] args)
   {
      accounts = new ArrayList<>();
      accounts.add(new Account(1000, 200));
      accounts.add(new Account(2000, -500));
      accounts.add(new Account(3000, 0));
      accounts.add(new Account(4000, -80));
      accounts.add(new Account(5000, 1000));
      // Print all accounts
      printAccounts(account -> true);
      System.out.println();
      // Print all accounts with negative balances.
      printAccounts(account -> account.getBalance() < 0);
      System.out.println();
      // Print all accounts whose id is greater than 2000 and less than 5000.
      printAccounts(account -> account.getID() > 2000 &&
                               account.getID() < 5000);
   }
   static void printAccounts(Predicate<Account> tester)
   {
      for (Account account: accounts)
         if (tester.test(account))
            account.print();
   }
}

清單9創建了一個基于數組的帳戶列表,其中有正余額、零余額和負余額。然后,它通過使用lambdas調用printAccounts()來演示謂詞<T>,以便打印出所有帳戶,僅打印出那些余額為負數的帳戶,以及僅打印出ID大于2000且小于5000的帳戶。

考慮lambda表達式帳戶->真。編譯器驗證lambda是否匹配謂詞<T>的布爾測試(T)方法,它會這樣做——lambda提供單個參數(account),其主體始終返回布爾值(true)。對于這個lambda,test()被實現為執行return true;。

編譯清單9并運行應用程序。我們能觀察以下輸出:

Account: [1000], Balance: [200]
Account: [2000], Balance: [-500]
Account: [3000], Balance: [0]
Account: [4000], Balance: [-80]
Account: [5000], Balance: [1000]
Account: [2000], Balance: [-500]
Account: [4000], Balance: [-80]
Account: [3000], Balance: [0]
Account: [4000], Balance: [-80]

Predicate<T>只是java.util.function的各種預定義函數接口之一。另一個示例是Consumer<T>,它表示接受單個參數但不返回結果的操作。與Predicate<T>不同,Consumer<T>預期通過副作用進行操作。換句話說,它以某種方式修改了它的論點。

使用者的void accept(T)方法對其argument(T)執行操作。當出現在此函數接口的上下文中時,lambda必須符合accept()方法的單獨參數和返回類型。

到此,相信大家對“Java中如何使用Lambda表達式和函數編程”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

河西区| 阿瓦提县| 昌平区| 伊通| 玉环县| 遂溪县| 宜川县| 延川县| 仲巴县| 巨野县| 旅游| 汨罗市| 涟水县| 孝义市| 霸州市| 富源县| 辽阳市| 南岸区| 大化| 招远市| 绵竹市| 曲沃县| 灵宝市| 通榆县| 固原市| 望都县| 东海县| 长沙县| 个旧市| 镇雄县| 故城县| 新津县| 革吉县| 北川| 清镇市| 扶风县| 阜康市| 福泉市| 两当县| 会东县| 抚松县|