函數式接口的使用 (Function、Predicate、Supplier、Consumer)


參考:https://blog.csdn.net/jmj18756235518/article/details/81490966

函數式接口

定義:有且只有一個抽象方法的接口

Function<T, R>: y = f(x) T: x 輸入參數, R: 返回結果,y

所有標注了@FunctionalInterface注解的接口都是函數式接口,所有標注了該注解的接口都將能用在lambda表達式上

特點:通過傳入不同的Function,實現了在同一個方法中實現不同的操作,在實際開發中可以大大減少很多重復的代碼。

例如:新增用戶的功能,用戶分為VIP和普通用戶,且有兩種不同的新增邏輯。那么此時我們就可以先寫兩種不同的邏輯。除此之外,這樣還讓邏輯與數據分離開來,我們可以實現邏輯的復用。

函數式編程與非函數式編程的區別

函數式編程: 先考慮傳入的參數,再考慮方法的實現

非函數式編程:先定義好方法,再傳入指定的參數

/**
 * 需求
 * 1.定義一個函數式接口CurrentTimePrinter,其中抽象方法void printCurrentTime(),使用注解@FunctionalInterface
 * 2.在測試類中定義static void showLongTime(CurrentTimePrinter timePrinter),該方法的預期行為是使用timePrinter打印系統當前毫秒值
 * 3.測試showLongTime(),通過lambda表達式完成需求
 */
@FunctionalInterface
public interface CurrentTimePrinter {
    void printCurrentTime();
}

測試類
public class FunctionalInterfaceTest {
    /**
     * 打印當前系統的毫秒值
     * @param timePrinter
     */
    public static void showLongTime(CurrentTimePrinter timePrinter){
        timePrinter.printCurrentTime();
    }

    public static void main(String[] args) {
        showLongTime(() -> System.out.println(System.currentTimeMillis()));
    }
}



/**
 * 需求
 * 1.定義一個函數式接口IntCalc,其中抽象方法int calc(int a , int b),使用注解@FunctionalInterface
 * 2.在測試類中定義static void getProduct(int a , int b ,IntCalc calc), 該方法的預期行為是使用calc得到a和b的乘積並打印結果
 * 3.測試getProduct(),通過lambda表達式完成需求
 */
@FunctionalInterface
public interface IntCalc {
    int calc(int a , int b);
}

測試類:
/**
 * 需求
 * 定義static void getProduct(int a , int b ,IntCalc calc), 該方法的預期行為是使用calc得到a和b的乘積並打印結果
 */
public class FunctionalInterfaceTest02 {
    static void getProduct(int a , int b ,IntCalc calc){
       int result = calc.calc(a, b);
        System.out.println(result);
    }

    public static void main(String[] args) {
        getProduct(2,3, (a, b) -> a*b);
    }
}

靜態方法的引用

/**
 * 1.定義一個函數式接口NumberToString,其中抽象方法String convert(int num),使用注解@FunctionalInterface
 * 2.在測試類中定義static void decToHex(int num ,NumberToString nts), 
 * 該方法的預期行為是使用nts將一個十進制整數轉換成十六進制表示的字符串,tips:已知該行為與Integer類中的toHexString方法一致
 * 3.測試decToHex (),使用方法引用完成需求
 */
@FunctionalInterface
public interface NumberToString {
    String convert(int num);
}

測試類

public class FunctionalInterfaceTest03 {
    /**
     * 需求:
     * 在測試類中定義static void decToHex(int num ,NumberToString nts),
     * 該方法的預期行為是使用nts將一個十進制整數轉換成十六進制表示的字符串,tips:已知該行為與Integer類中的toHexString方法一致
     */
    public static void main(String[] args) {
        //NumberToString類的方法的實現使用了Integer 類的toHexString 方法
        decToHex(999, Integer::toHexString);
    }
    public static void decToHex(int num ,NumberToString nts){
        String convert = nts.convert(num);
        System.out.println(convert);
    }
}

使用函數式編程來實現延遲加載

Predicate的使用(構造斷言式):

簡介:predicate是一個接口,含有一個抽象方法test(),含有4個由default修飾的具體實現方法and()、or()、negate()、isEquals()

and()對應java的連接符 &&;

or()對應java的連接符 || ;

negate()對應java的連接符 ! ;

isEquals對應java的連接符 == ;

package com.test.stream;

/**
 * @program: basic-java
 * @Author:chenxuebing
 * @Date:2019-09-16 9:25
 * @Description:(描述)
 */

import java.util.function.Predicate;

/**
 * 需求:1.請在測試類main方法中完成以下需求
 * 已知有Integer[] arr = {-12345, 9999, 520, 0,-38,-7758520,941213}
 * a)使用lambda表達式創建Predicate對象p1,p1能判斷整數是否是自然數(大於等於0)
 * b)使用lambda表達式創建Predicate對象p2,p2能判斷整數的絕對值是否大於100
 * c)使用lambda表達式創建Predicate對象p3,p3能判斷整數是否是偶數
 *
 * 	遍歷arr,僅利用已創建的Predicate對象(不使用任何邏輯運算符),完成以下需求
 * i.打印自然數的個數
 * ii.打印負整數的個數
 * iii.打印絕對值大於100的偶數的個數
 * iv.打印是負整數或偶數的數的個數
 */
