Java8函數(shù)式接口詳解

函數(shù)式接口

Lambda表達(dá)式需要接口的支持汉操,并且接口的抽象方法還只能有一個(gè),要么沒法區(qū)分實(shí)現(xiàn)的是哪一個(gè)抽象方法了蒙兰。因此Lambda表達(dá)式需要函數(shù)式接口的支持搜变。

什么是函數(shù)式接口

接口中只有一個(gè)抽象方法的接口稱為函數(shù)式接口。

函數(shù)式接口可以使用一個(gè)注解@FunctionalInterface修飾愉耙,此注解可以檢查是否是函數(shù)式接口

函數(shù)式接口的使用

假設(shè)我們現(xiàn)在有一個(gè)需求:對(duì)一個(gè)數(shù)進(jìn)行運(yùn)算赌渣,什么運(yùn)算都可以坚芜。如果我們想用Lambda表達(dá)式來實(shí)現(xiàn)的話,我們就需要一個(gè)接口來支持,下面我們先寫一個(gè)MyFunction接口

@FunctionalInterface
public interface MyFunction {
    public Integer getValue(Integer num);
}

然后我們需要一個(gè)運(yùn)算的方法

//運(yùn)算方法
public Integer operation(Integer num, MyFunction fun){
    return fun.getValue(num);
}

測(cè)試類

@Test
public void test06(){
    //平方運(yùn)算
    Integer num = operation(10,(x) -> x*x);
    System.out.println(num);
    
    //加和運(yùn)算
    Integer num2 = operation(100,(y) -> y+200);
    System.out.println(num2);
}

執(zhí)行結(jié)果

100
300

不管是什么運(yùn)算缚忧,我們只需要關(guān)注Lambda表達(dá)式的方法體如何實(shí)現(xiàn)運(yùn)算就可以了悟泵。

Java8內(nèi)置的四大核心函數(shù)式接口

接口 參數(shù) 返回 中文 實(shí)例
Supplier None T 提供者 工廠方法創(chuàng)建對(duì)象
Consumer T None 消費(fèi)者 消費(fèi)一個(gè)數(shù)據(jù),無返回
Predicate T boolean 判斷/謂詞 對(duì)指定條件進(jìn)行測(cè)試
Function T R 函數(shù) 根據(jù)一個(gè)參數(shù)得到另一個(gè)參數(shù)值

一闪水、Supplier 接口

Supplier 接口代表一個(gè)結(jié)果的提供者糕非。

Supplier 接口是用來生成數(shù)據(jù)的,數(shù)據(jù)的類型通過泛型參數(shù)給定球榆,使用 get()方法獲得返回值朽肥。

接口的源碼如下:

@FunctionalInterface
public interface Supplier<T> {

    /**
     * 得到一個(gè)結(jié)果,返回 T 對(duì)象
     *
     * @return a result
     */
    T get();
}

Supplier 接口中的方法

T get() 獲得指定類型的數(shù)據(jù)

1.1芜果、將 Supplier 直接使用

案例需求:get()方法的基本使用鞠呈,在 Supplier 接口中 get 方法返回一個(gè)字符串。

案例步驟:

  • 使用 Lambda 創(chuàng)建 Supplier 對(duì)象右钾,泛型類型為 String蚁吝,方法體返回一個(gè)字符串,return 可以省略。
  • 調(diào)用 Supplier 的 get()方法得到字符串国撵,并打印輸出

public class LambdaTest {
    public static void main(String[] args) {
        //使用 Lambda 創(chuàng)建 Supplier 對(duì)象
        Supplier supplier = () -> "Hello Java!";
        //輸出它的值
        System.out.println(supplier.get());
    }
}
// 輸出
// Hello Java!

1.2背犯、將 Supplier 使用生成對(duì)象

案例需求:
下面的例子演示了如何通過調(diào)用一個(gè)靜態(tài)方法,生成一個(gè)員工對(duì)象返回山林。使用構(gòu)造方法做為 Supplier 參數(shù)的引用。

案例步驟:

  • 在主類內(nèi)部創(chuàng)建一個(gè)私有的靜態(tài) Employee 對(duì)象邢羔,重寫 toString()方法驼抹,返回一個(gè)字符串:"我是員工"。
  • 在 main 函數(shù)中創(chuàng)建一個(gè) Supplier 對(duì)象拜鹤,泛型類型是 Employee框冀。使用 Lambda 傳入 Supplier 對(duì)象,方法體實(shí)例化員工對(duì)象敏簿,省略 return 方法明也。
  • 使用 supplier 對(duì)象的 get()方法得到員工對(duì)象
  • 打印輸出員工對(duì)象

因?yàn)?Employee 對(duì)象是私有的,外部類無法直接實(shí)例化員工對(duì)象惯裕。

調(diào)用 Supplier 的 get()方法來生成員工對(duì)象温数,這樣做的目的是可以控制員工對(duì)象的生成方式,類似于工廠模式蜻势。


public class LambdaTest {
 
    public static void main(String[] args) {
        //使用 Lambda 傳入 Supplier 對(duì)象撑刺,將生成一個(gè)員工對(duì)象
        //此時(shí)僅僅是實(shí)例化了接口并未執(zhí)行里面代碼
        Supplier supplier = ()->new Employee();
        //輸出員工對(duì)象
        System.out.println(supplier.get());
    }
 
    //員工類
    private static class Employee {//注意static
        @Override
        public String toString() {
            return "我是員工";
        }
    }
}
// 輸出
// 我是員工

1.3、將 Supplier 做為方法的參數(shù)

需求說明:求數(shù)組中的最大值握玛,使用 Supplier 接口作為方法參數(shù)類型够傍,通過 Lambda 表達(dá)式求出 int 數(shù)組中的最大值次员。

需求分析:

  • 定義整型數(shù)組 int[] arr = {12,68,10,2,99,313,46};
  • 創(chuàng)建靜態(tài)方法 getMax():返回 int 類型,將 Supplier 做為參數(shù)王带,泛型類型為 Integer淑蔚,方法體調(diào)用 get()方法返回值。
  • 在 main 函數(shù)中調(diào)用 getMax()方法愕撰,使用 Lambda 傳入 Supplier 對(duì)象刹衫,并且實(shí)現(xiàn)查找最大值的功能。
  • 在 Lambda 表達(dá)式相當(dāng)于方法體:遍歷每個(gè)元素搞挣,比較大小带迟,找出最大值。
public class LambdaTest {
 
    public static void main(String[] args) {
        int[] arr = {12, 68, 10, 2, 99, 313, 46};
        // 調(diào)用 getMax 方法獲得最大值囱桨,Lambda 相當(dāng)于方法體
        int num = getMax(() -> {
            int max = arr[0];
            for (int i = 1; i < arr.length; i++) {
                if (max < arr[i]) {
                    max = arr[i];
                }
            }
            return max;
        });
        //輸出最大值
        System.out.println("最大值是:" + num);
    }
    
    //使用 Supplier 做為參數(shù)
    public static int getMax(Supplier<Integer> supplier) {
        return supplier.get();
    }
}
// 輸出
// 最大值是:313

二仓犬、Consumer 接口

