2020年最新Java全套教程函數式接口

Java函數式接口

1. 函數式接口

1.1 概述
<code>如果說一個接口內有且只有一個方法,而且該方法是一個缺省屬性為public abstract方法,該接口可以稱之為是一個函數式接口。
自定義函數式接口,還有系統中提供的函數式接口
Comparator Runnable



可以直接理解JDK1.8的新特徵,Lambda表達式來使用。


Lambda表達式對比匿名內部類使用
1. 簡化了代碼結構
2. 節約了內存資源
3. 讓程序員更加關注,我要做什麼,而不是為了做什麼需要完成什麼
/<code>
1.2 @FunctionalInterface 使用
<code>類似於
@Override

開啟代碼重寫格式嚴格檢查
/**
* 使用@FunctionalInterface檢查函數式接口格式問題
* 要求當前接口中有且只有一個缺省屬性為public abstract的方法
*
* @author Anonymous 2020/3/11 9:55
*/

@FunctionalInterface
public interface FunctionalType {

   void test();

}/<code>
1.3 使用自定義的函數式接口作為方法的參數使用
<code>package com.qfedu.a_functional;



/**
* 自定義函數式接口作為方法的參數演示
*
* @author Anonymous 2020/3/11 9:55
*/
public class Demo1 {

   public static void main(String[] args) {

       /*
       使用匿名內部類來完成函數式接口的使用,但是這種方式有悖於函數式接口的目的
       Low


       useFunctionalInterface(new FunctionalType() {
           @Override
           public void test() {
               System.out.println("匿名內部類的匿名對象直接作為方法的參數。");
           }
       });
       int(*) (char **, int *)
           C語言中的函數指針
           如果是C語言中,這需要的參數是方法名
       */
      useFunctionalInterface(() -> System.out.println("函數式接口 lambda表達式實現完成方法,實現目的"));


  }



   /**
    * 使用一個函數式接口作為方法的參數
    *
    * @param ft 函數式接口的實現類對象,或者說直接操作本質,直接傳入Lambda表達式
    */
   public static void useFunctionalInterface(FunctionalType ft) {

       ft.test();

  }

}
代碼中使用函數式接口
1. 讓程序的目的性更強
2. 提供複用,普適性的價值
3. 節約資源/<code>

2. 函數式編程思想

2.1 Lambda延遲執行
2.1.1 日誌記錄
<code>日誌是否保存會存在等級限制
演示一個根據不同的等級來記錄log日誌
要求:

等級 == 1 記錄log日誌,其他情況不記錄
package com.qfedu.b_lambda;



enum Level {

   /**
    * 枚舉測試
    */
   HIGH, MIDDLE, LOWER
}



/**
* 日誌等級記錄操作
*
* @author Anonymous 2020/3/11 10:17
*/
public class Demo1 {

   public static void main(String[] args) {

       /*
       這裡存問題:
           "異常位置XXX," + "異常問題XXX," + "異常時間XXX" 字符疊加過程,會產生
           5個字符串
           這5個字符串如果Level.HIGH等級是有用的,但是除此之外是沒有任何作用的。
           MIDDLE,LOWER是沒有必要進行字符串累加,存在資源浪費問題。


           字符串的累加過程,需要經過Level判斷之後才可以執行,避免沒有必要的性能浪
           費。


           這裡就可以使用Lambda表達式執行的延遲性,在沒有滿足level情況下,不去做字
           符串累加過程。
           這裡需要【函數式接口】

        */
       log(Level.MIDDLE, "異常位置XXX," + "異常問題XXX," + "異常時間XXX");

  }



   /**
    * 判斷等級是否需要記錄當前日誌信息
    *
    * @param level 等級,枚舉類型
    * @param logMsg 需要記錄的日誌信息
    */
   public static void log(Level level, String logMsg) {

       // 判斷是否滿足枚舉類型 Level.HIGH要求
       if (Level.HIGH == level) {

           System.err.println(logMsg);

      }

  }

}/<code>
2.1.2 使用函數式接口提供日誌信息功能
<code>這裡需要一個函數式接口,返回值類型是String類型,其他的無所謂。
package com.qfedu.b_lambda;
 
