主頁 > 後端開發 > java -- 函式式編程

java -- 函式式編程

2023-04-21 07:40:40 後端開發

函式式編程

面向物件過分強調“必須通過物件的形式來做事情”,而函式式思想則盡量忽略面向物件的復雜語法——強調做什么,而不是怎么做
有時只是為了做某事情而不得不創建一個物件,而傳遞一段代碼才是我們真正的目的,

Lambda

Lambda是一個匿名函式,可以理解為一段可以傳遞的代碼,
當需要啟動一個執行緒去完成任務時, 通常會通過java.lang.Runnable介面來定義任務內容,并使用java.lang.Thread類來啟動該執行緒
傳統寫法,代碼如下:

public class Demo {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("多執行緒任務執行!");
            }
        }).start();
    }
}

借助Java 8的全新語法,上述Runnable介面的匿名內部類寫法可以通過更簡單的Lambda運算式達到同樣的效果:

public class Demo04LambdaRunnable {
    public static void main(String[] args) {
        new Thread(() -> System.out.println("多執行緒任務執行!")).start(); // 啟動執行緒
    }
}

Lambda的優點 簡化匿名內部類的使用,語法更加簡單,

前提條件

必須是介面, 介面中有且只有一個抽象方法

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

格式

Lambda運算式的標準格式為:

() -> {}
() 引數串列,無引數留空
-> 固定寫法, 代表指向動作
{} 方法體

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

  1. 引數型別可省略
  2. 如果只有一個引數 ()可以省略
  3. 如果方法體只有一句話 return 大括號 分號都可省略, 但必須同時省略
new Thread(() -> System.out.println("省略格式開啟執行緒")).start();

原理

  1. 在匿名方法所在類中新增一個方法,方法體為Lambda運算式中的代碼
  2. 運行時形成一個新的類,并實作對應介面
  3. 重寫方法的方法體中呼叫匿名方法所在類中新生成的方法.

函式式介面

函式式介面在Java中是指:有且僅有一個抽象方法的介面
函式式介面,即適用于函式式編程場景的介面,而Java中的函式式編程體現就是Lambda,所以函式式介面就是可以適用于Lambda使用的介面,

從應用層面來講,Java中的Lambda可以看做是匿名內部類的簡化格式,但是二者在原理上不同,

格式

只要確保介面中有且僅有一個抽象方法即可:

修飾符 interface 介面名稱 {
    public abstract 回傳值型別 方法名稱(可選引數資訊);
}

由于介面當中抽象方法的public abstract是可以省略的,所以定義一個函式式介面很簡單:

public interface MyFunctionalInterface {
    void myMethod();
}

@FunctionalInterface

@FunctionalInterface 該注解可用于一個介面的定義上:

@FunctionalInterface
public interface MyFunctionalInterface {
    void myMethod();
}

一旦使用該注解來定義介面,編譯器將會強制檢查該介面是否確實有且僅有一個抽象方法,否則將會報錯,不過,即使不使用該注解,只要滿足函式式介面的定義,這仍然是一個函式式介面

常用函式式介面

Supplier介面

java.util.function.Supplier<T>介面,它意味著"供給" , 對應的Lambda運算式需要“對外提供”一個符合泛型型別的物件資料,
抽象方法:
T get() 用來獲取一個泛型引數指定型別的物件資料
求陣列元素最大值
使用Supplier介面作為方法引數型別,通過Lambda運算式求出int陣列中的最大值

public class supplierInterface {
    public static void main(String[] args) {
        int[] arr = {3,24,346,4,13};
        method(() -> {
            Arrays.sort(arr);
            return arr[arr.length - 1];
        });
    }

    public static void method(Supplier<Integer> s) {
        Integer max = s.get();
        System.out.println(max);
    }
}
Consumer介面

java.util.function.Consumer<T> 介面不生產資料,而是消費一個資料,其資料型別由泛型引數決定
抽象方法
void accept(T t),意為消費一個指定泛型的資料
默認方法
default Consumer<T> andThen(Consumer<? super T> after)