Consumer 接口代表接受單一的輸入變量而且沒有返回值的一類操作。 它的作用和 Supplier 相反舍肠,是消費(fèi)一個(gè)數(shù)據(jù)的搀继,消費(fèi)的數(shù)據(jù)類型需要通過泛型指定。

源代碼如下:


@FunctionalInterface
public interface Consumer<T> {
 
    /**
     * 接受 t 對(duì)象翠语,無返回值
     */
    void accept(T t);
 
    /**
     * 默認(rèn)的組合方法叽躯,參數(shù)和返回值都是 Consumer 類型
     * 先調(diào)用自己的 accept()方法,再調(diào)用參數(shù)的 accept()方法
     */
    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}

Consumer 接口中的方法

void accept(T t) 接受對(duì)給定的參數(shù)進(jìn)行操作肌括。

Consumer 接口中的默認(rèn)方法:

default Consumer<T> andThen(Consumer<T> after)

如果一個(gè)方法的參數(shù)和返回值全都是 Consumer<T> 類型点骑,那么就可以實(shí)現(xiàn)效果:

消費(fèi)一個(gè)數(shù)據(jù)的時(shí)候,首先做一個(gè)操作谍夭,然后再做另一個(gè)操作黑滴,兩個(gè)操作依次執(zhí)行,實(shí)現(xiàn)一種組合操作紧索。而這個(gè)方法就是 Consumer 接口中的默認(rèn)方法 andThen袁辈。

2.1、直接使用 Consumer 對(duì)象

實(shí)現(xiàn)步驟:

  • 使用 Lambda 創(chuàng)建 Consumer 對(duì)象齐板,直接打印傳入的字符串?dāng)?shù)據(jù)吵瞻。
  • 調(diào)用 Consumer 的 accept()方法葛菇,在 accept()方法中傳入一個(gè)字符串?dāng)?shù)據(jù)甘磨。
public class LambdaTest {
 
    public static void main(String[] args) {
        //創(chuàng)建 Consumer 對(duì)象,打印傳入的變量 t
        Consumer consumer = t -> System.out.println(t);
        //調(diào)用 Consumer 中的方法
        consumer.accept("Hello Lambda");
    }
}
// 輸出
// Hello Lambda

2.2眯停、Consumer 做為參數(shù)

List 和 Set 集合中遍歷的 forEach 方法它的參數(shù)就是 Consumer济舆,請(qǐng)看下面的代碼:

案例需求:

  • 創(chuàng)建一個(gè)數(shù)組,使用 Arrays.asList("孫悟空", "豬八戒", "白骨精", "嫦娥") 轉(zhuǎn)成 List 對(duì)象莺债。
  • 使用 forEach 方法打印每一個(gè)元素滋觉,forEach 中使用 Lamba 表達(dá)式輸出傳入的字符串
public class LambdaTest {
    public static void main(String[] args) {
        //將數(shù)組轉(zhuǎn)成 List 對(duì)象
        List<String> names = Arrays.asList("孫悟空", "豬八戒", "白骨精", "嫦娥");
        //打印每一個(gè)字符串签夭,forEach 的參數(shù)就是 Consumer
        names.forEach(t -> System.out.println(t));
    }
}
// 輸出
//孫悟空
//豬八戒
//白骨精
//嫦娥

分析 forEach()方法的源代碼

default void forEach(Consumer<? super T> action) {
    Objects.requireNonNull(action);
    for (T t : this) {
        action.accept(t);
    }
}

這是定義在 java.lang.Iterable 接口中的默認(rèn)方法,參數(shù)就是 Consumer 對(duì)象椎侠,方法體內(nèi)對(duì)當(dāng)前集合使用 for遍歷第租,this 就是集合對(duì)象。每次對(duì)一個(gè)元素調(diào)用 accept()方法我纪。而我們外部調(diào)用的代碼中對(duì) accept()方法進(jìn)行了實(shí)現(xiàn)慎宾,輸出了每個(gè)元素。

public static T requireNonNull(T obj) 靜態(tài)方法浅悉,JDK7 中新增的方法趟据,判斷傳入的對(duì)象是否為 NULL,如果是 NULL 則拋出異常术健,不為 NULL 則返回對(duì)象本身汹碱。常用于方法或構(gòu)造方法中傳入對(duì)象參數(shù)的校驗(yàn)。


default Consumer<T>  andThen(Consumer<? super T>  after) {
     //判斷 after 是否為 null
     Objects.requireNonNull(after);
     //先調(diào)用自己的 accept()方法荞估,再調(diào)用參數(shù)的 accept()方法
     return (T t) -> { accept(t); after.accept(t); };
}

要想實(shí)現(xiàn)組合咳促,需要兩個(gè)或多個(gè) Lambda 表達(dá)式,而 andThen 的語義正是執(zhí)行“一步接一步”操作勘伺。

案例需求:將字符串 Hello 首先打印大寫的 HELLO等缀,然后打印小寫的 hello

實(shí)現(xiàn)步驟:

  • 創(chuàng)建 Consumer 對(duì)象 c1,使用 Lambda 打印 s 對(duì)象的大寫
  • 創(chuàng)建 Consumer 對(duì)象 c2娇昙,使用 Lambda 打印 s 對(duì)象的小寫
  • c1 調(diào)用 andThen(c2)方法尺迂,再調(diào)用 accept("字符串"),完成依次的操作冒掌。
public class LambdaTest {
    public static void main(String[] args) {
        //打印大寫
        Consumer<String> c1 = s -> System.out.println(s.toUpperCase());
        //打印小寫
        Consumer<String> c2 = s-> System.out.println(s.toLowerCase());
        //調(diào)用方法
        c1.andThen(c2).accept("Hello Consumer");
    }
}
// 輸出
// HELLO CONSUMER
// hello consumer

2.3噪裕、使用 Consumer 做為參數(shù)

需求說明:

格式化打印信息,下面的字符串?dāng)?shù)組當(dāng)中存有多條信息股毫,請(qǐng)按照格式“姓名:XX膳音。性別:XX×逦埽”的格式將信息打印出來祭陷。要求將打印姓名的動(dòng)作作為第一個(gè) Consumer 接口的 Lambda 實(shí)例,將打印性別的動(dòng)作作為第二個(gè)Consumer 接口的 Lambda 實(shí)例趣席,將兩個(gè) Consumer 接口按照順序“拼接”到一起兵志。以下數(shù)組共 5 個(gè)元素,每個(gè)元素包含 2 項(xiàng)信息用逗號(hào)分隔宣肚。

String[] arr = { "張飛,男", "貂蟬,女", "曹操,男","孫尚香,女","小喬,女" };