/**
* 提供返回值為String類型方法的函數式接口
*
* @author Anonymous 2020/3/11 10:52
*/
@FunctionalInterface
public interface LogMessage {
    /**

     * 函數式接口中方法內容,該方法的返回值是String類型
     *
     * @return String類型返回值
     */
    String returnLogMessage();
}
package com.qfedu.b_lambda;
 
/**
* 使用函數式接口完成Log日誌記錄問題
*
* @author Anonymous 2020/3/11 10:53
*/
public class Demo2 {
    public static void main(String[] args) {
        String msg1 = "異常位置XXX,";
        String msg2 = "異常問題XXX,";
        String msg3 = "異常時間XXX";
 
        log(Level.LOWER, () -> {
            System.out.println("Lambda表達式執行!!!");
            return msg1 + msg2 + msg3;
        });
    }
 
    /**
     * 根據日誌等級Level來確定是否需要記錄日誌
     *
     * @param level Level枚舉類型,有三個數據 HIGH MIDDLE LOWER
     * @param lm LogMessage函數式接口做方法的參數
     */
    public static void log(Level level, LogMessage lm) {
        /*
        發現當Level等級為HIGH,執行對應的lm.returnLogMessage();
        Level等級不是HIGH不執行對應的方法。
 
        Lambda執行延遲問題不是Lambda效率執行慢,而是在執行之前多了一個判斷

        是在判斷之後才可以執行對應的代碼。
            不執行代碼字符串不會產生拼接導致的資源浪費問題,從而提高效率。
         */
        if (Level.HIGH == level) {
            // 通過函數式接口獲取調用對應的returnLogMessage()方法
            System.err.println(lm.returnLogMessage());
        }
    }
 
    public static void testEnum(int level) {
        if (Level.HIGH.getStatus() == level) {
 
        }
    }
}/<code>
2.2 Lambda作為方法參數和返回值
<code>參數演示:
                   Runnable接口
package com.qfedu.b_lambda;
 
/**
* Runnable接口函數式接口使用,作為方法的參數
*
* @author Anonymous 2020/3/11 11:18
*/
public class Demo3 {
    public static void main(String[] args) {
        // 匿名內部類來完成對應當前Runnable接口實現類對象使用,作為Thread構造方法參數
        // low
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("線程代碼");
            }
        }).start();

 
        // Lambda表達式直接作為方法的參數
        Thread thread = new Thread(() -> {
 
            System.out.println("線程執行需要時間");
 
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("線程執行");
        }
        , "線程");
 
        thread.start();
    }
}
Java中提供的比較接口Comparator
                   利用一些返回值作為方法中操作的調節
                  
public interface Comparator {
                   int compare(T o1, T o2);
}
package com.qfedu.b_lambda;
 
import java.util.Arrays;
import java.util.Comparator;
 
/**
* Lambda表示完成函數式接口,利用返回值作為其他操作所需的數據
*
* @author Anonymous 2020/3/11 11:25
*/
public class Demo4 {
    public static void main(String[] args) {
        /*
        字符串排序默認是一個字典順序
         */

        String[] arr = {"eeeeeeee", "2a","dddd",  "1bb", "ccccccc", "3fffff"};
 
        Arrays.sort(arr);
        System.out.println(Arrays.toString(arr));
 
        System.out.println("-----------------------------------------");
 
        // 利用一個函數式接口完成的方法,利用方法的返回值作為當前sort方法運行
        // 所需參數,該參數用於比較規則約束
        Arrays.sort(arr, stringComparator());
        System.out.println(Arrays.toString(arr));
 
        System.out.println("-----------------------------------------");
 
        Arrays.sort(arr, (a, b) -> a.length() - b.length());
 
        Arrays.sort(arr, Comparator.comparingInt(String::length));
        /*
        Comparator.comparingInt(String::length)
 
       Comparator:接口
        comparingInt:按照Int類型方式比較判斷
        String:表示比較的類型是String,比較什麼類型用什麼類型
        length:按照String類型的哪一種方式比較
        */
        System.out.println(Arrays.toString(arr));
 
 
    }
 
