Java14了還不知道Lambda表達式?

更多知識,請移步我的小破站:http://hellofriend.top

1. 個人理解

Lambda 表達式是一種簡潔高效的實現匿名內部類的一種方式,可以使代碼變得更清晰、更靈活,大大增加代碼可讀性。

2. 匿名內部類和Lambda表達式的比較

下面通過實際的例子,將匿名內部類與 Lambda 表達式進行比較,效果一目瞭然。

在 java8 之前使用匿名內部類是這樣的:

public void Test3() {
    List<Student> list = fitterStudent(students, new MyPredicate<Student>() {
        @Override
        public boolean judge(Student stu) {
            return stu.getSex().equals("男");
        }
    });
}

可以看到真正有用的只有return stu.getSex().equals("男");這一行代碼,但是因爲格式,確不得不把其他的好多行都寫出來,毫無疑問這樣的話,代碼的可讀性會大大降低。

下面來看一下使用Lambda表達式的效果:

public void Test2() {
      List<Student> list = fitterStudent(students, (stu) -> stu.getSex().equals("男"));
} 

看到效果了吧,原來的6行代碼,現在只需要1行。是不是很厲害…

3. Lambda表達式的基本語法

java8中引入一個新的操作符->,稱爲箭頭操作符或者爲 lambda 操作符。

箭頭操作符將拉lambda表達式拆分成兩個部分:
左側:參數列表,所實現接口抽象方法的參數列表(函數式接口)
右側:所需執行的功能,稱爲lambda體
lambda表達式需要"函數式接口"(接口中只有一個抽象方法)支持
可以使用註解@FunctionalInterface 幫忙檢查是否是函數式接口

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

 /**
     * @Description 創建一個線程輸出語句
     * @Param []
     * @return void
     **/
    @Test
    public void test1() {
        Runnable r0 = new Runnable() {
            @Override
            public void run() {
                System.out.println("匿名內部類的方式:Hello Lambda!");
            }
        };
        r0.run();
        //語法格式一:無參數,無返回值
        Runnable r1 = () -> System.out.println("Lambda表達式的方法:Hello Lambda!");
        r1.run();
    }

語法格式二: 有一個參數,無返回值

/**
     * @Description 參數是啥輸出啥 
     * @Param []
     * @return void
     **/
    @Test
    public void test2(){
        //聲明一個消費型接口(有一個參數,但是無返回值)調用accept方法,傳入一個參數
        Consumer<String> con = (x) -> System.out.println(x);
        //語法格式二: 有一個參數,無返回值
        con.accept("Hello Lambda!");
    }

語法格式三: 若只有一個參數,則參數的小括號可以省略不寫

Consumer<String> con = (x) -> System.out.println(x);

上面的語句等價於:

Consumer<String> con = x -> System.out.println(x);

語法格式四: 有多個參數,lambda體中有多個語句,並且有返回值

 /**
     * @Description 比較兩個整數
     * @Param []
     * @return void
     **/
    @Test
    public void test4(){
        //用於比較的接口Comparable,提供了一個比較的方法
        Comparator<Integer> com = (x, y) -> {
            //有多個參數,並且lambda體中有多個語句,必須使用大括號,並且有返回值
            System.out.println("x = " + x);
            System.out.println("y = " + y);
            //Integer類就是Comparator的實現類
            return Integer.compare(x,y);
        };
        System.out.println(com.compare(1, 520));
    }

語法格式五: 有多個參數並且有返回值,只有一條語句(return 和大括號都可以省略)

Comparator<Integer> com = (x, y) -> {
    return Integer.compare(x,y);
};

上面的寫法等價於:

Comparator<Integer> com = (x,y) ->  Integer.compare(x, y);

語法格式六: lambda表達式的參數列表數據類型可以不寫,jvm自動推斷(推薦不寫)

Comparator<Integer> com = (Integer x,Integer y) ->  Integer.compare(x, y);

上面的寫法等價於:

Comparator<Integer> com = (x,y) ->  Integer.compare(x, y);

小總結

  • 左右遇一括號省->左邊參數列表中若只有一個參數,那麼小括號可以省略,->右邊如果只有一條語句,那麼大括號可以省略。
  • 左側推斷類型省->左邊參數的參數類型可以省略。
  • 右側一條return省:如果Lambda表達式具有返回值,並且只有一條語句,那麼可以省略return關鍵字。

Lambda表達式既然這麼好用,那麼是不是什麼時候都可以應用呢?

不是的,Lambda 表達式必須要有函數式接口的支持,即接口中必須只有一個抽象方法。

4. 四大基本的函數式接口

那麼問題來了,難道每次使用 Lambda 表達式都需要自己寫一個函數式接口嗎?

當然不是了,java8 現在內置了四大基本的函數式接口,而且還有好多函數式接口,所以沒有想象的那麼麻煩,下面就開始介紹 java8 內置的四大函數式接口。

① Consumer 消費型接口(有一個參數,但是無返回值) void accept(T t);

@Test
public void test7() {
    happy(20000, (money) -> System.out.println("我今天花了"+money+"元"));
}
/**
 * @Description happy的作用就是想參數傳遞給 Consumer
 * @Param [money, consumer]
 * @return void
 **/
public void happy(double money,Consumer<Double> consumer) {
    consumer.accept(money);
}

不寫happy方法可以直接這樣寫:

Consumer<Double> consumer = (x) -> {
        System.out.println("我今天花了"+x+"元");
    };
    consumer.accept(2000d);

② Supplier 供給型接口(無參數,但是有返回值) T get();

@Test
public void test8() {
    //獲得5個0-100的隨機數
    List<Integer> numList = getRandomNum(5, () -> (int)(Math.random()*100));
    numList.forEach(System.out::println);
}

/**
 * @Description 獲得num個sup.get()得到的結果
 * @Param [num, sup]
 * @return java.util.List<java.lang.Integer>
 **/
public List<Integer> getRandomNum(int num, Supplier<Integer> sup){
    List<Integer> list = new ArrayList<>();
    for (int i = 0; i < num; i++) {
        list.add(sup.get());
    }
    return list;
}

③ Function 函數型接口(有一個參數,有返回值) R apply(T t);

@Test
public void test9() {
    String result = strHandler("hello ", (str) -> {
        return str+= "Lambda";
    });
    System.out.println(result);
}

/**
 * @Description  將str傳遞給函數型接口
 * @Param [str 前綴, fun]
 * @return java.lang.String
 **/
public String strHandler(String str, Function<String, String> fun) {
    return fun.apply(str);
}

④ Predicate 斷言型接口(有一個參數,返回值爲布爾類型) boolean test(T t);

@Test
public void Test10() {
    List<String> list = Arrays.asList("Hello","world","my","name","is","lg");
    List<String> result = filterStr(list, (str) -> {
        //判斷字符串是否含有o
        return str.contains("o");
    });
    result.forEach(System.out::println);
}

/**
 * @Description 根據 斷言型接口提供的條件,篩選集合
 * @Param [list, pre]
 * @return java.util.List<java.lang.String>
 **/
public List<String> filterStr(List<String> list, Predicate<String> pre){
    List<String> resultList = new ArrayList<>();
    for (String string : list) {
        if(pre.test(string)) {
            resultList.add(string);
        }
    }
    return resultList;
}

5. java8之後的接口可以這麼寫

@FunctionalInterface
interface myInterface{
    //只有一個沒實現的方法,這個接口就叫做函數式接口
    void fun1();
    //默認實現
    default int fun2(int a,int b){
        return a+b;
    }
    //靜態方法
    static int fun3(int a,int b){
        return a*b;
    }
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章