實(shí)現(xiàn)步驟

  • 創(chuàng)建靜態(tài)方法 printInfo()想罕,有 3 個(gè)參數(shù),第 1 個(gè)是需要打印的字符串?dāng)?shù)組霉涨,第 2 個(gè)是 Consumer用于打印姓名 name按价,第 3 個(gè)是 Consumer用于打印性別 gender惭适。
  • 在 printInfo 方法中遍歷數(shù)組中每個(gè)元素,再調(diào)用 name.andThen(gender).accept(單個(gè)元素)
  • 每調(diào)用一次 andThen()方法楼镐,在下面輸出一行橫線
  • 在 main 函數(shù)中創(chuàng)建上面要遍歷的數(shù)組
  • 調(diào)用 printInfo 方法癞志,傳入 3 個(gè)參數(shù),第 1 個(gè)參數(shù)是數(shù)組框产,第 2 個(gè)參數(shù)使用 Lambda 打印姓名今阳,參數(shù) s 表示數(shù)組中的每個(gè)元素。第 3 個(gè)參數(shù)使用 Lambda 打印性別茅信。
public class LambdaTest {
 
    public static void main(String[] args) {
        String[] arr = {"張飛,男", "貂蟬,女", "曹操,男","孫尚香,女"};
        //這里的 s 表示數(shù)組中的每個(gè)元素
        printInfo(arr,
                s ->System.out.println("姓名:" + s.split(",")[0]),
                s ->System.out.println("性別:" + s.split(",")[1]));
    }
 
    public static void printInfo(String[] arr, Consumer<String> name, Consumer<String> gender) {
        for (String s : arr) {
            name.andThen(gender).accept(s);
            System.out.println("------------------");
        }
    }
}

三盾舌、Predicate 接口

Predicate 中文意思為謂語,"我是一個(gè)程序員"蘸鲸,"是"或"不是"就是謂語妖谴。

它代表只有一個(gè)變量的函數(shù),返回 boolean 類型酌摇。有時(shí)候我們需要進(jìn)行某種判斷膝舅,從而得到一個(gè) boolean 值的結(jié)果∫ざ啵可以使用 java.util.function.Predicate接口仍稀。

@FunctionalInterface
public interface Predicate<T> {
 
    /**
     * 抽象方法,對(duì) t 進(jìn)行測(cè)試埂息,返回 boolean 類型
     */
    boolean test(T t);
 
    /**
     * 組合方法技潘,將當(dāng)前的謂語與另一個(gè)謂語進(jìn)行短路的與操作,返回一個(gè)謂語對(duì)象
     */
    default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }
 
    /**
     * 對(duì)當(dāng)前的謂語進(jìn)行邏輯非操作千康,返回一個(gè)謂語對(duì)象
     */
    default Predicate<T> negate() {
        return (t) -> !test(t);
    }
 
    /**
     * 組合方法享幽,將當(dāng)前的謂語與另一個(gè)謂語進(jìn)行短路的或操作,返回一個(gè)謂語對(duì)象
     */
    default Predicate<T> or(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }
 
    /**
     * 靜態(tài)方法拾弃,判斷 test(object)方法傳入的對(duì)象是否與參數(shù) targetRef 對(duì)象相等
     */
    static <T> Predicate<T> isEqual(Object targetRef) {
        return (null == targetRef)
                ? Objects::isNull
                : object -> targetRef.equals(object);
    }
}

Predicate 接口中的方法

boolean test(T t) 對(duì) t 進(jìn)行指定條件的測(cè)試豪椿,返回 boolean 類型

3.1搭盾、test()方法演示

案例需求:判斷 test("字符串")方法給定的參數(shù)長(zhǎng)度是否大于 5

案例步驟:

  • 創(chuàng)建一個(gè) Predicate 謂語對(duì)象,使用 Lambda 實(shí)現(xiàn) boolean test(T t)方法
  • 方法體的參數(shù)是 s滴某,返回字符串的長(zhǎng)度大于 5霎奢,省略 return 關(guān)鍵字幕侠。
  • 兩次調(diào)用 test()方法看運(yùn)行結(jié)果碍彭,第 1 次使用字符串 Hello庇忌,第 2 次使用字符串 Predicate
public class LambdaTest {
 
    public static void main(String[] args) {
        //創(chuàng)建一個(gè) Predicate 謂語對(duì)象皆疹,boolean test(T t)方法接收字符串類型,返回 boolean 類型
        Predicate<String> predicate = s -> s.length() > 5;
        //兩次調(diào)用 test 方法看運(yùn)行結(jié)果
        System.out.println("Hello 的長(zhǎng)度是否大于 5:" + predicate.test("Hello"));
        System.out.println("Predicate 的長(zhǎng)度是否大于 5:" + predicate.test("Predicate"));
    }
}
// 執(zhí)行結(jié)果
// Hello 的長(zhǎng)度是否大于 5:false
// Predicate 的長(zhǎng)度是否大于 5:true

3.2捎迫、默認(rèn)方法 and()

既然是條件判斷窄绒,就會(huì)存在與崔兴、或、非三種常見的邏輯關(guān)系螺戳。 其中將兩個(gè) Predicate 條件使用“與”邏輯連接起來實(shí)現(xiàn)“并且”的效果時(shí)倔幼,可以使用 default 方法 and爽待。 這個(gè)默認(rèn)方法接收一個(gè) Predicate 參數(shù)鸟款,返回一個(gè) Predicate參數(shù)何什。

其 JDK 源碼為:

/**
 * 組合方法,將當(dāng)前的謂語與另一個(gè)謂語進(jìn)行短路的與操作蛛砰,返回一個(gè)謂語對(duì)象
 */
default Predicate<T> and(Predicate<? super T> other) {
    Objects.requireNonNull(other);
    return (t) -> test(t) && other.test(t);
}
and 方法演示示例:

案例需求:判斷一個(gè)字符串是否包含指定的字符串:既包含大寫“H”泥畅,又要包含大寫“W”

案例步驟:

  • 創(chuàng)建 2 個(gè)需要判斷的字符串:s1="Hello world"和 s2="Hello World"
  • 使用 Lambda 表達(dá)式琅翻,創(chuàng)建兩個(gè) Predicate 對(duì)象
  • 判斷字符串 s 是否包含 H
  • 判斷字符串 s 是否包含 W
  • 調(diào)用 and 方法和 test 方法,分別輸出 s1 和 s2 的結(jié)果
public class LambdaTest {
 
    public static void main(String[] args) {
        //創(chuàng)建 2 個(gè)需要判斷的字符串
        String s1 = "Hello world";
        String s2 = "Hello World";
        // 使用 Lambda 表達(dá)式,創(chuàng)建兩個(gè) Predicate 對(duì)象
        //判斷 s 是否包含 H
        Predicate<String> p1 = s -> s.contains("H");
        //判斷 s 是否包含 W
        Predicate<String> p2 = s -> s.contains("W");
        //調(diào)用 and 方法
        System.out.println(s1 + "是否包含 H 和 W:" + p1.and(p2).test(s1));
        System.out.println(s2 + "是否包含 H 和 W:" + p1.and(p2).test(s2));
    }
}
// 輸出結(jié)果
// Hello world是否包含 H 和 W:false
// Hello World是否包含 H 和 W:true

3.3涛浙、默認(rèn)方法 or()

與 and 的“與”類似摄欲,默認(rèn)方法 or 實(shí)現(xiàn)邏輯關(guān)系中的“或”操作胸墙。 這個(gè)默認(rèn)方法接收一個(gè) Predicate 參數(shù)我注,返回一個(gè) Predicate 參數(shù)迟隅。

JDK 源碼為:

/**
 * 組合方法但骨,將當(dāng)前的謂語與另一個(gè)謂語進(jìn)行短路的或操作,返回一個(gè)謂語對(duì)象
 */
default Predicate<T> or(Predicate<? super T> other) {
    Objects.requireNonNull(other);
    return (t) -> test(t) || other.test(t);
}

or 方法演示示例:

案例需求:判斷一個(gè)字符串的長(zhǎng)度大于 10 或者小于 5

案例步驟:

  • 創(chuàng)建三個(gè)字符串 s1,s2,s3 內(nèi)容如下圖
  • 使用 Lambda 創(chuàng)建 2 個(gè) Predicate 接口對(duì)象奔缠,第 1 個(gè)判斷長(zhǎng)度是否大于 10,每 2 個(gè)判斷長(zhǎng)度是否小于 5
  • 調(diào)用 or 和 test 方法輸出每個(gè)字符串的測(cè)試結(jié)果
public class LambdaTest {
 
    public static void main(String[] args) {
        //創(chuàng)建三個(gè)字符串
        String s1 = "Hello World"; //大于 10
        String s2 = "Java"; //小于 5
        String s3 = "I am boy"; //既不大于 10吼野,又不小于 5
 
        //使用 Lambda 創(chuàng)建 2 個(gè) Predicate 接口對(duì)象
        Predicate<String> p1 = s -> s.length() > 10;
        Predicate<String> p2 = s -> s.length() < 5;
 
        //輸出每個(gè)字符串的測(cè)試結(jié)果
        System.out.println(s1 + "=" + p1.or(p2).test(s1));
        System.out.println(s2 + "=" + p1.or(p2).test(s2));
        System.out.println(s3 + "=" + p1.or(p2).test(s3));
    }
}
// 輸出結(jié)果
// Hello World=true
// Java=true
// I am boy=false

3.4、默認(rèn)方法 negate()

“與”瞳步、“或”已經(jīng)了解了闷哆,剩下的“非”(取反)也會(huì)簡(jiǎn)單。方法沒有參數(shù)抱怔,返回值為 Predicate。

默認(rèn)方法 negate的 JDK 源代碼為:

/**
 * 對(duì)當(dāng)前的謂語進(jìn)行邏輯非操作屈留,返回一個(gè)謂語對(duì)象
 */
default Predicate<T> negate() {
    return (t) -> !test(t);
}
從實(shí)現(xiàn)中很容易看出,它是執(zhí)行了 test 方法之后,對(duì)結(jié)果 boolean 值進(jìn)行“!”取反而已赠摇。

要在 test 方法調(diào)用之前調(diào)用 negate 方法固逗,正如 and 和 or 方法一樣惜傲。

案例需求:判斷年齡是否小于 18 歲,將判斷的結(jié)果取反贝攒。

案例步驟

  • 創(chuàng)建 2 個(gè)整數(shù)類型的年齡盗誊,一個(gè) 25,一個(gè) 15 歲隘弊。
  • 使用 Lambda 創(chuàng)建 1 個(gè) Predicate哈踱,判斷年齡小于 18 歲。
  • 使用 nagate()取反以后再調(diào)用 test()方法梨熙,輸出兩個(gè)年齡的結(jié)果
public class LambdaTest {
 
    public static void main(String[] args) {
        int age1 = 25; //25 歲
        int age2 = 15; //15 歲
 
        Predicate<Integer> predicate = (a) -> a < 18; //判斷是否小于 18 歲
        System.out.println(age1 + "小于 18 歲开镣,取反:" + predicate.negate().test(age1));
        System.out.println(age2 + "小于 18 歲,取反:" + predicate.negate().test(age2));
    }
}
// 執(zhí)行結(jié)果
// 25小于 18 歲咽扇,取反:true
// 15小于 18 歲邪财,取反:false

3.5、靜態(tài)方法 isEqual ()

Predicate 中唯一的靜態(tài)方法质欲,方法的參數(shù)是兩個(gè) Object 類型树埠,返回一個(gè) Predicate 類型。

作用:根據(jù) Objects.equals(Object, Object)方法比較兩個(gè)參數(shù)是否相等嘶伟,

一個(gè)對(duì)象通過 isEqual()傳入怎憋,另一個(gè)對(duì)象通過 test()傳入。

// java.util.Objects 類中的方法 說明
public static boolean equals(Object a,Object b)

作用:用于比較兩個(gè)對(duì)象是否相等

參數(shù):a 和 b 是要比較的兩個(gè)對(duì)象

返回:如果兩個(gè)對(duì)象相等九昧,則返回 true盛霎,否則返回 false

JDK 源代碼為:

/**
 * 靜態(tài)方法,判斷 test(object)方法傳入的對(duì)象是否與參數(shù) targetRef 對(duì)象相等
 */
static <T> Predicate<T> isEqual(Object targetRef) {
    return (null == targetRef)
            ? Objects::isNull
            : object -> targetRef.equals(object);
}

案例需求:比較兩個(gè)字符串是否相等

案例步驟:

  • 通過靜態(tài)方法 isEqual("newboy")耽装,直接返回 Predicate 對(duì)象
  • 調(diào)用 Predicate 中的 test()方法傳入另兩個(gè)字符串分別比較
public class LambdaTest {
    public static void main(String[] args) {
        //通過靜態(tài)方法直接返回 Predicate 對(duì)象
        Predicate predicate = Predicate.isEqual("newboy");
 
        //調(diào)用 test()方法傳入另兩個(gè)字符串分別比較
        System.out.println("兩個(gè)字符串是否相等:" + predicate.test("newboy"));
        System.out.println("兩個(gè)字符串是否相等:" + predicate.test("NewBoy"));
    }
}
// 執(zhí)行結(jié)果
// 兩個(gè)字符串是否相等:true
// 兩個(gè)字符串是否相等:false

3.6愤炸、Predicate 的應(yīng)用示例

需求說明:

集合當(dāng)中有多條“姓名+性別”的信息如下:"張飛,男", "貂蟬,女", "曹操,男","孫尚香,女","小喬,女",請(qǐng)通過 Predicate 接口的 and 組合方法掉奄,將符合要求的字符串篩選到集合 ArrayList 中规个,需要同時(shí)滿足兩個(gè)條件:

  • 必須為女生
  • 姓名為兩個(gè)字

開發(fā)步驟:

  • 創(chuàng)建第 1 個(gè) Predicate 判斷條件:使用逗號(hào)分隔的第 0 個(gè)元素姓名長(zhǎng)度是 2
  • 創(chuàng)建第 2 個(gè) Predicate 判斷條件:使用逗號(hào)分隔的第 1 個(gè)元素性別等于女
  • 創(chuàng)建一個(gè)新的 List 集合凤薛,用于存儲(chǔ)過濾以后符合條件的字符串
  • 使用 List 中的 forEach(Lambda)遍歷上面的原始 List 集合,使用 Predicate 中的 and 和 test 方法判斷每個(gè)元素
  • 兩個(gè)條件都為真才添加到新的 List 集合中
  • 創(chuàng)建第 1 個(gè) Consumer 接口诞仓,輸出使用逗號(hào)分隔的第 0 個(gè)元素姓名
  • 創(chuàng)建第 2 個(gè) Consumer 接口缤苫,輸出使用逗號(hào)分隔的第 1 個(gè)元素性別
  • 使用 List 中的 forEach(Lambda)遍歷,輸出過濾后的新的集合
  • 使用 Consumer 接口中的 andThen 和 accept 方法墅拭,輸出每一個(gè)元素

