【Java8新特性】- Lambda表達式

Java8新特性 – Lambda表達式

😄生命不息,寫作不止
🔥 繼續踏上學習之路,學之分享筆記
👊 總有一天我也能像各位大佬一樣
🏆 一個有夢有戲的人 @怒放吧德德
🌝分享學習心得,歡迎指正,大家一起學習成長!

lambda表達式.jpg

簡介

Lambda 表達式(lambda expression)是一個匿名函數,Lambda表達式基於數學中的λ演算得名,直接對應於其中的lambda抽象(lambda abstraction),即沒有函數名的函數。Lambda表達式可以表示閉包(注意和數學傳統意義上的不同)。這是來自百度百科對lambda的介紹,實際上lambda就是簡化了匿名函數的編寫,只需一行程式碼就能代替繁雜的程式碼。
lambda主要是可以非常簡潔的形式調用我們的匿名函數介面。

簡單例子

首先聲明一個介面,並且編寫實現類實現這個介面

// UserService
public interface UserService {
    void add();
}
// UserServiceImpl
public class UserServiceImpl implements UserService {
    @Override
    public void add() {
        System.out.println("UserServiceImpl --- add");
    }
}

一般來說是通過new實現類從而拿到實現中的add方法,如果通過new介面類就需要使用匿名內部類的形式調用介面。IDEA會提示使用lambda表達式。
image.png

如下程式碼可以看一下對比。

public static void main(String[] args) {
    UserService userService = new UserServiceImpl();
    userService.add();

    UserService user = new UserService() {
        @Override
        public void add() {
            // 匿名內部介面業務邏輯
            System.out.println("匿名內部介面業務邏輯");
        }
    };

    // Lamdba表達式
    UserService user2 = () -> System.out.println("匿名內部介面業務邏輯");
    user2.add();
}

Lambda表達式的規範

Java中的Lambda表達式的規範,必須是為函數介面。

使用函數式介面

使用Lambda表達式依賴於函數式介面:
1、使用@FunctionalInterface註解來聲明函數介面
2、在這個函數介面中只能有一個抽象方法
3、在函數介面中可以定義object類中的方法
4、可以有靜態方法
*函數式介面(Functional Interface) 就是一個有且僅有一個抽象方法,但是可以有多個非抽象方法的介面。
更多函數式介面可以查看菜鳥聯盟//www.runoob.com/java/java8-functional-interfaces.html

函數式介面的定義

通過@FunctionalInterface註解聲明介面類,在java中也有許多內置的函數介面,詳情看菜鳥聯盟。

@FunctionalInterface // 聲明函數式介面
public interface UserService {
    void add();

    String toString(); // Object類中的方法

    static void hello() { // 靜態方法
        System.out.println("hello");
    }
}

Lambda表達式的基礎語法

表達式格式

(參數) -> {方法體}

格式說明

():存放參數,留空就代表沒有參數。函數介面的參數列表,不需要寫類型,需要定義參數名稱。
->:是新引入的語法格式,代表指向動作。
{}:方法體

無參方法調用

在介面類中聲明一個無參的抽象方法,通過lambda表達式來完成調用。()不需要存放參數,最後將會返回一個實現類對象。在通過調用對象的get方法。

// 匿名內部介面業務邏輯
UserService user2 = () -> System.out.println("匿名內部介面業務邏輯");
user2.get();

更加簡便的寫法

((UserService)() -> System.out.println("匿名內部介面業務邏輯")).get();

含參數方法調用

在MathService定義一個含有參數的抽象方法,原本的方式通過匿名內部介面。可以通過使用lambda表達式更加簡便,並且可以省去{},也不需要return。

MathService math = new MathService() {
    @Override
    public Integer add(int a, int b) {
        return a + b;
    }
};

MathService mathService = (a, b) -> a + b;

System.out.println(mathService.add(1, 1));

方法引入

規則

方法引入需要遵循規範:方法參數列表、返回類型與函數介面參數列表與返回類型必須
要保持一致。
方法引入的規則:
       靜態方法引入: 類名::(靜態)方法名稱
       對象方法引入: 類名:: 實例方法名稱
       實例方法引入:new對象 對象實例::方法引入
       構造函數引入:類名::new