public class _4_consumerInterface {
    public static void main(String[] args) {
        method("Hello World", (String s) -> {
            System.out.println(s.toUpperCase());
        });

        method("HEllO WorlD", s -> System.out.println(s.toLowerCase()));

        System.out.println("==========================");
        method("HEllO WorlD", (String s) -> {
            System.out.println(s.toUpperCase());
        }, (String s) -> {
            System.out.println(s.toLowerCase());
        });
        method("HEllO WorlD",
                s -> System.out.println(s.toUpperCase()),
                s -> System.out.println(s.toLowerCase())
        );
    }

    public static void method(String s, Consumer<String> c) {
        c.accept(s);
    }
    public static void method(String s, Consumer<String> c1, Consumer<String> c2) {
//        c1.accept(s);
//        c2.accept(s);
        // andThen c1.accept(s)后執行c2.accept(s) 等同于上面的寫法
        c1.andThen(c2).accept(s);
    }
}
Function介面

java.util.function.Function<T,R> 介面用來根據一個型別的資料得到另一個型別的資料,前者稱為前置條件,后者稱為后置條件
抽象方法:
R apply(T t) 根據型別T的引數獲取型別R的結果

public class Test {
    public static void main(String[] args) {
        Function<String,Integer> f = new Function<String, Integer>() {
            @Override
            public Integer apply(String s) {
                return Integer.parseInt(s);
            }
        };

        Integer apply = f.apply("100");
        System.out.println(apply);

        Function<String,Integer> f2 = s -> Integer.parseInt(s);
        System.out.println(f2.apply("200"));
    }
}

默認方法:andThen

Function介面中有一個默認的andThen方法,用來進行組合操作,與Consumer介面相同

public class Test {
    public static void main(String[] args) {
        method5("10", (String s) -> {
            return Integer.parseInt(s);
        }, (Integer i) -> {
            return i * 10;
        });
        method5("100", s -> Integer.parseInt(s), i -> i * 10);
        method5("1000", Integer::parseInt, i -> i * 10);
    }
    private static void method5(String s, Function<String, Integer> f1, Function<Integer, Integer> f2) {
//        Integer i = f1.apply(s);
//        Integer n = f2.apply(i);
        Integer n = f1.andThen(f2).apply(s);
        System.out.println(n);
    }
}

Function的前置條件泛型和后置條件泛型可以相同

Predicate介面

java.util.function.Predicate 判斷型介面
抽象方法: boolean test(T t) 回傳boolean

public class predicateInterface {
    public static void main(String[] args) {
        method("HelloWorld.java", (String s) -> {
            return s.toLowerCase().endsWith(".java");
        });

        method("Hello.java", s -> s.toLowerCase().endsWith(".java"));

    }
    public static void method(String filename, Predicate<String> p) {
        boolean b = p.test(filename);
        System.out.println(b);
    }
}

默認方法
Predicate<T> and(Predicate<? super T> other) 并且, 底層使用 &&
Predicate<T> or(Predicate<? super T> other) 或者, 底層使用 ||
Predicate<T> negate() 取反, 底層使用 !

public class Test {
    public static void main(String[] args) {
        method("Helloworld" ,s -> s.contains("H"), s -> s.contains("W"));
    }
    private static void method(String str ,Predicate<String> one, Predicate<String> two) {
        boolean b1 = one.test(str);
        boolean b2 = two.test(str);
        System.out.println("字串符合要求嗎:" + (b1 && b2));

        boolean isValid = one.and(two).test(str);
        System.out.println("字串符合要求嗎:" + isValid);
    }
}