public class LambdaTest {
    public static void main(String[] args) {
        //從數(shù)組中創(chuàng)建一個(gè) List 集合
        List<String> list = Arrays.asList("張飛,男", "貂蟬,女", "曹操,男","孫尚香,女","小喬,女");
 
        //創(chuàng)建第 1 個(gè) Predicate 判斷條件:使用逗號(hào)分隔的第 0 個(gè)元素姓名長(zhǎng)度是 2
        Predicate<String> pname = s -> s.split(",")[0].length() ==2;
        //創(chuàng)建第 2 個(gè) Predicate 判斷條件:使用逗號(hào)分隔的第 1 個(gè)元素性別等于女
        Predicate<String> pgender = s-> s.split(",")[1].equals("女");
 
        //創(chuàng)建一個(gè)新的 List 集合
        List<String> infos = new ArrayList<>();
        //使用 Lamba 中的 forEach()遍歷上面的 List 集合
        //使用 Predicate 中的 and 和 test 方法判斷每個(gè)元素
        list.forEach(s -> {
            //兩個(gè)都為真才添加到集合中
            if (pname.and(pgender).test(s)) {
                infos.add(s);
            }
        });
        //創(chuàng)建第 1 個(gè) Consumer 接口活玲,輸出使用逗號(hào)分隔的第 0 個(gè)元素姓名
        Consumer<String> cname = s -> System.out.println("姓名:" + s.split(",")[0]);
        //創(chuàng)建第 2 個(gè) Consumer 接口,輸出使用逗號(hào)分隔的第 1 個(gè)元素性別
        Consumer<String> cgender = s -> System.out.println("性別:" + s.split(",")[1]);
        //使用 Lamba 中的 forEach()遍歷谍婉,輸出過濾后的集合
        infos.forEach(s -> {
            //使用 Consumer 接口中的 andThen 和 accept 方法舒憾,每輸出一個(gè)元素隔一條線
            cname.andThen(cgender).accept(s);
            System.out.println("---------------");
        });
    }
}
// 輸出結(jié)果
姓名:貂蟬
性別:女
---------------
姓名:小喬
性別:女
---------------

四、Function 接口

Function接口:

  • 根據(jù)一個(gè)參數(shù)得到另一個(gè)參數(shù)值穗熬,前面稱為計(jì)算的參數(shù)镀迂,后面稱為計(jì)算的結(jié)果。
  • 有進(jìn)有出唤蔗,所以稱為“函數(shù) Function”探遵。

類似于數(shù)學(xué)中的函數(shù),通過一個(gè)變量求出另一個(gè)變量的值妓柜。如:f(x) = 2x+3

以下是它的 Java 源代碼:

// 代表通過一個(gè)變量求出另一個(gè)變量的結(jié)果的函數(shù)
@FunctionalInterface
public interface Function<T, R> {
 
    /**
     * 對(duì)給定的變量 t 進(jìn)行計(jì)算箱季,得到返回的結(jié)果 R
     */
    R apply(T t);
 
    /**
     * 默認(rèn)組合方法,先計(jì)算當(dāng)前函數(shù)棍掐,再計(jì)算傳入的函數(shù)
     */
    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }
 
    /**
     * 默認(rèn)組合方法藏雏,先計(jì)算傳入的函數(shù),再計(jì)算當(dāng)前函數(shù)
     */
    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }
 
    /**
     * 靜態(tài)方法:總是返回它的輸入變量
     */
    static <T> Function<T, T> identity() {
        return t -> t;
    }
}

4.1塌衰、抽象方法:apply()

是java.util.function.Function 接口中的方法

R apply(T t); 對(duì)給定的變量 t 進(jìn)行計(jì)算诉稍,得到返回的結(jié)果 R

apply 方法演示示例:

案例需求:將 Integer 類型轉(zhuǎn)換為 String 類型,并且輸出轉(zhuǎn)換以后字符串的長(zhǎng)度最疆。

  • 創(chuàng)建一個(gè) Function 對(duì)象杯巨,輸入類型是整數(shù),輸出類型是字符串
  • Lambda 表達(dá)式將一個(gè)整數(shù) i 轉(zhuǎn)成字符串
  • 調(diào)用 apply(數(shù)字)方法得到轉(zhuǎn)換后的字符串努酸,再調(diào)用字符串的 length()方法得到長(zhǎng)度服爷,打印輸出
  • 第 1 次轉(zhuǎn)換 99 這個(gè)數(shù)字,第 2 次轉(zhuǎn)換 1000 這個(gè)數(shù)字
public class LambdaTest {
    public static void main(String[] args) {
        //創(chuàng)建一個(gè) Function 對(duì)象
        Function<Integer,String> converter = i -> Integer.toString(i);
        System.out.println("99 轉(zhuǎn)成字符串的長(zhǎng)度是:" + converter.apply(99).length());
        System.out.println("1000 轉(zhuǎn)成字符串的長(zhǎng)度是:" + converter.apply(1000).length());
    }
}
// 輸出結(jié)果
99 轉(zhuǎn)成字符串的長(zhǎng)度是:2
1000 轉(zhuǎn)成字符串的長(zhǎng)度是:4

4.2获诈、默認(rèn)方法:andThen()

Function 接口中有一個(gè)默認(rèn)的 andThen 方法仍源,用來進(jìn)行組合操作。

先計(jì)算當(dāng)前函數(shù)舔涎,再計(jì)算傳入的函數(shù)笼踩。兩個(gè)函數(shù)依次執(zhí)行。

andThen 方法的參數(shù)是 Function 對(duì)象亡嫌,返回一個(gè) Function 對(duì)象嚎于。

JDK 源代碼:

/**
 * 默認(rèn)組合方法掘而,先計(jì)算當(dāng)前函數(shù),再計(jì)算傳入的函數(shù)
 */
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
    Objects.requireNonNull(after);
    return (T t) -> after.apply(apply(t));
}

案例需求:
連續(xù)進(jìn)行兩個(gè)操作:第 1 個(gè)操作是將字符串轉(zhuǎn)換成為 int 數(shù)字于购,第 2 個(gè)操作將轉(zhuǎn)換好的數(shù)字乘以 10袍睡。兩個(gè)操作按照前后順序組合到一起。

  • 讓用戶從鍵盤輸入 1 個(gè)數(shù)字肋僧,使用字符串接收斑胜。
  • 創(chuàng)建第 1 個(gè) Function 函數(shù)將字符串轉(zhuǎn)成整數(shù)
  • 創(chuàng)建第 2 個(gè)函數(shù)將整數(shù)乘以 10 返回
  • 調(diào)用 andThen 方法和 apply,并且輸出結(jié)果