    /**
     * 按照字符串長度排序,返回值類型是一個Comparator<string>接口
     * 這裡需要完成Comparator接口中的compare方法
     *
     * @return 已經完成方法體的Comparator接口,並且數據類型是String類型
     */

    public static Comparator<string> stringComparator() {
        /*
        public interface Comparator {
            int compare(T o1, T o2);
        }
         */
        return (a, b) -> b.length() - a.length();
    }
}
 
/<string>/<string>
/<code>

3. Java中提供的常用函數式接口

3.1 JDK常用函數式接口概述
<code>java.util.function包名 。提供了很多函數式接口
                   規範了一些操作,提升了開發效率,更加專注於目的性!!!
                  
                   Supplier 生產者, 返回一個指定類型的數據
                   Consumer 消費者, 消耗一個指定類型的數據
                   Predicate 判斷調節,過濾使用
                   Function 類型轉換,根據你指定的類型T, 轉換成對應類型R
/<code>
3.2 Supplier 生產者,返回一個指定的數據類型
<code>java.util.function.Supplier
                   有且只有一個方法
                                      T get();
                                      不需要參數,返回指定T類型數據
                                      什麼都不吃,擠的都是輸出。。。
package com.qfedu.c_supplier;
 
import com.qfedu.b_lambda.Level;
 
import java.util.function.Supplier;
 
/**
* Supplier函數式接口演示
*
* @author Anonymous 2020/3/11 14:44
*/
public class Demo1 {
    public static void main(String[] args) {
        String msg1 = "異常位置XXX,";
        String msg2 = "異常問題XXX,";
        String msg3 = "異常時間XXX";
 
        /*
        這裡需要的是一個函數式接口,直接傳入一個lambda表達式
         */
        log(Level.HIGH, () -> {
            System.out.println("Lambda表達式執行!!!");
            return msg1 + msg2 + msg3;
        });
 
        /*
        Lambda表達式優化
         */
        log(Level.HIGH, () -> msg1 + msg2 + msg3);
    }
 
    /**
     * 根據日誌等級Level來確定是否需要記錄日誌

     *
     * @param level Level枚舉類型,有三個數據 HIGH MIDDLE LOWER
     * @param supplier Supplier函數式接口,利用T get() 完成提供數據操作
     */
    public static void log(Level level, Supplier<string> supplier) {
        /*
        Supplier函數式接口利用get方法,提供對應的返回指定String類型數據的操作
         */
        if (Level.HIGH == level) {
            // 通過函數式接口獲取調用對應的returnLogMessage()方法
            System.err.println(supplier.get());
        }
    }
}/<string>
/<code>
找出數組中最大值所在下標位置
<code>package com.qfedu.c_supplier;
 
import java.util.function.Supplier;
 
/**
* 利用函數式接口Supplier其中get方法,找出數組中最大值下標位置
*
* @author Anonymous 2020/3/11 14:54
*/
public class Demo2 {
    public static void main(String[] args) {
        int[] array = {1, 3, 5, 7, 9, 2, 4, 6, 8, 10};
 
        /*
        getMax方法需要的參數是一個Supplier函數式接口,這裡可以使用Lambda表達式完成
         */
        int max = getMax(() -> {
            int index = 0;
 

            for (int i = 1; i < array.length; i++) {
                if (array[index] < array[i]) {
                    index = i;
                }
            }
 
            return index;
        });
 
        System.out.println(max);
    }
 
    /**
     * 利用函數式接口完成一個getMax,提供一個操作思想
     *
     * @param sup Supplier函數式接口
     * @return 最大值下標位置
     */
    public static int getMax(Supplier<integer> sup) {
        return sup.get();
    }
}/<integer>/<code>
引出滿足更多普適性代碼的函數式接口使用方式
<code>package com.qfedu.c_supplier;
 
import java.util.function.Supplier;
 