public class Test {
    public static void main(String[] args) {
        method("Helloworld" ,s -> s.contains("H"), s -> s.contains("W"));
    }
    private static void method(String str ,Predicate<String> one, Predicate<String> two) {
        boolean b1 = one.test(str);
        boolean b2 = two.test(str);
        System.out.println("字串符合要求嗎:" + (b1 || b2));

        boolean isValid = one.or(two).test(str);
        System.out.println("字串符合要求嗎:" + isValid);
    }
}


public class Test {
    public static void main(String[] args) {
       isLong("aaa", new Predicate<String>() {
           @Override
           public boolean test(String s) {
               return  s.length()<5;
           }
       });
       isLong("bbbaa",s -> s.length()>=5);
    }
    public static void isLong(String s , Predicate<String> p){
        boolean test = p.test(s);
        System.out.println(!test);
        boolean b2 =  p.negate().test(s);
        System.out.println(b2);
    }
}

方法參考

前提

Lambda運算式中只有一句話時 可能使用

格式

符號表示 : ::
符號說明 : 雙冒號為方法參考運算子,而它所在的運算式被稱為方法參考
推導與省略 : ** 如果使用Lambda,那么根據“可推導就是可省略**”的原則,無需指定引數型別,也無需指定的多載形式——它們都將被自動推導

應用Lambda運算式 , 在accept方法中接收字串 , 目的就是為了列印顯示字串 , 那么通過Lambda來使用它的代碼很簡單:

public class DemoPrintSimple {
    private static void printString(Consumer<String> data, String str) {
        data.accept(str);
    }
    public static void main(String[] args) {
      	printString(s -> System.out.println(s), "Hello World");
    }
}

使用方法參考進行簡化

public class DemoPrintRef {
    private static void printString(Consumer<String> data, String str) {
        data.accept(str);
    }
    public static void main(String[] args) {
      	printString(System.out::println, "HelloWorld");
    }
}

其他參考

public class _5_functionInterface {
    public static void main(String[] args) {
        method("100", (String s) -> {
            return Integer.parseInt(s);
        });
        method("10", s -> Integer.parseInt(s));
        /*
            類名參考靜態方法
                類名::方法名
         */
        method("1000", Integer::parseInt);
        /*
            類名參考構造方法
                類名::new
         */
        method2("張三", Person::new);
        method2("李四", Person::new);
        method2("王五", s -> new Person(s));
        method3(Person::new);
         /*
            陣列參考構造方法
                資料型別[]::new
         */
        method4(5,int[]::new);
        method4(3, (Integer i) -> {
            return new int[i];
        });
        method4(1, i -> new int[i]);

    }

    public static void method(String s, Function<String, Integer> f) {
        Integer n = f.apply(s);
        System.out.println(n);
    }
    private static void method2(String s, Function<String, Person> f) {
        Person p = f.apply(s);
        System.out.println(p);
    }
    private static void method3(Supplier<Person> su) {
        Person p = su.get();
        System.out.println(p);
    }
    private static void method4(Integer i, Function<Integer, int[]> f) {
        int[] arr = f.apply(i);
        System.out.println(Arrays.toString(arr));
    }
}
class Person {
    private String name;

    public Person() {}
    public Person(String name) {
        this.name = name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                '}';
    }
}

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/550639.html

標籤:其他

上一篇:UML類圖

下一篇:返回列表