public class LambdaTest {
    public static void main(String[] args) {
        //用戶輸入一個(gè)字符串
        System.out.println("請(qǐng)輸入數(shù)字:");
        Scanner input = new Scanner(System.in);
        String str = input.nextLine();
        //第 1 個(gè)函數(shù)將字符串轉(zhuǎn)成整數(shù)
        Function<String,Integer> f1 = s -> Integer.parseInt(s);
        //第 2 個(gè)函數(shù)將整數(shù)乘以 10 返回
        Function<Integer,Integer>  f2 = i -> i * 10;
        //調(diào)用 andThen 方法嫌吠,并且輸出結(jié)果
        System.out.println("轉(zhuǎn)成整數(shù)并乘以 10 以后的結(jié)果是:" + f1.andThen(f2).apply(str));
    }
}
// 輸出結(jié)果
請(qǐng)輸入數(shù)字:
2
轉(zhuǎn)成整數(shù)并乘以 10 以后的結(jié)果是:20

4.3止潘、默認(rèn)方法:compose()

Function 中有一個(gè)與 andThen 非常類似的 compose 方法。

中文是"組成"的意思居兆,方法參數(shù)是 Function覆山,返回值是 Function竹伸,先運(yùn)行參數(shù)的 apply 方法泥栖,再調(diào)用自己的 apply 方法。

其 JDK 源代碼為:

/**
 * 默認(rèn)組合方法勋篓,先計(jì)算傳入的函數(shù)吧享,再計(jì)算當(dāng)前函數(shù)
 */
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
    Objects.requireNonNull(before);
    return (V v) -> apply(before.apply(v));
}

// 結(jié)合 andThen 方法的 JDK 源碼實(shí)現(xiàn)進(jìn)行對(duì)比,會(huì)發(fā)現(xiàn) compose 方法的參數(shù) Lamda 將會(huì)先執(zhí)行譬嚣。
所以二者只是先后順序的不同而已钢颂。

compose 方法的演示

案例需求:
創(chuàng)建兩個(gè)函數(shù)對(duì)象:1 個(gè)將字符串轉(zhuǎn)成大寫,1 個(gè)將字符串轉(zhuǎn)成小寫拜银。分別使用 andThen 和 compose 方法組合調(diào)用殊鞭,查看不同的計(jì)算結(jié)果。

開發(fā)步驟:

  • 創(chuàng)建第 1 個(gè) Function尼桶,輸入輸出都是 String 類型操灿,將字符串轉(zhuǎn)成大寫。
  • 創(chuàng)建第 2 個(gè) Function泵督,輸入輸出都是 String 類型趾盐,將字符串轉(zhuǎn)成小寫。
  • 調(diào)用第 1 個(gè)函數(shù)的 apply 方法小腊,并且輸出值
  • 調(diào)用第 2 個(gè)函數(shù)的 apply 方法救鲤,并且輸出值
  • 調(diào)用 andThen 方法和 apply 方法查看運(yùn)行結(jié)果
  • 調(diào)用 compose 方法和 apply 方法查看運(yùn)行結(jié)果
public class LambdaTest {
    public static void main(String[] args) {
        Function<String, String> f1 = s -> s.toUpperCase();
        Function<String, String> f2 = s -> s.toLowerCase();
        System.out.println("轉(zhuǎn)成大寫:" + f1.apply("Hello"));
        System.out.println("轉(zhuǎn)成小寫:" + f2.apply("Hello"));
        System.out.println("先轉(zhuǎn)成大寫,再轉(zhuǎn)成小寫:" + f1.andThen(f2).apply("Hello"));
        System.out.println("先轉(zhuǎn)成小寫秩冈,再轉(zhuǎn)成大寫:" + f1.compose(f2).apply("Hello"));
    }
}
// 執(zhí)行結(jié)果
轉(zhuǎn)成大寫:HELLO
轉(zhuǎn)成小寫:hello
先轉(zhuǎn)成大寫本缠,再轉(zhuǎn)成小寫:hello
先轉(zhuǎn)成小寫,再轉(zhuǎn)成大寫:HELLO

Function 的應(yīng)用示例

需求說明:請(qǐng)使用 Function 進(jìn)行函數(shù)拼接入问,按照順序執(zhí)行多個(gè)函數(shù)丹锹。

操作依次為:

  • 將字符串"趙麗穎,20"截取數(shù)字年齡部分犹赖,得到字符串;
  • 將上一步的字符串轉(zhuǎn)換成為 int 類型的數(shù)字卷仑;
  • 將上一步的 int 數(shù)字累加 100峻村,得到結(jié)果 int 數(shù)字。

開發(fā)步驟:

  • 創(chuàng)建第 1 個(gè) Function 對(duì)象锡凝,將字符串 20 取出粘昨,返回一個(gè)字符串
  • 創(chuàng)建第 2 個(gè) Function 對(duì)象,將字符串轉(zhuǎn)成整數(shù)窜锯,返回整數(shù)
  • 創(chuàng)建第 3 個(gè) Function 對(duì)象张肾,將整數(shù)加 100,返回計(jì)算結(jié)果4) 調(diào)用 andThen 方法 2 次锚扎,apply 方法應(yīng)用字符串:"趙麗穎,20"吞瞪,輸出結(jié)果

代碼實(shí)現(xiàn)

public class LambdaTest {
    public static void main(String[] args) {
        //創(chuàng)建第 1 個(gè) Function 對(duì)象,將字符串 20 取出驾孔,返回一個(gè)字符串
        Function<String,String> fun1 = s -> s.split(",")[1];
        //創(chuàng)建第 2 個(gè) Function 對(duì)象芍秆,將字符串轉(zhuǎn)成整數(shù),返回整數(shù)
        Function<String,Integer> fun2 = s -> Integer.parseInt(s);
        //創(chuàng)建第 3 個(gè) Function 對(duì)象翠勉,將整數(shù)加 100妖啥,返回計(jì)算結(jié)果
        Function<Integer,Integer> fun3 = num -> num + 100;
        //調(diào)用 andThen 方法 2 次,apply 方法應(yīng)用字符串对碌,輸出結(jié)果
        System.out.println("計(jì)算結(jié)果:" + fun1.andThen(fun2).andThen(fun3).apply("趙麗穎,20"));
    }
}
//輸出結(jié)果
計(jì)算結(jié)果:120

五荆虱、BinaryOperator 接口

BinaryOperator 表示對(duì)兩個(gè)相同類型的操作數(shù)進(jìn)行操作,產(chǎn)生相同類型的結(jié)果朽们。

接口中的方法

@FunctionalInterface
public interface BinaryOperator<T> extends BiFunction<T,T,T> {

    /**
     * 
     * 返回BinaryOperator返回根據(jù)指定的兩個(gè)元件的較小的Comparator 
     *
     */
    public static <T> BinaryOperator<T> minBy(Comparator<? super T> comparator) {
        Objects.requireNonNull(comparator);
        return (a, b) -> comparator.compare(a, b) <= 0 ? a : b;
    }

    /**
     * 
     * 返回一個(gè)BinaryOperator 怀读,它根據(jù)指定的Comparator返回兩個(gè)元素中的較大Comparator
     *
     */
    public static <T> BinaryOperator<T> maxBy(Comparator<? super T> comparator) {
        Objects.requireNonNull(comparator);
        return (a, b) -> comparator.compare(a, b) >= 0 ? a : b;
    }
}