/**
* 演示Supplier函數式接口使用,對於方法的拓展能力和
* 普適性滿足
*
* @author Anonymous 2020/3/11 15:06
*/
public class Demo3 {
    public static void main(String[] args) {
        Integer[] array = {1, 3, 5, 7, 9, 2, 4, 6, 8, 10};
 
        Integer max = getMax(array, () -> {
            Integer temp = array[0];
 
            for (int i = 1; i < array.length; i++) {

                if (temp < array[i]) {
                    temp = array[i];
                }
            }
 
            return temp;
        });
 
        System.out.println(max);
 
        System.out.println("-------------------------------------------");
 
        Person[] persons = {new Person(1, "騷磊", 16),
                new Person(2, "老黑", 66),
                new Person(3, "老付", 36),
                new Person(4, "老高", 26),
                new Person(5, "汙雲", 96),
                new Person(6, "帥棟", 106)
        };
 
        Person max1 = getMax(persons, () -> {
            Person p = persons[0];
 
            for (int i = 1; i < persons.length; i++) {
                if (p.getAge() < persons[i].getAge()) {
                    p = persons[i];
                }
            }
 
            return p;
        });
 
        System.out.println(max1);
    }
 
    /**
     * 找出任意類型數組中最大數據
     *
     * @param arr 任意類型數組,同時約束當前泛型的使用規則
     * @param sup Supplier函數式接口,要利用get方法,返回指定T類型數據
     * @param 泛型
     * @return 和數組類型一致的數據

     */
    public static T getMax(T[] arr, Supplier sup) {
        return sup.get();
    }
}
/<code>
3.3 Consumer消費者,處理數據
<code>Consumer
                   操作使用的方式是
                   void accept(T t);
                                      根據接口指定的數據類型接收對應數據,進行處理和消費,對外沒有任何的返回
                                      至於處理的過程,展示,處理,計算。。。
package com.qfedu.d_consumer;
 
import java.util.function.Consumer;
 
/**
* 使用Consumer處理數據
*
* @author Anonymous 2020/3/11 15:24
*/
public class Demo1 {
    public static void main(String[] args) {
        // 該方法需要的參數是一個String類型,同時使用Consumer接口處理數據
        // 因為Consumer接口是一個函數式接口,可以使用Lambda表達式
        testConsumer("宮保雞丁,番茄牛腩,醬牛肉,黃燜雞米飯", (str) -> {
            String[] split = str.split(",");
            for (String s : split) {

                System.out.println(s);
            }
        });
    }
 
    /**
    * 給予當前方法一個String類型,通過Consumer函數式接口中的accept方法完成對應
     * 字符串處理
     *
     * @param str String類型字符串
     * @param consumer Consumer處理數據的函數式接口
     */
    public static void testConsumer(String str, Consumer<string> consumer) {
        consumer.accept(str);
    }
}/<string>
/<code>
andThen
<code>package com.qfedu.d_consumer;
 
import java.util.function.Consumer;
 
/**
* Consumer接口andThen使用
* 需要兩個Consumer接口,兩個Consumer接口進行組合處理,對數據進行消費
*
* andThen(Consumer con)
*      調用格式
*          con1.andThen(con2).accept(T t);
*          等價於一下操作
*          con1.accept(t);
*          con2.accept(t);
*
* @author Anonymous 2020/3/11 15:57
*/
public class Demo2 {
    public static void main(String[] args) {
        /*
        該方法需要兩個Consumer函數式接口,這裡可以使用兩個Lambda表達式操作

         */
        testAndThen("鄭州加油!!!中國加油!!!",
                (str) -> System.out.println(str)
                ,
                (str) -> System.err.println(str)
                );
    }
 
    /**
     * 使用兩個Consumer消費者方式處理str數據,首先是con1處理,再來con2處理
     *
     * @param str  需要處理的String類型數據
     * @param con1 Consumer<string> 處理String類型函數式接口
     * @param con2 Consumer<string> 處理String類型函數式接口
     */
    public static void testAndThen(String str, Consumer<string> con1, Consumer<string> con2) {
        /*
        con1.accept(str);
        con2.accept(str);
 
        允許組合拳
        con1.andThen(con2).andThen(con1).andThen(con2).andThen(con1).andThen(con2).accept(str);
        */
        con1.andThen(con2).accept(str);
    }
}/<string>/<string>/<string>/<string>
/<code>
3.4 Predicate 判斷數據是否合適,返回true/false
<code>Predicate一般用於調節判斷,過濾數據的方法
                   函數式接口中指定的方法
                   boolean test(T t);
                                      處理T類型數據,返回boolean true / false
package com.qfedu.e_predicate;
 

import java.util.function.Predicate;
 
/**
* 演示Predicate基本使用
*      boolean test(T t)
*
* @author Anonymous 2020/3/11 16:11
*/
public class Demo1 {
    public static void main(String[] args) {
 
        // Predicate函數式接口,使用Lambda表達式作為方法的參數
        boolean b = testPredicate("鄭州奧力給!!!中國奧力給!!!",
                (str) -> {
                   return str.contains("加油");
                });
 
        System.out.println("ret : " + b);
 
        System.out.println("---------------------------");
 
        /*
        優化Lambda表達式,
            因為是一個參數,小括號可以省略
            就一行代碼,大括號可以省略
            return也可以省略
         */
        testPredicate("鄭州奧力給!!!中國奧力給!!!", str -> str.contains("加油"));
    }
 
    /**
     * 使用Predicate函數式接口利用boolean test(T t)對於當前數據進行判斷操作,
     * 返回boolean類型數據
     *
     * @param str 需要進行判斷數據的String類型字符串
     * @param pre 處理使用Predicate函數式接口

     * @return 判斷接口是否滿足要求,滿足返回true,不滿足返回false
     */
    public static boolean testPredicate(String str, Predicate<string> pre) {
        return pre.test(str);
    }
}
 /<string>
/<code>
and 與
<code>package com.qfedu.e_predicate;
 
import java.util.function.Predicate;
 
/**
* Predicate and使用
* default修飾方法add(Predicate pre)
*      and就是邏輯運算符裡面的 &&
*      同真為真,有假【即】假
*      需要對兩個Predicate進行判斷處理
*
*      例如:
*          pre1.test(str) && pre2.test(srt);
*          ==> pre1.and(pre2).test(str);
*
* @author Anonymous 2020/3/11 16:19
*/
public class Demo2 {
    public static void main(String[] args) {
 
        /*
        這裡需要量Predicate接口,使用Lambda
         */
        boolean ret = testAnd("趕緊復工吧,不要搞事情了!!!",
                str -> str.length() > 5,
                str -> str.startsWith("趕緊"));
 
        System.out.println(ret);
    }

 
    /**
     * 組合判斷
     *
     * @param str  需要判斷的字符串
     * @param pre1 判斷方式1
     * @param pre2 判斷方式2
     * @return 處理結果 true, false
     */
    public static boolean testAnd(String str, Predicate<string> pre1, Predicate<string> pre2) {
        // return pre1.test(str) && pre2.test(str)
        return pre1.and(pre2).test(str);
    }
}/<string>/<string>
/<code>
or 或
<code>package com.qfedu.e_predicate;
 
import java.util.function.Predicate;
 
/**
* Predicate or演示
*
* @author Anonymous 2020/3/11 16:32
*/
public class Demo3 {
    public static void main(String[] args) {
        boolean ret = testOr("國家之強大,國外人羨慕不得~~",
                str -> str.length() < 10,
                str -> str.contains("國家"));
 
        System.out.println(ret);
    }
 
    /**
     * or 組合判斷
     *
     * @param str  需要判斷的字符串
     * @param pre1 判斷方式1
     * @param pre2 判斷方式2
     * @return 處理結果 true, false
     */

    public static boolean testOr(String str, Predicate<string> pre1, Predicate<string> pre2) {
        // return pre1.test(str) || pre2.test(str);
        return pre1.or(pre2).test(str);
    }
}/<string>/<string>/<code>
negate 非
<code>package com.qfedu.e_predicate;
 