方法引用提供了非常有用的語法,可以直接引用已有的java類或對象的方法或構造器。方法引用其實也離不開Lambda表達式,
與lambda聯合使用 ,方法引用可以使語言的構造更加緊湊簡潔,減少冗餘程式碼。方法引用提供非常有用的語法,可以直接引用已有的java類或者對象中方法或者構造函數,
方法引用需要配合Lambda表達式語法一起使用減少程式碼的冗餘性問題。
1664976332232.png

實例

構造器引用

通過構造器引用實例化對象,

public static void main(String[] args) {
    // 使用匿名內部類
    CarService carService = new CarService() {
        @Override
        public Car getCar() {
            return null;
        }
    };
    // 使用引用方法
    CarService car = Car::new;
    car.getCar();
}
public class Car {
    private String name;
    private String brand;

    public Car() {
    }
}
public interface CarService {
    Car getCar();
}

靜態方法引入

UserService u = UserService::hello;
u.get();

在userservice中,有一個抽象get方法和一個靜態方法

@FunctionalInterface
public interface UserService {
    void get();
    static void hello() {
        System.out.println("hello");
    }
}

運行後會輸出hello

hello

Process finished with exit code 0

對象方法引入

這是一種更為方便的寫法, 我記得在mybatis-plus使用自帶條件查詢的時候會用到這種方式,以下用簡單例子來實現。java8中提供了public interface Function<T, R>的類,這個類也是使用@FunctionalInterface註解,可見也是函數式介面。
程式碼:

// 在car中聲明一個方法
public class Car {
    public String Info() {
        return "保時捷 - 帕拉梅拉";
    }
}
// 函數式介面
@FunctionalInterface
public interface CarInFoService {
    String getCar(Car car);
}

測試採用了三種方式進行比較

public class LambdaTest4 {
    public static void main(String[] args) {
        System.out.println("**************匿名內部類**************");
        CarInFoService carInFoService = new CarInFoService() {
            @Override
            public String getCar(Car car) {
                return car.Info();
            }
        };
        System.out.println(carInFoService.getCar(new Car()));
        System.out.println("**************lambda**************");
        CarInFoService carInFoService2 = (car) -> car.Info();
        System.out.println(carInFoService2.getCar(new Car()));
        System.out.println("**************對象方法引入**************");
        CarInFoService carInFoService3 = Car::Info;
        System.out.println(carInFoService3.getCar(new Car()));

        // R apply(T t); T  apply方法傳遞的參數類型 : R apply 方法返回的類型
        Function<String, Integer> function = String::length;
        System.out.println(function.apply("lyd_code"));
    }
}

結果
image.png

Lambda表達式遍歷

通過foreach循環遍歷,forEach實際上需要使用匿名內部類Consumer<? super E>。
image.png
程式碼如下

public class LambdaTest5 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("lyd");
        list.add("tom");
        list.add("jack");
        list.forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println("name: " + s);
            }
        });
        System.out.println("lambda表達式");
        /**
         * s:遍歷鏈表所得到的元素字元串
         */
        list.forEach(s -> System.out.println("name: " + s));
    }
}

測試結果
image.png

Lambda排序

通過Comparator匿名內部類

public class LambdaTest6 {
    public static void main(String[] args) {
        ArrayList<Student> students = new ArrayList<>();
        students.add(new Student("lyd", 99));
        students.add(new Student("lkj", 55));
        students.add(new Student("llm", 67));
        students.add(new Student("lss", 87));

//        students.sort(new Comparator<Student>() {
//            @Override
//            public int compare(Student o1, Student o2) {
//                return o1.getScore() - o2.getScore();
//            }
//        });

        students.sort((o1, o2) -> o1.getScore() - o2.getScore());

        students.forEach(student -> System.out.println("name: " + student.getName() + " score: " + student.getScore()));
    }
}

結果
image.png

為了寫好部落格,包括程式碼、文字,我是經過斟酌了的,如果有錯誤,歡迎指正!感謝觀看!
👍創作不易,如有錯誤請指正,感謝觀看!記得點贊哦!👍

Tags: