Java8新特性, Lambda表達式與函數式接口


 

Java8的新特性有哪些

 

 

 

 

新特性的特征:

 速度更快
 代碼更少(增加了新的語法:Lambda 表達式)
 強大的 Stream API
 便於並行
 最大化減少空指針異常:Optional
 Nashorn引擎,允許在JVM上運行JS應用

 

 

 

lambda表達式

 

什么是lambda表達式?

Lambda 是一個匿名函數,我們可以把 Lambda 表達式理解為是一段可以
傳遞的代碼(將代碼像數據一樣進行傳遞)。使用它可以寫出更簡潔、更 靈活的代碼。作為一種更緊湊的代碼風格,使Java的語言表達能力得到了
提升

 

 

為什么要有lambda表達式?

Lambda表達式。它可以讓你很簡潔地表示一個行為或傳遞代碼。現在你可以把Lambda 表達式看作匿名功能,它基本上就是沒有聲明名稱的方法,但和匿名類一樣,它也可以作為參 數傳遞給一個方法。 

 

 

哪些場景可以使用到lambda表達式?

 

?????

 

  

 

首先我們看下再沒有使用lambda的時候使用匿名內部類的對比

lambda與匿名內部類對比

  //匿名內部類
        Comparator<Integer> c1 = new Comparator<Integer>() {
            @Override
            public int compare(Integer t1, Integer t2) {
                return Integer.compare(t1,t2);
            }
        };
        int compareNumOne = c1.compare(12,13);
        System.out.println(compareNumOne); //-1

        System.out.println("==========Lambda==========");

        // lambda表達式
        Comparator<Integer> c2 = (c3,c4) -> Integer.compare(c3,c4);
        int compareNumTwo = c2.compare(11,10);
        System.out.println(compareNumTwo); // 1

 

可以看出lambda表達式簡潔了很多,直接了,不像以前這么難懂 還有一大堆的內部邏輯

 

匿名內部類

Button button = new Button("Send"); 
button.setOnAction(new EventHandler<ActionEvent>() {
  
    public void handle(ActionEvent event) {
            label.setText("Sent!!");
      }
});

 

這里,setOnAction方法的行為就用EventHandler參數化了。用Lambda表達式的話,看 起來就是這樣: 

button.setOnAction((ActionEvent event) -> label.setText("Sent!!")); 

 

 

 

上面可以看出lambda使用起來很方便的  簡單明了

 

lambda的使用

 

lambda的結構

 

 

 

 參數列表——這里它采用了Comparator中compare方法的參數,兩個Apple。 
 箭頭——箭頭->把參數列表與Lambda主體分隔開。 
 Lambda主體——比較兩個Apple的重量。表達式就是Lambda的返回值了。 

 

 1.舉例: (o1,o2) -> Integer.compare(o1,o2);
 * 2.格式:
 *      -> :lambda操作符 或 箭頭操作符
 *      ->左邊:lambda形參列表 (其實就是接口中的抽象方法的形參列表)
 *      ->右邊:lambda體 (其實就是重寫的抽象方法的方法體)


Lambda 表達式:在Java 8 語言中引入的一種新的語法元素和操 作符。這個操作符為 “->” ,該操作符被稱為 Lambda 操作符 或箭頭操作符。

它將 Lambda 分為兩個部分:

  左側:指定了 Lambda 表達式需要的參數列表

  右側:指定了 Lambda 體,是抽象方法的實現邏輯,也即 Lambda 表達式要執行的功能。

 

 

 

 

下面給出了Java 8中五個有效的Lambda表達式的例子

 

 

Lambda表達式的使用(分六種)

 

語法格式一:無參,無返回值

Runnable r1 =  () -> {System.out.println("Hello Lambda");};

r1.run();

語法格式二:Lambda需要一個參數,但是沒有返回值

Consumer<String> con = (String s) -> {System.out.println(s);};

con.accept("value");

語法格式三:數據類型可以省略,因為可由編譯器推斷得出,稱為“類型推斷”

 Consumer<String> con = (s) -> {System.out.println(s);};

 con.accept("value");

語法格式四:Lambda若只需要一個參數,參數的小括號可以省略

 Consumer<String> con = s -> {System.out.println(s);};

 con.accept("value");

語法格式五:Lambda需要兩個以上的參數,多條執行語句,並且可以有返回值

Consumer<Integer> con = (x,y) -> {

System.out.println(x);

return x.compareTo(y);

}

語法格式六:當Lambda體只有一條語句時,return與大括號

 Comparator<Integer> com = (o1, o2) -> o1.compareTo(o2);

 com.compreTo(10,13); 

 

 // 語法格式一:無參,無返回值
    @Test
    public void TestPOne(){
        Runnable r1 = new Runnable() {
            @Override
            public void run() {
                System.out.println(" I'm one");
            }
        };
        r1.run();

        System.out.println("=======lambda======");
        Runnable r2 = () -> System.out.println("I'm lambda'One");
        r2.run();
    }


    // 語法格式二:Lambda 需要一個參數,但是沒有返回值。
    @Test
    public void TestTwo(){
        Consumer<String> con1 = new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        con1.accept("老王");

        System.out.println("=======lambda======");
        Consumer<String> con2 = (String s1) -> {System.out.println(s1);};
        con2.accept("我是lambda老王");
    }


    //語法格式三:數據類型可以省略,因為可由編譯器推斷得出,稱為“類型推斷”
    // 類型推斷想我們之前遇到的泛型和數組一樣
    /* Consumer<String> con = new Consumer<>();  // 省略后面的String類型
        int [] len = new int [] {1,2,3}; 可以 寫成 int [] len = {1,2,3}
     */
    @Test
    public void TestThree(){
        Consumer<String> con = new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        con.accept("老王頭");

        System.out.println("=======lambda======");
        Consumer<String> con1 = (s) -> { System.out.println(s); };
        con1.accept("吾乃lambda老王頭");
    }


    //語法格式四:Lambda 若只需要一個參數時,參數的小括號可以省略
    @Test
    public void TestFour(){
        Consumer<String> con = new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        con.accept("老劉");
        System.out.println("=======lambda======");
        Consumer<String> con1 = s -> {System.out.println(s);};
        con1.accept("吾乃lambda老劉");

    }


    //語法格式五:Lambda 需要兩個或以上的參數,多條執行語句,並且可以有返回值
    @Test
    public void TestFive(){
        Comparator<Integer> com = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                System.out.println(o1);
                System.out.println(o2);
                return o1.compareTo(o2);
            }
        };
        System.out.println(com.compare(13, 14));

        System.out.println("=======lambda======");
        Comparator<Integer> com1 = (l1,l2) -> {
            System.out.println(l1);
            System.out.println(l2);
            return l1.compareTo(l2);
        };
        System.out.println(com1.compare(11, 10));
    }


    //語法格式六:當 Lambda 體只有一條語句時,return 與大括號若有,都可以省略
    @Test
    public void TestSix(){

        // 原有
        Comparator<Integer> com = (o1, o2) -> {return o1.compareTo(o2);};
        System.out.println(com.compare(10, 11));

        //優化后
        Comparator<Integer> com1 = (l1, l2) -> l1.compareTo(l2);
        System.out.println(com1.compare(20, 10));

    }

 

 

由上可以看出lambda只是修改了  以前寫法的方法體 方法后面的執行和參數的傳遞依舊時不變的  只需要看方法體怎么改變即可。

 

Summary

 * 3. Lambda表達式的使用:(分為6種情況介紹)
 *
 *    總結:
 *    ->左邊:lambda形參列表的參數類型可以省略(類型推斷);如果lambda形參列表只有一個參數,其一對()也可以省略
 *    ->右邊:lambda體應該使用一對{}包裹;如果lambda體只有一條執行語句(可能是return語句),省略這一對{}和return關鍵字
 *
 * 4.Lambda表達式的本質:作為函數式接口的實例
 *
 * 5. 如果一個接口中,只聲明了一個抽象方法,則此接口就稱為函數式接口。我們可以在一個接口上使用 @FunctionalInterface 注解,
 *   這樣做可以檢查它是否是一個函數式接口。
 *
 * 6. 所以以前用匿名實現類表示的現在都可以用Lambda表達式來寫。

 

 

 

函數式接口

 

什么是函數式接口

只包含一個抽象方法的接口,稱為函數式接口。 

 

為什么要有函數式接口

Java從誕生日起就是一直倡導“一切皆對象”,在Java里面面向對象(OOP) 編程是一切。但是隨着python、scala等語言的興起和新技術的挑戰,
Java不 得不做出調整以便支持更加廣泛的技術要求,也即java不但可以支持OOP還 可以支持OOF(面向函數編程)