import java.util.function.Predicate;
 
/**
* Predicate negate()操作
*
* @author Anonymous 2020/3/11 16:36
*/
public class Demo4 {
    public static void main(String[] args) {
        boolean ret = testNegate("疫情總會過去的!!!",
                str -> str.length() < 5);
        System.out.println(ret);
    }
 
    /**
     * negate操作
     *
     * @param str 字符串
     * @param pre Predicate函數式接口
     * @return 處理結果
     */
    public static boolean testNegate(String str, Predicate<string> pre) {
        // return !pre.test(str);
        return pre.negate().test(str);
    }
}/<string>/<code>
ArrayList中使用Predicate刪除指定數據
<code>package com.qfedu.e_predicate;
 
import com.qfedu.c_supplier.Person;
 
import java.util.ArrayList;
 
/**
* ArrayList,使用Predicate作為條件約束刪除對應的數據

*
* @author Anonymous 2020/3/11 16:41
*/
public class Demo5 {
    public static void main(String[] args) {
        ArrayList<person> list = new ArrayList<>();
 
        list.add(new Person(1, "騷磊", 16));
        list.add(new Person(2, "老黑", 66));
        list.add(new Person(3, "老付", 36));
        list.add(new Person(4, "老高", 26));
        list.add(new Person(5, "汙雲", 96));
        list.add(new Person(6, "帥棟", 96));
 
        // 直接安排Predicate函數式接口來約束對應的條件,進行刪除操作
        // 代碼的閱讀性,普適性提升
        // 以及代碼的冗餘程度降低
        list.removeIf(person -> person.getAge() > 40 && person.getId() > 3);
 
        System.out.println(list);
    }
}/<person>/<code>
3.5 Function 類型轉換
<code>使用R apply(T t)
                   轉換指定類型T到R
package com.qfedu.f_function;
 
import com.qfedu.c_supplier.Person;
 
import java.util.function.Function;
 
/**
* Function 函數式接口
*      R apply(T)
*
* @author Anonymous 2020/3/11 16:50
*/
public class Demo1 {

    public static void main(String[] args) {
        // Integer類型轉換成一個String
        String change = change(10, i -> i + "");
        System.out.println(change);
 
        // 利用函數式接口處理一個String類型,轉換成對應的Person類型
        Person person1 = change("1,騷磊,16", str -> {
            String[] split = str.split(",");
            Person person = new Person();
 
            person.setId(Integer.parseInt(split[0]));
            person.setName(split[1]);
            person.setAge(Integer.parseInt(split[2]));
 
            return person;
        });
 
        System.out.println(person1);
    }
 
    /**
     * 轉換格式的方法,要求數據從Integer類型轉換到指定的String類型
     *
     * @param i 需要轉換的Integer類型
     * @param fun 轉換使用的Function函數式接口
     * @return 返回值的是String類型
     */
    public static String change(Integer i, Function<integer> fun) {
        return fun.apply(i);
    }
 
    public static Person change(String str, Function<string> fun) {
        return fun.apply(str);
    }
}/<string>/<integer>
/<code>
andThen
<code>package com.qfedu.f_function;
 
import java.util.function.Function;
 

/**
* Function
*     default修飾andThen方法使用
*
* @author Anonymous 2020/3/11 17:01
*/
public class Demo2 {
    public static void main(String[] args) {
        String s = testAndThen(10,
                i -> i + "",
                i -> i + "測試");
 
        System.out.println(s);
    }
 
    /**
     * 兩次轉換過程
     *
     * @param i 需要處理的類型
     * @param fun1 Function函數接口
     * @param fun2 Function函數接口
     * @return String類型
     */
    public static String testAndThen(int i, Function<integer> fun1, Function<string> fun2) {
 
        // andThen使用,最後apply方法參數類型是fun1要求的轉換參數類型
        return fun1.andThen(fun2).apply(i);
    }
}/<string>/<integer>
/<code>

源碼請私信或下載

https://gitee.com/qfjiaoyan/javabase


分享到:


相關文章: