日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java8新特性之函数式接口

發布時間:2025/3/15 java 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java8新特性之函数式接口 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、函數接口

Lambda的設計者們為了讓現有的功能與Lambda表達式良好兼容,考慮了很多方法,于是產生了函數接口這個概念。函數接口指的是只有一個函數的接口,這樣的接口可以隱式轉換為Lambda表達式。java.lang.Runnable和java.util.concurrent.Callable是函數式接口的最佳例子。在實踐中,函數式接口非常脆弱:只要某個開發者在該接口中添加一個函數,則該接口就不再是函數式接口進而導致編譯失敗。為了克服這種代碼層面的脆弱性,并顯式說明某個接口是函數式接口,Java 8 提供了一個特殊的注解@FunctionalInterface(Java 庫中的所有相關接口都已經帶有這個注解了),舉個簡單的函數式接口的定義:

@FunctionalInterface public interface Functional {void method(); }

有一點需要注意,默認方法和靜態方法不會破壞函數式接口的定義(且方法數不限),因此如下的代碼是合法的。

@FunctionalInterface public interface FunctionalDefaultMethods {void method();default void defaultMethod() {}public static void staticMethod(){} default void defaultMethod1() {}public static void staticMethod1(){} }

默認方法和抽象方法之間的區別在于抽象方法需要實現,而默認方法不需要。接口提供的默認方法會被接口的實現類繼承或者覆寫

private interface Defaulable {// Interfaces now allow default methods, the implementer may or // may not implement (override) them.default String notRequired() { return "Default implementation"; } } private static class DefaultableImpl implements Defaulable { }private static class OverridableImpl implements Defaulable {@Overridepublic String notRequired() {return "Overridden implementation";} } //Defaulable接口使用關鍵字default定義了一個默認方法notRequired() 。DefaultableImpl類實現了這個接口,同時默認繼承了這個接口中的默認方法; OverridableImpl類也實現了這個接口,但覆寫了該接口的默認方法,并提供了一個不同的實現。

重點注意:函數式接口就是一個有且僅有一個(除和Object中方法有相同簽名的外)抽象方法

二、lambda完整例子

三個函數式接口(無參、單參無返回、多參有返回)

@FunctionalInterface public interface MyInterface {void say(); } @FunctionalInterface public interface MyInterface1 {void SayHello(String name); } @FunctionalInterface public interface MyInterface2 {Integer calculator(Integer x,Integer y); }

調用

public class realizeInterface implements MyInterface {@Overridepublic void say() {System.out.println("hello");}public static void main(String[] args) {//傳統的方法是定義一個類實現接口方法,再實例化類后進行調用realizeInterface realizeInterface=new realizeInterface();realizeInterface.say();//lambda方式實現,其中()表示show方法傳入的參數為空,只有一個參數時,(x)的括號可以省略,直接寫x/*x表示接口方法中傳入一個參數,類型會自動推斷;System.out.println(“hello from lambda”)表示實現say()方法的方法體;當方法體只有一行時,可以省略大括號*/MyInterface myInterface=()->System.out.println("hello from lambda");MyInterface1 myInterface1= x->System.out.println("The interface's arg is " + x);MyInterface2 myInterface2=(x,y)-> x+y;myInterface.say();myInterface1.SayHello("java");System.out.println("result is "+myInterface2.calculator(5, 6));} }

在創建線程時的應用:

Runnable r = new Runnable() { @Override public void run() {System.out.println("Hello World!" + "This is a Thread!");}};r.run(); //基于lambda表達式實現 Runnable r = () -> System.out.println("Hello World!" + "This is a Thread!");r.run();

三、java內置核心四大函數式接口

  • Consumer接口(支持泛型,Lambda表達式左邊有一個參數,無返回值)
  • @FunctionalInterface public interface Consumer<T> {void accept(T t); }
  • Supplier接口(實現輸入空,返回一個值)
  • @FunctionalInterface public interface Supplier<T> {T get(); }
  • Function接口
    (輸入一個T類型的值,返回一個R類型的值。例如我們實現:輸入一個List 類型的值,返回該list中最大的整數值。)
  • @FunctionalInterface public interface Function<T, R> {R apply(T t); }
  • Predicate接口
    (該接口實現,輸入一個T類型的值,然后返回一個boolean類型。)
  • @FunctionalInterface public interface Predicate<T> {boolean test(T t); }

    綜合例子:

    public class JavaFunctionalInterface {public static void testConsumer() {Consumer<Float> consumer =(x) -> {System.out.println("He consumes " + x + "¥");};consumer.accept((float) 50.5);}public static void testSupplier(){Supplier<Integer> supplier =() -> {String s = "hello world";Integer n = s.length();return n;};Integer n = supplier.get();System.out.println("n 的值為:" + n);}public static void testFunction(){Function<List<Integer>, Integer> function =(x) -> {int n = x.size();Integer value = x.get(n-1);return value;};List<Integer> list = Arrays.asList(1, 2, 3);Integer lastValue = function.apply(list);System.out.println("The lastValue is " + lastValue);}public static void testPredicate(){Predicate<String> predicate =(x) -> {int n = x.length();if (n > 10) {System.out.println("n 大于 10");return true;}else {System.out.println("n 小于 10");return false;}};predicate.test("Hello world!");}public static void main(String[] args) {testConsumer();testSupplier();testFunction();testPredicate();} }

    四、lambda使用之 方法引用與構造器引用

    方法引用
    若 Lambda 體中的功能,已經有相應的方法提供了實現,可以在Lambda體中引用該方法。(可以將方法引用理解為 Lambda 表達式的另外一種表現形式)。
    舉一個簡單示例:

    @FunctionalInterface public interface Consumer<T> {void accept(T t); }

    用該接口的Lambda表達式實現字符串的輸出功能

    @Testpublic void test(){Consumer<String> consumer = (s) -> {if (s != null) {System.out.println(s);}else{System.out.println("s 為空");}};consumer.accept("java");System.out.println("------------");consumer.accept(null);} }

    此時,如果Lambda體中的內容已經被其它方法實現了,此時不必在Lambda體中再實現一遍了,直接調用相應的方法即可。例如有一個Info類中的show方法實現了相同的功能:

    public class Info<T> {public void show(T s){if (s != null) {System.out.println(s);}else{System.out.println("s 為空");}} }

    此時在用Consumer的函數接口Lambda表達式時,可以用下面的形式,實現了相同的功能。

    public void test(){Info<String> info = new Info<>();Consumer<String> consumer = info::show;consumer.accept("java");System.out.println("-----------");consumer.accept(null);}

    在上面的示例中,Consumer接口中的accept方法的參數和返回值要和Info中的show方法中的參數和返回值一致方可用上面的形式。
    Lambda的方法引用形式有以下三種形式:

    1. 對象的引用 :: 實例方法名2. 類名 :: 靜態方法名3. 類名 :: 實例方法名
  • 對象的引用 :: 實例方法名
  • //用Lambda表達式實現打印字符串public void test1(){Consumer<String> consumer = (x) -> System.out.println(x);consumer.accept("java");} //用Lambda的方法引用方式實現字符串打印 public void test1(){ PrintStream ps = System.out;/*Consumer接口中的accept方法的參數和返回值同println方法的參數和返回值相同*/Consumer<String> consumer1 = ps::println;consumer1.accept("java");} //兩種方式運行結果相同,都輸出:java
  • 類名 :: 靜態方法名
    例如我們要用Comparator接口的compare方法實現比較兩個整數值的大小
  • //用Lambda表達式表示如下public void test3(){Comparator<Integer> comparator = (x, y) -> {Integer differ = x < y ? -1 : ((x == y) ? 0 : 1);return differ;};Integer differ1 = comparator.compare(10, 5);System.out.println("differ1 : " + differ1);} //用Lambda的方法引用 /*由于Integer類中的compare靜態方法已經實現了比較兩個整數的大小,重要的是,Integer中的compare方法與Comparator接口中的compare方法的參數和返回值一致。*/public void test3(){Comparator<Integer> comparator2 = Integer::compare;Integer differ2 = comparator2.compare(10, 5);System.out.println("differ2 : " + differ2);} //以上兩種形式運行,輸出結果相同:differ1 : 1
  • 類名 :: 實例方法名
  • //用Lambda表達式實現比較兩個字符串的大小public void test4(){BiPredicate<String, String> bp =(x, y) -> {Boolean flag = x.equals(y);return flag;};Boolean flag = bp.test("java", "java");System.out.println("flag : " + flag);} //用Lambda的方法引用 /*String 類中的equals方法已經實現了比較兩個字符串大小,可以通過該方法實現Lambda的方法引用。前兩種方式都是函數式接口的輸入參數和實現Lambda體功能的方法的傳入方法一致,如果不一致時,函數式接口中兩個參數,其中一個通過方法調用另一參數時可以用下面形式*/public void test4(){ BiPredicate<String, String> bp1 = String::equals;Boolean flag1 = bp1.test("java", "java");System.out.println("flag1 : " + flag1);} //BiPredicate接口中傳入兩個參數"java”和“java”,一個參數通過方法調用另一個,"java".equals("java") ,在用Lambda的方法引用時可以寫成 String::equals的形式。

    構造器引用

    public class User {private String name;private Integer age;public User() {super();}public User(String name) {super();this.name = name;}public User(String name, Integer age) {super();this.name = name;this.age = age;}@Overridepublic String toString() {return "User [name=" + name + ", age=" + age + "]";} }

    1、用Lambda表達式實現分別通過User的無參構造器和一個有參構造器獲得User對象

    public void test5(){Supplier<User> supplier =() -> {return new User();};User user1 = supplier.get(); System.out.println("user1 : " + user1);System.out.println("-----------------------------------");Function<String, User> function =(x) -> {User user = new User(x);return user;};User user = function.apply("java");System.out.println("user : " + user);}

    2、Lambda的構造器引用分別實現通過User的無參構造器和一個有參構造器獲得User對象

    public void test6(){Supplier<User> supplier = User::new;/*get方法無參,有返回值,所以調用的User的無參構造器,返回User對象*/User user1 = supplier.get();System.out.println("user1 : " + user1);System.out.println("-----------------------------------");Function<String, User> function = User::new;/*apply方法有一個參數,有返回值,所以調用User的一個參數的構造器,并返回User對象*/User user = function.apply("java");System.out.println("user : " + user);}

    兩種方式輸出結果相同:

    user1 : User [name=null, age=null] ----------------------------------- user : User [name=java, age=null]

    Lambda的數組引用

    public void test7(){Function<Integer, String[]> function =(x) -> new String[x]; //省略retuen的寫法String[] ss = function.apply(5);System.out.println("ss.length : " + ss.length);Function<Integer, String[]> function1 = String[]::new;String[] sss = function1.apply(5);System.out.println("sss.length : " + sss.length);}

    文章參考

    與50位技術專家面對面20年技術見證,附贈技術全景圖

    總結

    以上是生活随笔為你收集整理的Java8新特性之函数式接口的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。