Java8 Consumer、Supplier、Predicate、Function

来源:https://www.cnblogs.com/toutou/p/java_Function_Consumer.html
-Advertisement-
Play Games

今天我們還講講Consumer、Supplier、Predicate、Function這幾個介面的用法,在 Java8 的用法當中,這幾個介面雖然沒有明目張膽的使用,但是,卻是潤物細無聲的。為什麼這麼說呢?這幾個介面都在 java.util.function 包下的,分別是Consumer(消費型) ...


今天我們還講講Consumer、Supplier、Predicate、Function這幾個介面的用法,在 Java8 的用法當中,這幾個介面雖然沒有明目張膽的使用,但是,卻是潤物細無聲的。為什麼這麼說呢?這幾個介面都在 java.util.function 包下的,分別是Consumer(消費型)、supplier(供給型)、predicate(謂詞型)、function(功能性),相信有了後面的解釋,你應該非常清楚這個介面的功能了。那麼,下麵,我們從具體的應用場景來講講這個介面的用法!

vConsumer

Java Consumer介面來自Java 8中引入的 java.util.function包。
Consumer是一個功能介面,用來作為lambda表達式或方法引用的任務目標(傳遞一個參數執行指定的方法)。

Consumer的功能介面是一個接受單一參數並且不返回任何結果的操作。

Consumer的功能方法是accept(T t)。

Consumer具有以下方法。

1. accept : 這是Consumer功能介面的功能方法。accept 方法對給定的參數進行這一操作。

2. andThen : 此方法返回一個組合的Consumer,該Consumer先執行原始的Consumer操作,然後按照從左到右的順序執行給定的andThen操作。

功能方法:accept

功能方法accept在功能介面Consumer中的定義

void accept(T t) 

使用示例

ConsumerAccept.java

import java.util.function.Consumer;

public class ConsumerAccept {
  public static void main(String[] args) {
    Consumer<String> nameConsumer = s -> System.out.println(s); 
    
    nameConsumer.accept("Mahesh");
    nameConsumer.accept("Krishna");
  }
} 

輸出

Mahesh
Krishna 

使用Lambda表達式創建Consumer
可以使用lambda表達式創建Consumer。

例1 基礎類型操作
在我們的示例中,我們將使用lambda表達式在此處創建兩個Consumer。

一個用於將數字添加到列表的方法,如果數字為奇數,則將添加到具有奇數的列表中;如果數字為偶數,則將其添加到具有偶數的另一個列表中。

ConsumerLambda1.java

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

public class ConsumerLambda1 {
  public static void main(String[] args) {
    List<Integer> oddList = new ArrayList<>();
    List<Integer> evenList = new ArrayList<>();
    
    Consumer<Integer> storeNumber = n -> {
       if (n % 2 == 0) {
         evenList.add(n);
       } else {
         oddList.add(n);
       }
    };
    
    Consumer<List<Integer>> printList = list -> list.forEach(n -> System.out.println(n));
    
    storeNumber.accept(10);
    storeNumber.accept(15);
    storeNumber.accept(25);
    storeNumber.accept(30);
    
    System.out.println("--- Odd number ---");
    
    printList.accept(oddList);
    
    System.out.println("--- Even number ---");
    
    printList.accept(evenList);
  }
} 

輸出結果

--- Odd number ---
15
25
--- Even number ---
10
30 

例2 對象類型操作

我們將使用lambda表達式創建一個Consumer,它將決定並顯示一個公民在選舉中是否可以投票的數據。

ConsumerLambda2.java

import java.util.function.Consumer;

public class ConsumerLambda2 {
  public static void main(String[] args) {
     Consumer<Citizen> electionConsumer = c -> {
       if (c.getAge() < 18) {
         System.out.println(c.getName() + " is not eligible to vote.");
       } else {
         System.out.println(c.getName() + " can vote.");
       }
     };
     
     electionConsumer.accept(new Citizen("Ritesh", 15));
     
     electionConsumer.accept(new Citizen("Shreya", 20));
  }
}

class Citizen {
  private String name;
  private int age;

  public Citizen(String name, int age) {
    this.name = name;
    this.age = age;
  }

  public String getName() {
    return name;
  }

  public int getAge() {
    return age;
  }
} 

輸出結果

Ritesh is not eligible to vote.
Shreya can vote. 

使用方法引用創建Consumer
Consumer可以使用方法引用來創建。

在我們的例子中,我們有一個有兩個方法的實用類Utility,其中一個方法將替換Map中的值,第二個方法顯示Map中的數據。我們將使用方法引用來創建Consumer。

ConsumerMethodRef.java

import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;

public class ConsumerMethodRef {
  public static void main(String[] args) {
    Map<Integer, String> persons = new HashMap<Integer, String>();
    persons.put(101, "Mahesh");
    persons.put(102, "Krishna");

    Consumer<Map<Integer, String>> updatePersons = Utility::updateData;

    Consumer<Map<Integer, String>> displayPersons = Utility::displayData;

    updatePersons.accept(persons);

    displayPersons.accept(persons);
  }
}

class Utility {
  static void updateData(Map<Integer, String> persons) {
    persons.replaceAll((k, v) -> "Shree ".concat(v));
  }

  static void displayData(Map<Integer, String> persons) {
    for (Map.Entry<Integer, String> entry : persons.entrySet()) {
      System.out.println(entry.getKey() + " - " + entry.getValue());
    }
  }
} 

輸出結果

101 - Shree Mahesh
102 - Shree Krishna 

使用andThen方法

Java文檔中andThen方法聲明。

default Consumer<T> andThen(Consumer<? super T> after) 
  1. 這個方法返回一個組合的Consumer,先執行當前Consumer操作,然後再執行afterConsumer操作。
  2. 如果在此操作或操作之後有異常,則將其中繼到當前組合操作。
  3. 如果這個操作出現異常,那麼後面的操作將不會被執行。

例1 簡單拼接Consumer

我們的示例中有兩個Consumer

首先將執行squareConsumer,然後將執行printConsumer

ConsumerAndThen1.java

import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;

public class ConsumerAndThen1 {
  public static void main(String[] args) {
    List<Integer> numList = Arrays.asList(3, 4, 5, 6);

    Consumer<List<Integer>> squareConsumer = list -> {
      for (int i = 0; i < list.size(); i++) {
        list.set(i, list.get(i) * list.get(i));
      }
    };

    Consumer<List<Integer>> printConsumer = list -> list.forEach(n -> System.out.println(n));

    squareConsumer.andThen(printConsumer).accept(numList);
  }
} 

 輸出

9
16
25
36 

 

例2 多個拼接Consumer

我們多次使用andThen。首先將執行oddNumConsumer,然後將執行evenNumConsumer,然後將執行taskFinishConsumer

ConsumerAndThen2.java

import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;

public class ConsumerAndThen2 {
  public static void main(String[] args) {
    List<Integer> list = Arrays.asList(12, 13, 14, 15, 16, 17);

    Consumer<List<Integer>> oddNumConsumer = MyNumber::printOddNum;

    Consumer<List<Integer>> evenNumConsumer = MyNumber::printEvenNum;

    Consumer<List<Integer>> taskFinishConsumer = MyNumber::taskFinishMsg;

    oddNumConsumer.andThen(evenNumConsumer).andThen(taskFinishConsumer).accept(list);
  }
}

class MyNumber {
  static void printOddNum(List<Integer> myNumbers) {
    System.out.println("--- odd numbers ---");
    myNumbers.forEach(n -> {
      if (n % 2 == 1) {
        System.out.print(n + " ");
      }
    });
  }

  static void printEvenNum(List<Integer> myNumbers) {
    System.out.println("\n--- even numbers ---");
    myNumbers.forEach(n -> {
      if (n % 2 == 0) {
        System.out.print(n + " ");
      }
    });
  }

  static void taskFinishMsg(List<Integer> myNumbers) {
    System.out.println("\nTotal " + myNumbers.size() + " number processed.");
  }
} 

輸出結果

--- odd numbers ---
13 15 17 
--- even numbers ---
12 14 16 
Total 6 number processed. 

vSupplier

Java 8引入了函數式介面 Supplier 是一個無參數的函數式介面,它不接受任何輸入參數,但可以返回一個結果。它定義了一個名為 get() 的抽象方法,用於獲取結果。

下麵是Supplier<T>介面的定義:

@FunctionalInterface
public interface Supplier<T> {
    T get();
}

在函數式編程中, Supplier 介面常用於延遲計算或惰性求值。它可以用來表示一個供應商或提供者,用於生成或獲取數據。當需要獲取數據時,可以調用 Supplier 的 get() 方法來獲取結果。使用 Supplier 介面的主要優勢之一是它可以與Java 8的新特性lambda表達式結合使用。通過lambda表達式,可以以更簡潔和易讀的方式定義 Supplier 對象。

下麵是一個使用Supplier介面的示例:

import java.util.function.Supplier;

public class SupplierExample {
    public static void main(String[] args) {
        // 使用lambda表達式創建Supplier對象
        Supplier<String> supplier = () -> "你好,世界!";
        String result = supplier.get();
        // 調用get()方法獲取結果
        System.out.println(result);
    }
}
// 輸出:你好,世界!

在上面的示例中,我們使用lambda表達式創建了一個返回字元串"Hello, World!"的 Supplier 對象。然後,我們調用了 get() 方法來獲取結果,並將其列印到控制臺上。
除了簡單的返回固定值之外, Supplier 介面還可以用於生成隨機數、讀取文件、從資料庫中獲取數據等各種場景。通過實現 Supplier 介面的自定義類,我們可以根據具體需求來生成或獲取數據。

以下是其他常見用法示例:
1. 提供隨機數生成器:

Supplier<Integer> randomGenerator = () -> new Random().nextInt();
int randomNumber = randomGenerator.get();

2. 延遲載入資源:

Supplier<DatabaseConnection> connectionSupplier = () -> new DatabaseConnection();
DatabaseConnection connection = connectionSupplier.get();

3. 惰性初始化對象:

Supplier<ExpensiveObject> lazyInitializer = ExpensiveObject::new;
ExpensiveObject object = lazyInitializer.get();

總結一下,Java 8的函數式介面 Supplier 用於表示一個供應商或提供者,它不接受任何輸入參數,但可以返回一個結果。它可以與lambda表達式結合使用,用於延遲計算或惰性求值。

vPredicate

Java 8中引入了Predicate功能介面。Java Predicate表示一個參數的謂詞。Predicate是一個布爾值的函數。Java Predicate是一個功能介面,屬於java.util.function包。Predicate的功能方法是test(T t)。Predicate的其他方法是isEqual、and、or、negate和not。not方法在Java 11中被引入。

        Predicate<Integer> predicate = new Predicate<Integer>() {
            @Override
            public boolean test(Integer integer) {
                if(integer > 5){
                    return true;
                }else{
                    return false;
                }
            }
        };
        System.out.println(predicate.test(6)); // true
        Predicate<Integer> predicate2 = (t) -> t > 5;
        System.out.println(predicate2.test(1)); // false
        Predicate<String> isUserNameValid = u -> u != null && u.length() > 5 && u.length() < 10;
        System.out.println(isUserNameValid.test("Mahesh")); // true

vFunction

函數式介面(Functional Interface)就是一個有且僅有一個抽象方法,但是可以有多個非抽象方法的介面。且用@Function標簽標記的介面。Java8 新增加的函數介面在 java.util.function 包下,它包含了很多類,用來支持 Java 的函數式編程。

Function< T , R >

函數產生給定數據類型的結果,並接受一個參數作為給定數據類型,T參數類型,R是結果類型。Function 介面是一個功能型介面,它的一個作用就是轉換作用,將輸入數據轉換成另一種形式的輸出數據。

        Function<Integer,String> ob = f1 -> "Age:"+f1;
        System.out.println(ob.apply(20)); // 輸出:Age:20
        Function<String, Integer> function = new Function<String, Integer>() {
            @Override
            public Integer apply(String s) {
                return s.length();//獲取每個字元串的長度,並且返回
            }
        };

        Stream<String> stream = Stream.of("qqq", "wwwww", "eeeeee");
        Stream<Integer> stream1 = stream.map(function);
        stream1.forEach(System.out::println);

其他參考/學習資料:

v源碼地址

https://github.com/toutouge/javademosecond/tree/master/hellolearn


作  者:請叫我頭頭哥
出  處:http://www.cnblogs.com/toutou/
關於作者:專註於基礎平臺的項目開發。如有問題或建議,請多多賜教!
版權聲明:本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接。
特此聲明:所有評論和私信都會在第一時間回覆。也歡迎園子的大大們指正錯誤,共同進步。或者直接私信
聲援博主:如果您覺得文章對您有幫助,可以點擊文章右下角推薦一下。您的鼓勵是作者堅持原創和持續寫作的最大動力!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 多線程在訪問同一個共用變數時很可能會出現併發問題,特別是在多線程對共用變數進入寫入時,那麼除了加鎖還有其他方法避免併發問題嗎?本文將詳細講解 ThreadLocal 的使用及其源碼。 ...
  • 根據不同場景使用不同方案進行實現尤為必要。通常開發過程中,文件較小,直接將文件轉化為位元組流上傳到伺服器,但是文件較大時,用普通的方法上傳,顯然效果不是很好,當文件上傳一半中斷再次上傳時,發現需要重新開始,這種體驗不是很爽,下麵介紹幾種好一點兒的上傳方式。 這裡講講如何在Spring bo... ...
  • Stirling-PDF —— 一個基於 Web 的 PDF 操作工具,支持對 PDF 文件進行各種操作,包括分割、合併、轉換、重組、添加圖像、旋轉、壓縮等。 ...
  • 1 開源解析和拆分文檔 第三方工具去對文件解析拆分,將文件內容給提取出來,並將我們的文檔內容去拆分成一個小的chunk。常見的PDF word mark down, JSON、HTML。都可以有很好的一些模塊去把這些文件去進行一個東西去提取。 1.1 優勢 支持豐富的文檔類型 每種文檔多樣化選擇 與 ...
  • 正文 21 日正是周五,夏至。全年當中,白天時長最長的一天。而恰好那天也是銀行扣息的日子。所以很忙,我差點沒能走掉。 所幸最終還是有驚無險。 到斯的家裡,是晚上 9 點鐘。比我想得要早。這個周周四,他過生日。但是那天因為上班,所以移到了周末。不是法定節假日,很普通的一個周末。全年有很多個這樣的周末。 ...
  • 大模型在一定程度上去改變了我們生活生工作的思考的方式,然後也越來越多的個人還有企業在思考如何將大模型去應用到更加實際的呃生產生活中去,希望大語言模型能夠呃有一些更多企業級別生產落地的實踐,然後去幫助我們解決一些業務上的問題。目前 1 LLM的問題 1.1 幻覺 LLM因為是一個預訓練模型,它已有一些 ...
  • SingleStringMathTex是Mobjects分類中用來顯示數學公式的class。manim中有3個可以用來顯示數學公式的class,還有兩個是MathTex和Tex,後續再介紹。 從SingleStringMathTex的名稱中也可以看出,它是用來顯示只有一行的簡單公式。SingleSt ...
  • 1 模型 來看兩種不同類型的模型--LLM 和聊天模型。然後,它將介紹如何使用提示模板來格式化這些模型的輸入,以及如何使用輸出解析器來處理輸出。 LangChain 中的語言模型有兩種類型: 1.1 Chat Models 聊天模型通常由 LLM 支持,但專門針對會話進行了調整。提供者 API 使用 ...
一周排行
    -Advertisement-
    Play Games
  • 一:背景 1. 講故事 前些天有位朋友找到我,說他們的程式會偶發性的卡死一段時間,然後又好了,讓我幫忙看下怎麼回事?窗體類的程式解決起來相對來說比較簡單,讓朋友用procdump自動抓一個卡死時的dump,拿到dump之後,上 windbg 說話。 二:WinDbg 分析 1. 主線程在做什麼 要想 ...
  • 功能說明 使用ListView時,希望可以在單元格顯示圖片或其他控制項,發現原生的ListView不支持,於是通過拓展,實現ListView可以顯示任意控制項的功能,效果如下: 實現方法 本來想著在單元格裡面實現控制項的自繪的,但是沒找到辦法,最後是通過在單元格的錶面顯示對應控制項的,浮於錶面達到目的。 實 ...
  • 由於.NET Framework 4.0 是比較古老的版本,只有New Relic 7.0以下的版本才會支持.NET Framework 4.0的引用程式。 Technical support for .NET Framework 4.0 or lower 你可以參考這個官方Install New ...
  • 前言 隨著 DEV24.1.3 的發佈,XAF Blazor 中的屬性編輯器(PropertyEditor)也進行了很大的改動,在使用體驗上也更接近 WinForm 了,由於進行了大量的封裝,理解上沒有 WinForm 直觀,所以本文通過對屬性編輯器的原理進行解析,並對比新舊版本中的變化,使大家能夠 ...
  • OPC基金會提供了OPC UA .NET標準庫以及示常式序,但官方文檔過於簡單,光看官方文檔和示常式序很難弄懂OPC UA .NET標準庫怎麼用,花了不少時間摸索才略微弄懂如何使用,以下記錄如何從一個控制台程式開發一個OPC UA伺服器。 安裝Nuget包 安裝OPCFoundation.NetSt ...
  • 今天在技術群里,石頭哥向大家提了個問題:"如何在一個以System身份運行的.NET程式(Windows Services)中,以其它活動的用戶身份啟動可互動式進程(桌面應用程式、控制台程式、等帶有UI和互動式體驗的程式)"? 我以前有過類似的需求,是在GitLab流水線中運行帶有UI的自動化測試程 ...
  • .Net 中提供了一系列的管理對象集合的類型,數組、可變列表、字典等。從類型安全上集合分為兩類,泛型集合 和 非泛型集合,傳統的非泛型集合存儲為Object,需要類型轉。而泛型集合提供了更好的性能、編譯時類型安全,推薦使用。 ...
  • 在以前我做程式的時候,一般在登錄視窗裡面顯示程式名稱,登錄視窗一般設置一張背景圖片,由於程式的名稱一般都是確定的,所以也不存在太大的問題,不過如果客戶定製不同的系統的時候,需要使用Photoshop修改下圖層的文字,再生成圖片,然後替換一下也可以了。不過本著減少客戶使用繁瑣性,也可以使用空白名稱的通... ...
  • 一:背景 1. 講故事 在dump分析的過程中經常會看到很多線程卡在Monitor.Wait方法上,曾經也有不少人問我為什麼用 !syncblk 看不到 Monitor.Wait 上的鎖信息,剛好昨天有時間我就來研究一下。 二:Monitor.Wait 底層怎麼玩的 1. 案例演示 為了方便講述,先 ...
  • 目錄前言學習參考過程總結: 前言 做個自由仔。 學習參考 ChatGpt; https://www.cnblogs.com/zhili/p/DesignPatternSummery.html(大佬的,看了好多次) 過程 原由: 一開始只是想查查鏈式調用原理,以為是要繼承什麼介面,實現什麼方法才可以實 ...