public class Test01 {
    public static void main(String[] args) {
        Integer[] arr = {-12345, 9999, 520, 0,-38,-7758520,941213};
        Predicate<Integer> p1 = (t) -> t >= 0;
        Predicate<Integer> p2 = (t) -> Math.abs(t) > 100;
        Predicate<Integer> p3 = (t) -> t % 2 == 0;
        int count1 = 0;
        int count2 = 0;
        int count3 = 0;
        int count4 = 0;
        for(int a : arr){
            //自然數個數
            if(p1.test(a)){
               count1++;
            }
            //絕對值大於100的偶數的個數
            if(p2.and(p3).test(a)){
                count2++;
            }
            //負整數的個數
            if(p1.negate().test(a)){
                count3++;
            }
            //負整數或偶數的數的個數
            //先找滿足條件的負整數,再找滿足條件的偶數,然后取交集,p1.negate(),!p1.test(),p3.test()取交集
            if(p1.negate().or(p3).test(a)){
                count4++;
            }
        }
        System.out.println("自然數"+ count1);
        System.out.println("絕對值大於100的偶數的個數"+ count2);
        System.out.println("負整數的個數"+ count3);
        System.out.println("負整數或偶數的數的個數"+ count4);
    }
}

Function接口的使用

簡介:含有一個抽象方法R apply(T t), 兩個default修飾的實現了的方法compose(), andThen()

特點:

f1.compose(f2).apply(T) : 先執行f2.apply(T), 再執行f1.apply(f2.apply(T))

compose接收一個Function參數,返回時先用傳入的邏輯執行apply,然后使用當前Function的apply

f1.andThen(f2).apply(T): 先執行f1.apply(T) , 再執行分f2.apply(f1.apply(T))

andThen跟compose正相反,先執行當前的邏輯,再執行傳入的邏輯。

/**
 * 需求
 * 1.使用lambda表達式分別將以下功能封裝到Function對象中
 * a)求Integer類型ArrayList中所有元素的平均數
 * b)將Map<String,Integer>中value存到ArrayList<Integer>中
 * 2.已知學生成績如下
 * 姓名	成績
 * 岑小村	59
 * 谷天洛	82
 * 渣渣輝	98
 * 藍小月	65
 * 皮幾萬	70
 * 3.以學生姓名為key成績為value創建集合並存儲數據,使用剛剛創建的Function對象求學生的平均成績
 */
public class FunctionTest {
    public static void main(String[] args) {
        //使用Lambda表達式求Integer類型ArrayList中所有元素的平均數
        Function<ArrayList<Integer>, Integer> f1 = (list) -> {
            int sum = 0;
            int count = 0;
            for(Integer score : list){
                sum += score;
                count++;
            }
            return sum/count;
        };
        //使用Lambda表達式將Map<String,Integer>中value存到ArrayList<Integer>中
        Function<Map<String, Integer>, ArrayList<Integer>> f2 = (map) -> {
            ArrayList<Integer> scoreList = new ArrayList<>();
            Collection<Integer> values = map.values();
            for(Integer score : values){
                scoreList.add(score);
            }
            return scoreList;
        };

        //以學生姓名為key成績為value創建集合並存儲數據
        Map<String,Integer> map = new HashMap<String, Integer>();
        map.put("岑小村", 59);
        map.put("谷天洛", 82);
        map.put("渣渣輝", 98);
        map.put("藍小月", 65);
        map.put("皮幾萬", 70);
        //使用剛剛創建的Function對象求學生的平均成績
        //f1.compose(f2).apply(map),先求f2.apply(map),再求     f1.apply(f2.apply(map)),f2.apply(map)的返回值作為f1的apply的參數值
        int averge = f1.compose(f2).apply(map);
        System.out.println(averge);
    }

}

Supplier接口(生產者)

簡介:Supplier函數式接口

        T get()抽象方法,返回一個T類型的對象

import java.util.function.Supplier;

/**
 * Supplier函數式接口
 * 抽象方法 T get(): 返回一個T類型的對象
 */
public class SupplierTest {
    //Supplier<String> supplier 的泛型為String,那么它的get 方法返回對象也是一個String類型
    public static String getString(Supplier<String> supplier){
        return supplier.get();
    }

    public static void main(String[] args) {
        //若方法體只有一條語句可以省略{} 和 return
        String result = getString(() -> "胡歌");
        System.out.println(result);
    }
}

Consumer接口(消費者)

import java.util.function.Consumer;

/**
 * Consumer函數式編程接口
 * void accept(T t)方法, 用來做消費
 */
public class ConsumerTest {
    //對String類型的對象進行消費
    public static void method(String name, Consumer<String> consumer){
        consumer.accept(name);
    }

    public static void main(String[] args) {
        //對name,進行消費,反轉打印姓名
        method("趙麗穎", name -> {
           StringBuilder builder = new StringBuilder();
           builder.append(name);
            System.out.println(builder.reverse().toString());
        });
    }
}

andThen()方法

/**
 * andThen(Consumer)
 * consumer1.andThen(consumer2).accept(T)
 * 先執行consumer1.accept(T),再執行consumer2.accept(T),因為T是對象,consumer1對對象進行消費后對象發生變化
 * 隨着consumer2消費的對象是consumer1消費后的對象
 */
public class ConsumerAndThenTest {
    public static void method (int[] arr, Consumer<int[]> consumer1, Consumer<int[]> consumer2){
        consumer1.andThen(consumer2).accept(arr);
    }

    public static void main(String[] args) {
        method(new int[]{1, 3, 5, 6},
                //將數組的第一個元素改為0
                arr -> {
                    System.out.println( arr[1] = 0);
                    System.out.println(arr.toString());
                },// 0, 3, 5, 6
                //將數組的第一個元素改為1
                arr -> {
                    System.out.println(arr[2] = 2); // 2, 3, 5, 6
                    System.out.println(arr[1]);
                }
                );
    }
}


免責聲明!

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



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