關注微信公眾號【
Java之言】,領取學習資料和視頻,助你放棄編程之路!

系列文章目錄
| 序號 | 標題 | 文章鏈接 |
|---|---|---|
| 1 | 玩轉 Java8 Stream,讓你代碼更高效緊湊簡潔 | https://blog.csdn.net/chenlixiao007/article/details/112752413 |
| 2 | 玩轉 Java8 Optional,讓你代碼更緊湊簡潔且不再出現空指標 | https://blog.csdn.net/chenlixiao007/article/details/113358813 |
文章目錄
- 系列文章目錄
- 一、Lambda 簡介
- 二、Lambda 優勢
- 2.1 案例一
- 2.2 案例二
- 三、Lambda 語法
一、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);
}
}
}
Lambda 運算式是對某些介面的簡單實作,但不是所有介面都可以使用 Lambda 運算式來實作的,Lambda 規定能被 Lambda 運算式實作的介面中,它
只能只有一個需要被實作的方法(函式),但不要求介面中只能只有一個方法,因為Java8中有另外一個新特性,即default關鍵字修飾的介面方法有默認實作,這個默認的方法是可以不需要子類實作的,可使用@FunctionalInterface注解來強制使介面只能有一個需要被實作的方法,
// 此注解表明此介面為函式介面,即只能有一個抽象方法
@FunctionalInterface
public interface Human {
// 抽象方法,需要被實作
void eat(String name);
// default修飾的默認方法,不需要被子類實作
default void run() {
System.out.println("I can run...");
}
}
public static void main(String[] args) {
Human human = x -> System.out.println(x + " is eat");
human.eat("Mr.nobody");
human.run();
}
// 輸出結果
Mr.nobody is eat
I can run...
二、Lambda 優勢
2.1 案例一
以前我們要寫一個類才能實作一個介面,并且實作里面的抽象方法,如方式一:
// 介面
public interface Human {
// 抽象方法,需要被實作
void speak();
}
// 實作類,并且實作抽象方法
public class Man implements Human {
@Override
public void speak() {
System.out.println("I am man!");
}
}
public class Main {
public static void main(String[] args) {
// 方式一 直接撰寫實作類
Human human = new Man();
human.speak();
}
}
如果我們不想撰寫一個單獨的實作類(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();
}
}
但方式二中,有用的就只有
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();
}
}
2.2 案例二
再假如我們要對一個Student類的陣列按指定條件進行過濾,如下:
public class Student {
private String name;
private int age;
private double score;
}
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;
}
}
按上面的方式,如果要按另外一個條件過濾呢,又要寫一個方法,那可以用策略模式處理,撰寫一個抽象策略介面,然后撰寫多個不同策略類實作它,
// 策略介面
public interface MyPredicate<T> {
boolean test(T t);
}
// 過濾出年齡大于等于20的學生
public class filterStudentByAge implements MyPredicate<Student> {
@Override
public boolean test(Student t) {
return t.getAge() >= 20;
}
}
// 過濾出成績大于80的學生
public class filterStudentByScore implements MyPredicate<Student> {
@Override
public boolean test(Student t) {
return t.getScore() > 80;
}
}
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;
}
}
但是以上方式,每增加一個過濾條件,就要撰寫一個策略類,太麻煩,所以我們就用匿名內部類方式,
// 匿名內部類形式 過濾出年齡大于等于18的學生
List<Student> stus3 = filterStudent(students, new MyPredicate<Student>() {
@Override
public boolean test(Student t) {
return t.getAge() > 18;
}
});
System.out.println(stus3);
但我們會覺得匿名內部類還是太麻煩,無用代碼太多,有用的代碼其實就只有
return t.getAge() > 18;,于是 Lambda 運算式發揮的作用就來了:
// Lambda形式 過濾出年齡大于等于18的學生
List<Student> stus4 = filterStudent(students, t -> t.getAge() > 18);
System.out.println(stus4);
這時還是有人會問,那我們定義的
介面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;
}
當然,如果你會使用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);
}
}
三、Lambda 語法
語法:() -> {}
():Lambda的形參串列,也就是介面里面那個抽象方法的形參串列,
->:Lambda的運算子,可以理解為引數和Lambda體的分隔符,
{}:實作了介面中的抽象方法的方法體,
我們還是以一個簡單的例子,由淺到深學習 Lambda 語法,按照語法,我們可以寫出如下 Lambda 運算式,
(String name, int age)是引數串列,->是分隔符,{}中的代碼是方法體,
// 函式介面
@FunctionalInterface
public interface Human {
// 抽象方法,需要被實作
String speak(String name, int age);
}
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);
}
}
當然,
()括號內的引數型別還能省略(推薦),
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);
}
}
如果是
只有一個引數,() 也能省略,
@FunctionalInterface
public interface Human {
// 抽象方法,需要被實作
String speak(String name);
}
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");
}
}
如果,方法體
{}中,只有一行陳述句,{} 也能省略(推薦),
@FunctionalInterface
public interface Human {
// 抽象方法,需要被實作
void speak(String name, int age);
}
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);
}
}
如果
方法體需要回傳值,而且只有一行陳述句,那{}大括號和return關鍵字都可以省略(推薦),
@FunctionalInterface
public interface Human {
// 抽象方法,需要被實作
String speak(String name, int age);
}
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);
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/255569.html
標籤:java
上一篇:圖書管理系統
下一篇:python繪圖 ——蠟筆小新