說白了 函數式接口就是為了讓java能面向函數編程而創建的

 

函數式接口的作用

用函數式接口可以干什么呢?Lambda表達式允許你直接以內聯的形式為函數式接口的抽象方法提供實現,並把整個表達式作為函數式接口的實例(具體說來,是函數式接口一個具體實現 的實例)

 

   

 

 

你可以通過 Lambda 表達式來創建該接口的對象。(若 Lambda 表達式 拋出一個受檢異常(即:非運行時異常),那么該異常需要在目標接口的抽 象方法上進行聲明)。 

 

 

  我們可以在一個接口上使用 @FunctionalInterface 注解,這樣做可以檢 查它是否是一個函數式接口。同時 javadoc 也會包含一條聲明,說明這個 接口是一個函數式接口。 

  在java.util.function包下定義了Java 8 的豐富的函數式接口

   簡單的說,在Java8中,Lambda表達式就是一個函數式接口的實例。這就是 Lambda表達式和函數式接口的關系。也就是說,

    只要一個對象是函數式接口 的實例,那么該對象就可以用Lambda表達式來表示。

   所以以前用匿名實現類表  示的現在都可以用Lambda表達式來寫。

 

 

 

 

自定義函數式接口

只需要在自定義的接口上加入  @FunctionalInterface 注解即可讓這個接口成為函數事接口

@FunctionalInterface
public interface MyInterface {
    public void method1();
}

 

自定義函數接口與Lambda的使用

 

 

 

 

 

Java 內置四大核心函數式接口

 

 

 

其它接口

 

 

 

Lambda與函數式接口的使用

    // 根據傳遞參數輸出信息
    public void happyTime(double money, Consumer<Double> con){
        con.accept(money);
    }


    //根據給定的規則,過濾集合中的字符串。此規則由Predicate的方法決定
    public List<String> filterString(List<String> list, Predicate<String> pre){
        List<String> filterList = new ArrayList<>();
        for (String s:list
             ) {
            if(pre.test(s)){  // 如果參數s滿足定義的Predicate的String泛型
                filterList.add(s);
            }
        }
        return filterList;
    }



    @Test
    public void TestMonday(){
        happyTime(500, new Consumer<Double>() {
            @Override
            public void accept(Double aDouble) {
                System.out.println("去隔壁洗浴中心消費"+aDouble);
            }
        });

        System.out.println("=====lambda====");
        happyTime(4000, money -> System.out.println("買了大寶劍花費"+money));
    }

    @Test
    public void TestTuesday(){
        List<String> list = Arrays.asList("老王", "老張頭","隔壁老王","隔壁小姐姐");
        List<String> list1 = filterString(list, new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s.contains("老"); // 包含老的字符串
            }
        });
        System.out.println(list1);


        List<String> list2 = filterString(list,s -> s.contains("老") );
        System.out.println(list2);

    }

 

 

 

 

 lambda與方法搭配使用必須滿足函數式接口的要求,

 

下面既不是接口種的方法

 

 

Practices 

1:

      

 

 

 

(1) 這個Lambda沒有參數,並返回void。它類似於主體為空的方法:public void run() {}。
 (2) 這個Lambda沒有參數,並返回String作為表達式。
 (3) 這個Lambda沒有參數,並返回String(利用顯式返回語句)。
(4) return是一個控制流語句。要使此Lambda有效,需要使花括號,如下所示: (Integer i) -> {return "Alan" + i;}。 
(5)“Iron Man”是一個表達式,不是一個語句。要使此Lambda有效,你可以去除花括號 和分號,如下所示:(String s) -> "Iron Man"。或者如果你喜歡,可以使用顯式返回語 句,如下所示:(String s)->{return "IronMan";}。  
View Code

 

2: 下面哪些接口是函數式接口? 

public interface Adder{     
    int add(int a, int b);
 }

 public interface SmartAdder extends Adder{     
    int add(double a, double b); 
} 

public interface Nothing{ }
答案:只有Adder是函數式接口。 SmartAdder不是函數式接口,因為它定義了兩個叫作add的抽象方法(其中一個是從 Adder那里繼承來的)。 Nothing也不是函數式接口,因為它沒有聲明抽象方法。 
View Code

 

 

 

 

 

.


免責聲明!

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



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