標籤雲
其他(157682) Python(38083) JavaScript(25376) Java(17984) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • java -- 函式式編程

    函式式編程 面向物件過分強調“必須通過物件的形式來做事情”,而函式式思想則盡量忽略面向物件的復雜語法——強調做什么,而不是怎么做。 有時只是為了做某事情而不得不創建一個物件,而傳遞一段代碼才是我們真正的目的。 Lambda Lambda是一個匿名函式,可以理解為一段可以傳遞的代碼。 當需要啟動一個線 ......

    uj5u.com 2023-04-21 07:40:40 more
  • UML類圖

    UML類圖介紹 概念 UML中的類圖(Class Diagram)用于表示類、介面、實體等之間相互的靜態關系。雖然名字叫作類圖,但是圖中并不僅僅只有類。 類結構 繼承 該圖展示了Parentclass和Childclass兩個類之間的關系,其中的空心箭頭表明了兩者之間的層次關系。箭頭由子類指向父類, ......

    uj5u.com 2023-04-21 07:40:27 more
  • 關于Java中物件的向上轉型和向下轉型

    什么是多型? 同一個類呼叫同一個方法會產生不同的影響/結果 這就是多型 public class Pet{ public void eat(){ System.out.println("Pet eat...") } } class Dog extends Pet{ public void eat() ......

    uj5u.com 2023-04-21 07:40:19 more
  • Flask 背景關系是什么 ?

    哈嘍大家好,我是咸魚。今天我們來聊聊什么是 Flask 背景關系 咸魚在剛接觸到這個概念的時候腦子里蹦出的第一個詞是 CPU 背景關系 今天咸魚希望通過這篇文章,讓大家能夠對 Flask 背景關系設計的初衷以及應用有一個基本的了解 Flask 背景關系 我們在使用 Flask 開發 web 程式的時候,通常 ......

    uj5u.com 2023-04-21 07:40:08 more
  • 【0基礎學爬蟲】爬蟲基礎之自動化工具 Selenium 的使用

    大資料時代,各行各業對資料采集的需求日益增多,網路爬蟲的運用也更為廣泛,越來越多的人開始學習網路爬蟲這項技術,K哥爬蟲此前已經推出不少爬蟲進階、逆向相關文章,為實作從易到難全方位覆寫,特設【0基礎學爬蟲】專欄,幫助小白快速入門爬蟲,本期為自動化工具 Selenium 的使用。 概述 目前,很多網站都 ......

    uj5u.com 2023-04-21 07:39:47 more
  • 關于Java中方法多載和方法重寫

    方法重寫是子類繼承父類(默認繼承Object類)后覆寫父類的方法 需要保證同名 同參 同回傳值 且訪問權限范圍不能縮小(public>protected>default>private) public class Father{ public int method(){ return -1; } } ......

    uj5u.com 2023-04-21 07:39:34 more
  • Go語言入門8(匿名函式 閉包)

    匿名函式 閉包 匿名函式 ? 顧名思義,就是沒有名字的函式。。。 func(){ fmt.Println("我就是匿名函式") } 匿名函式的兩種執行方法 將匿名函式賦給一個變數 定義后立即執行匿名函式 // 講匿名函式賦給一個變數 tmp := func(){ fmt.Println("我是匿名函 ......

    uj5u.com 2023-04-21 07:39:30 more
  • Opencv在VS2022中的配置(Python)

    下載Opencv 先去官網https://opencv.org/opencv-4-7-0/下載, 找到適合你設備的版本下載Windows就是Win pack,完成后進行安裝即可,一路同意默認就行,可以更改安裝位置,但路徑上盡可能以英文,以防止后面不必要的問題。 2.下載Python 首先是版本 發文 ......

    uj5u.com 2023-04-21 07:38:40 more
  • Django筆記二十六之資料庫函式之數學公式函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十六之資料庫函式之數學公式函式 這一篇來介紹一下公式函式,主要是數學公式。 其中 sin,cos 這種大多數情況下用不上的就不介紹了,主要介紹下面幾種: Abs() 絕對值 Ceil() 向上取整 Floor() 向下取整 Mod() ......

    uj5u.com 2023-04-21 07:38:29 more
  • Flask 背景關系是什么 ?

    哈嘍大家好,我是咸魚。今天我們來聊聊什么是 Flask 背景關系 咸魚在剛接觸到這個概念的時候腦子里蹦出的第一個詞是 CPU 背景關系 今天咸魚希望通過這篇文章,讓大家能夠對 Flask 背景關系設計的初衷以及應用有一個基本的了解 Flask 背景關系 我們在使用 Flask 開發 web 程式的時候,通常 ......

    uj5u.com 2023-04-21 07:33:10 more