這個(gè)接口中定義了兩個(gè)靜態(tài)方法,
BiFunction 是用于定義兩個(gè)操作符的函數(shù)接口骑脱。

BiFunction接口中的方法

@FunctionalInterface
public interface BiFunction<T, U, R> {

    /**
     * 傳入兩個(gè)參數(shù) t 和 u 進(jìn)行函數(shù)計(jì)算菜枷,返回計(jì)算的結(jié)果。
     * 兩個(gè)參數(shù)和返回值都是同一種類型惜姐。
     *
     */
    R apply(T t, U u);

    /**
     * 返回一個(gè)組合函數(shù)犁跪,首先將該函數(shù)應(yīng)用于其輸入,然后將after函數(shù)應(yīng)用于結(jié)果歹袁。 
     * 如果任一函數(shù)的評(píng)估引發(fā)異常坷衍,則將其轉(zhuǎn)發(fā)給組合函數(shù)的調(diào)用者。
     *
     */
    default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t, U u) -> after.apply(apply(t, u));
    }
}

5.1条舔、方法的演示:apply()

案例需求:
使用 BinaryOperator 接口的 apply()方法枫耳,計(jì)算 2 個(gè)整數(shù)的和,并且輸出結(jié)果孟抗。

案例步驟:

  • 創(chuàng)建類 Demo25BinaryOperator
  • 創(chuàng)建 BinaryOperator 接口迁杨,使用 Lambda 實(shí)現(xiàn)方法钻心,方法有兩個(gè)參數(shù),返回方法的計(jì)算結(jié)果铅协。
  • 調(diào)用 apply()方法傳入實(shí)際的參數(shù)捷沸,打印計(jì)算結(jié)果。

案例代碼:

public class LambdaTest {
    public static void main(String[] args) {
        BinaryOperator<Integer> operator = (m, n) -> m + n;
        System.out.println("計(jì)算結(jié)果是:" + operator.apply(3, 5));
    }
}
// 輸出結(jié)果
計(jì)算結(jié)果是:8

靜態(tài)方法

public static  BinaryOperator minBy(Comparator comparator)
通過后面的 Comparator 比較器判斷狐史,返回兩個(gè)元素中較小的元素

public static  BinaryOperator maxBy(Comparator comparator)
通過后面的 Comparator 比較器判斷痒给,返回兩個(gè)元素中較大的元素

Comparator 接口中的靜態(tài)方法說明
naturalOrder() 按元素的自然排序的大小進(jìn)行比較,返回一個(gè) Comparator 對(duì)象
reverseOrder() 按元素的倒序大小進(jìn)行比較骏全,返回一個(gè) Comparator 對(duì)象

5.2苍柏、BinaryOperator 接口做為方法參數(shù)

案例需求:
有如下數(shù)組{2,1,3,5},對(duì)數(shù)組中的每個(gè)元素進(jìn)行替換姜贡。替換算法如下:

  • 第 0 個(gè)元素不變
  • 第 0 個(gè)+第 1 個(gè)元素的結(jié)果代替第 1 個(gè)元素
  • 第 1 個(gè)新元素+第 2 個(gè)元素的結(jié)果代替 2 個(gè)
  • 第 2 個(gè)新元素+第 3 個(gè)元素的結(jié)果代替第 3 個(gè)
  • 依次類推试吁,直到所有的元素替換完成為止。
//Arrays 類中的方法說明
void parallelPrefix(T[] array, BinaryOperator op)
 
作用:對(duì)數(shù)組中每個(gè)元素使用指定的二元操作函數(shù)進(jìn)行替換操作楼咳,并行累積
參數(shù) 1:要替換的數(shù)組
參數(shù) 2:指定二元操作函數(shù)

案例步驟

  • 創(chuàng)建 BinaryOperator對(duì)象熄捍,指定 2 個(gè)數(shù)的算法是 m+n
  • 創(chuàng)建 Integer 類型的數(shù)組:{2,1,3,5}
  • 輸出操作前的數(shù)組
  • 調(diào)用上面的 parallelPrefix()方法,將 BinaryOperator 做為參數(shù)傳入
  • 輸出操作后的數(shù)組
  • 如果使用不同的算法爬橡,則每個(gè)元素的替換的結(jié)果不同治唤。如:換成兩個(gè)數(shù)相乘棒动。

案例代碼

public class LambdaTest {
    public static void main(String[] args) {
        BinaryOperator<Integer> operator = (m,n) -> m+n;
        Integer [] arr = {2,1,3,5};
        System.out.println("操作前的數(shù)組:" + Arrays.toString(arr)) ;
        Arrays.parallelPrefix(arr,operator);
        System.out.println("操作后的數(shù)組:" + Arrays.toString(arr)) ;
    }
}
//輸出結(jié)果
操作前的數(shù)組:[2, 1, 3, 5]
操作后的數(shù)組:[2, 3, 6, 11]

5.3糙申、靜態(tài)方法的演示

案例需求:
比較兩個(gè)整數(shù),使用 minBy 靜態(tài)方法找出最小值比較兩個(gè)字符串船惨,使用 maxBy 靜態(tài)方法找出最大值

案例步驟

  • 創(chuàng)建 BinaryOperator對(duì)象柜裸,使用 minBy()靜態(tài)方法,按數(shù)字的正常大小進(jìn)行比較粱锐。
  • 輸出最小值疙挺,調(diào)用 apply()方法,傳入 2 個(gè)整數(shù)怜浅。
  • 創(chuàng)建 BinaryOperator對(duì)象铐然,使用 maxBy()靜態(tài)方法,按字符串的大小進(jìn)行比較恶座。
  • 輸出最大值搀暑,調(diào)用 apply()方法,傳入 2 個(gè)字符串:"ABCD","xyz"

案例代碼

public class LambdaTest {
    public static void main(String[] args) {
        //naturalOrder()是 Comparator 中的靜態(tài)方法跨琳,即按數(shù)字的正常大小進(jìn)行比較
        BinaryOperator oper1 = BinaryOperator.minBy(Comparator.naturalOrder());
        System.out.println("最小值是:" + oper1.apply(3,5));
 
        //naturalOrder()是 Comparator 中的靜態(tài)方法自点,即按字符串的正常大小進(jìn)行比較
        BinaryOperator oper2 = BinaryOperator.maxBy(Comparator.naturalOrder());
        System.out.println("最大值是:" + oper2.apply("ABCD","xyz"));
    }
}
// 輸出結(jié)果
最小值是:3
最大值是:xyz

六、UnaryOperator 接口

UnaryOperator 表示對(duì)單個(gè)操作數(shù)的操作脉让,該操作數(shù)生成與其操作數(shù)類型相同的結(jié)果桂敛。

UnaryOperator 接口繼承于 Function 接口功炮,

所以有 T apply(T t)抽象方法,與前面的 Function 接口中的 apply()方法相同术唬。

它的輸入類型和返回類型是相同的類型薪伏。

UnaryOperator 接口的源碼

@FunctionalInterface
public interface UnaryOperator<T> extends Function<T, T> {
 
    /**
     * 始終返回其輸入?yún)?shù)的一元運(yùn)算符
     */
    static <T> UnaryOperator<T> identity() {
        return t -> t;
    }
}

方法的演示

UnaryOperator 接口中的方法說明

T apply(T t); 
    從 Function 接口中繼承下來的抽象方法,使用給定的參數(shù)應(yīng)用此一元運(yùn)算函數(shù)粗仓,返回另一個(gè)值毅该。
    參數(shù)和返回值是同一種類型。

static  UnaryOperator identity() 
    始終返回其輸入?yún)?shù)的一元運(yùn)算符也就是后續(xù) apply()輸入的是什么潦牛,就返回什么眶掌。

案例步驟

  • 使用 UnaryOperator.identity()靜態(tài)方法創(chuàng)建 UnaryOperator對(duì)象
  • 應(yīng)用 apply()方法,輸入字符串 abc巴碗,得到結(jié)果也是 abc朴爬。
public class LambdaTest {
    public static void main(String[] args) {
        //創(chuàng)建一個(gè) UnaryOperator對(duì)象,
        UnaryOperator operator = UnaryOperator.identity();
 
        //調(diào)用 apply()方法橡淆,輸出參數(shù)的值
        System.out.println("輸出與輸入一樣:" + operator.apply("abc"));
    }
}
//輸出結(jié)果
輸出與輸入一樣:abc

UnaryOperator 使用方法的參數(shù)

案例需求:
有一個(gè)整數(shù)的列表集合召噩,將集合中每個(gè)元素乘以 2,再替換這個(gè)元素逸爵,輸出替換前后的列表集合有一個(gè)字符串的列表集合具滴,將集合中每個(gè)元素用它的大寫進(jìn)行替換。

ArrayList 中的方法說明
replaceAll(UnaryOperator operator) 
使用一元操作函數(shù)的結(jié)果师倔,替換列表中的每個(gè)元素

案例步驟:

  • 使用 Arrays.asList()創(chuàng)建一個(gè)整數(shù)列表
  • 創(chuàng)建 UnaryOperator一元運(yùn)算函數(shù)构韵,指定運(yùn)算表達(dá)式是 x*2
  • 調(diào)用 ArrayList 的 replaceAll()方法,把上面創(chuàng)建的一元運(yùn)算函數(shù)做為參數(shù)傳入
  • 輸出替換前后的列表
  • 使用 Arrays.asList()創(chuàng)建一個(gè)字符串列表
  • 這次直接在 replaceAll()方法中傳入 Lambda 表達(dá)式趋艘,s.toUpperCase()
  • 輸出替換前后的列表
public class LambdaTest {
    public static void main(String[] args) {
        List<Integer> nums = Arrays.asList(3, 10, 8, 2);
        System.out.println("替換前:" + nums);
        UnaryOperator<Integer> oper = x -> x * 2;
        nums.replaceAll(oper);
        System.out.println("替換后:" + nums);
 
        List<String> names = Arrays.asList("Jack","Rose","Tom","NewBoy");
        System.out.println("替換前:" + names);
        names.replaceAll(s -> s.toUpperCase());
        System.out.println("替換后:" + names);
    }
}
//輸出
替換前:[3, 10, 8, 2]
替換后:[6, 20, 16, 4]
替換前:[Jack, Rose, Tom, NewBoy]
替換后:[JACK, ROSE, TOM, NEWBOY]

七疲恢、常用的函數(shù)式接口小結(jié)

1、Supplier 提供數(shù)據(jù)者 
    T get();沒有傳入?yún)?shù)瓷胧,有結(jié)果显拳。

2、Consumer 消費(fèi)數(shù)據(jù)者 
    void accept(T t); 傳入數(shù)據(jù)搓萧,沒有結(jié)果杂数。 
    andThen() 
    
3、Predicate 謂語 
    boolean test(T t); 對(duì)傳入的數(shù)據(jù)邏輯判斷 
    and()
    or()
    negate()
    isEqual()
    
4瘸洛、Function 函數(shù) 
    R apply(T t); 傳入一個(gè)變量返回計(jì)算結(jié)果 
    andThen()
    compose()
    identity()
    
5揍移、BinaryOperator 二元操作符 
    T apply(T t,T u); 傳入兩個(gè)參數(shù)返回一個(gè)結(jié)果 
    andThen()
    繼承于 BiFunction
    
6、UnaryOperator
    繼承于 Function
    一元操作符 
    T apply(T t); 傳入一個(gè)參數(shù)返回一個(gè)結(jié)果 
    andThen()
    compose()
    identity()

參考:
https://blog.csdn.net/swadian2008/article/details/119780384

https://www.cnblogs.com/qwera/p/14710347.html

https://www.cnblogs.com/cathyqq/p/14493801.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末货矮,一起剝皮案震驚了整個(gè)濱河市羊精,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖喧锦,帶你破解...
    沈念sama閱讀 217,826評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件读规,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡燃少,警方通過查閱死者的電腦和手機(jī)束亏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來阵具,“玉大人碍遍,你說我怎么就攤上這事⊙粢海” “怎么了怕敬?”我有些...
    開封第一講書人閱讀 164,234評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)帘皿。 經(jīng)常有香客問我东跪,道長(zhǎng),這世上最難降的妖魔是什么鹰溜? 我笑而不...
    開封第一講書人閱讀 58,562評(píng)論 1 293
  • 正文 為了忘掉前任虽填,我火速辦了婚禮,結(jié)果婚禮上曹动,老公的妹妹穿的比我還像新娘斋日。我一直安慰自己,他們只是感情好墓陈,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評(píng)論 6 392
  • 文/花漫 我一把揭開白布恶守。 她就那樣靜靜地躺著,像睡著了一般跛蛋。 火紅的嫁衣襯著肌膚如雪熬的。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,482評(píng)論 1 302
  • 那天赊级,我揣著相機(jī)與錄音,去河邊找鬼岔绸。 笑死理逊,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的盒揉。 我是一名探鬼主播晋被,決...
    沈念sama閱讀 40,271評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼刚盈!你這毒婦竟也來了羡洛?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,166評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤藕漱,失蹤者是張志新(化名)和其女友劉穎欲侮,沒想到半個(gè)月后崭闲,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,608評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡威蕉,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評(píng)論 3 336
  • 正文 我和宋清朗相戀三年刁俭,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片韧涨。...
    茶點(diǎn)故事閱讀 39,926評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡牍戚,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出虑粥,到底是詐尸還是另有隱情如孝,我是刑警寧澤,帶...
    沈念sama閱讀 35,644評(píng)論 5 346
  • 正文 年R本政府宣布娩贷,位于F島的核電站暑竟,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏育勺。R本人自食惡果不足惜但荤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望涧至。 院中可真熱鬧腹躁,春花似錦、人聲如沸南蓬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽赘方。三九已至烧颖,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間窄陡,已是汗流浹背炕淮。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留跳夭,地道東北人涂圆。 一個(gè)月前我還...
    沈念sama閱讀 48,063評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像币叹,于是被迫代替她去往敵國(guó)和親润歉。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容