首頁>技術>

一、Lambda 簡介

Lambda 表示式,也可稱為閉包,是一個匿名函式。我們可以把 Lambda 表示式理解為是一段可傳遞的程式碼(像資料一樣傳遞)。即 Lambda 允許把函式作為一個方法的實參引數(函式當作引數傳遞到方法中)。是Java8的其中一個很重要的新特性。從而可以寫出更簡潔,更靈活的程式碼。作為一種更加緊湊的程式碼風格,使java的語言表達能力得到了提升。

public class LambdaDemo {    public static void main(String[] args) {        List<String> list = Arrays.asList("A", "B", "C");        //x -> System.out.println(x),就是一個匿名函式,即Lambda表示式,作為實參傳給dealList方法        dealList(list, x -> System.out.println(x));    }	    public static void dealList(List<String> list, Consumer<String> consumer) {    	// 遍歷list中的每一個元素,傳給consumer物件的accept函式,進行呼叫        for (String x : list) {            consumer.accept(x);        }    }}1234567891011121314

Lambda 表示式是對某些介面的簡單實現,但不是所有介面都可以使用 Lambda 表示式來實現的,Lambda 規定能被 Lambda 表示式實現的介面中,它只能只有一個需要被實現的方法(函式),但不要求介面中只能只有一個方法。因為Java8中有另外一個新特性,即 default 關鍵字修飾的介面方法有預設實現,這個預設的方法是可以不需要子類實現的,可使用@FunctionalInterface註解來強制使介面只能有一個需要被實現的方法。

二、Lambda 優勢2.1 案例一

以前我們要寫一個類才能實現一個介面,並且實現裡面的抽象方法。如方式一:

// 介面public interface Human {	// 抽象方法,需要被實現    void speak();}12345
// 實現類,並且實現抽象方法public class Man implements Human {    @Override    public void speak() {        System.out.println("I am man!");    }}1234567
public class Main {    public static void main(String[] args) {        // 方式一 直接編寫實現類        Human human = new Man();        human.speak();    }}1234567

如果我們不想編寫一個單獨的實現類(Man),則可以用匿名內部類。如方式二:

public class Main {    public static void main(String[] args) {        // 方式一 直接編寫實現類        Human human = new Man();        human.speak();        // 方式二 匿名內部類        Human human1 = new Human() {            @Override            public void speak() {                System.out.println("I am woman!");            }        };        human1.speak();    }}12345678910111213141516

但方式二中,有用的就只有System.out.println("I am woman!");這一行,所以有了Lambda表示式,可以這樣寫,如方式三:

public class Main {    public static void main(String[] args) {        // 方式一 直接編寫實現類        Human human = new Man();        human.speak();                // 方式二 匿名內部類        Human human1 = new Human() {            @Override            public void speak() {                System.out.println("I am woman!");            }        };        human1.speak();                // 方式三 Lambda表示式        Human human2 = () -> System.out.println("I am woman!");        human2.speak();    }}1234567891011121314151617181920
2.2 案例二

再假如我們要對一個Student類的陣列按指定條件進行過濾,如下:

public class Student {    private String name;    private int age;    private double score;}12345
public class Main {    public static void main(String[] args) {        List<Student> students = Arrays.asList(new Student("張三", 18, 89.5),                new Student("李四", 20, 60), new Student("王五", 19, 100), new Student("趙六", 22, 89));        // 過濾出年齡大於等於20的學生        List<Student> stus1 = filterStudentByAge(students);        System.out.println(stus1);        // 過濾出成績大於80的學生        List<Student> stus2 = filterStudentByScore(students);        System.out.println(stus2);    }    // 過濾出年齡大於等於20的學生    private static List<Student> filterStudentByAge(List<Student> students) {        List<Student> stus = new ArrayList<>();        for (Student stu : students) {            if (stu.getAge() >= 20) {                stus.add(stu);            }        }        return stus;    }    // 過濾出成績大於80的學生    private static List<Student> filterStudentByScore(List<Student> students) {        List<Student> stus = new ArrayList<>();        for (Student stu : students) {            if (stu.getScore() > 80) {                stus.add(stu);            }        }        return stus;    }}1234567891011121314151617181920212223242526272829303132333435363738

按上面的方式,如果要按另外一個條件過濾呢,又要寫一個方法。那可以用策略模式處理,編寫一個抽象策略介面,然後編寫多個不同策略類實現它。

// 策略介面public interface MyPredicate<T> {    boolean test(T t);}1234
// 過濾出年齡大於等於20的學生public class filterStudentByAge implements MyPredicate<Student> {    @Override    public boolean test(Student t) {        return t.getAge() >= 20;    }}1234567
// 過濾出成績大於80的學生public class filterStudentByScore implements MyPredicate<Student> {    @Override    public boolean test(Student t) {        return t.getScore() > 80;    }}1234567
public class Main {    public static void main(String[] args) {        List<Student> students = Arrays.asList(new Student("張三", 18, 89.5),                new Student("李四", 20, 60), new Student("王五", 19, 100), new Student("趙六", 22, 89));        // 過濾出年齡大於等於20的學生        List<Student> stus1 = filterStudent(students, new FilterStudentByAge());        System.out.println(stus1);        // 過濾出成績大於80的學生        List<Student> stus2 = filterStudent(students, new FilterStudentByScore());        System.out.println(stus2);    }    // 按myPredicate策略過濾出滿足條件的學生    private static List<Student> filterStudent(List<Student> students,            MyPredicate<Student> myPredicate) {        List<Student> stus = new ArrayList<>();        for (Student stu : students) {            if (myPredicate.test(stu)) {                stus.add(stu);            }        }        return stus;    }}12345678910111213141516171819202122232425262728

但是以上方式,每增加一個過濾條件,就要編寫一個策略類,太麻煩。所以我們就用匿名內部類方式。

// 匿名內部類形式 過濾出年齡大於等於18的學生List<Student> stus3 = filterStudent(students, new MyPredicate<Student>() {    @Override    public boolean test(Student t) {        return t.getAge() > 18;    }});System.out.println(stus3);12345678

但我們會覺得匿名內部類還是太麻煩,無用程式碼太多,有用的程式碼其實就只有return t.getAge() > 18;,於是 Lambda 表示式發揮的作用就來了:

// Lambda形式 過濾出年齡大於等於18的學生List<Student> stus4 = filterStudent(students, t -> t.getAge() > 18);System.out.println(stus4);123

這時還是有人會問,那我們定義的介面MyPredicate和方法filterStudent(),好像沒什麼作用呀。然而官方已經想到這一點,它內建了一些通用介面,我們可以使用它。例如斷言的介面 Predicate,那我們就用如下方式,完全不用寫介面MyPredicate和方法filterStudent(),如下:

// 按myPredicate策略過濾出滿足條件的學生private static List<Student> filterStudent(List<Student> students,        Predicate<Student> predicate) {    List<Student> stus = new ArrayList<>();    for (Student stu : students) {        if (predicate.test(stu)) {            stus.add(stu);        }    }    return stus;}1234567891011

當然,如果你會使用Stream(可以看我另外一篇文章),只需要寫下面的程式碼,如下:

public class Main {    public static void main(String[] args) {        List<Student> students = Arrays.asList(new Student("張三", 18, 89.5),                new Student("李四", 20, 60), new Student("王五", 19, 100), new Student("趙六", 22, 89));        // 過濾出年齡大於等於20的學生        students.stream().filter(t -> t.getAge() >= 20).forEach(System.out::println);                System.out.println("-------------------------------------");        // 過濾出成績大於80的學生        students.stream().filter(t -> t.getScore() > 80).forEach(System.out::println);    }}12345678910111213141516
三、Lambda 語法

語法:() -> {}():Lambda的形參列表,也就是接口裡面那個抽象方法的形參列表。->:Lambda的運算子,可以理解為引數和Lambda體的分隔符。{}:實現了介面中的抽象方法的方法體。

我們還是以一個簡單的例子,由淺到深學習 Lambda 語法。按照語法,我們可以寫出如下 Lambda 表示式,(String name, int age) 是引數列表,-> 是分隔符,{} 中的程式碼是方法體。

// 函式介面@FunctionalInterfacepublic interface Human {    // 抽象方法,需要被實現    String speak(String name, int age);}123456
public class LambdaDemo {    public static void main(String[] args) {        Human human = (String name, int age) -> {            System.out.println("My name is " + name + " ,I am " + age + " years old.");            return name;        };        human.speak("Mr.nobody", 18);    }}123456789

當然,() 括號內的引數型別還能省略(推薦)。

public class LambdaDemo {    public static void main(String[] args) {        Human human = (name, age) -> {            System.out.println("My name is " + name + " ,I am " + age + " years old.");            return name;        };        human.speak("Mr.nobody", 18);    }}123456789

如果是隻有一個引數,() 也能省略。

@FunctionalInterfacepublic interface Human {    // 抽象方法,需要被實現    String speak(String name);}12345
public class LambdaDemo {    public static void main(String[] args) {        Human human = name -> {            System.out.println("My name is " + name + ".");            return name;        };        human.speak("Mr.nobody");    }}123456789

如果,方法體 {} 中,只有一行語句,{} 也能省略(推薦)。

@FunctionalInterfacepublic interface Human {    // 抽象方法,需要被實現    void speak(String name, int age);}12345
public class LambdaDemo {    public static void main(String[] args) {        Human human = (name, age) -> System.out                .println("My name is " + name + " ,I am " + age + " years old.");        human.speak("Mr.nobody", 18);    }}1234567

如果方法體需要返回值,而且只有一行語句,那 {} 大括號和 return 關鍵字都可以省略(推薦)。

@FunctionalInterfacepublic interface Human {    // 抽象方法,需要被實現    String speak(String name, int age);}12345
public class LambdaDemo {    public static void main(String[] args) {        Human human = (name, age) -> "My name is " + name + " ,I am " + age + " years old.";        human.speak("Mr.nobody", 18);    }}

12
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 「python課程,精心總結」巢狀迴圈