Java8新特性[Lambda運算式和函式式介面]
前言
實體代碼
策略設計模式
匿名內部類
Lambda運算式
學習Lambda
語法格式
1、無參,無回傳值
2、有一個引數,有回傳值
3、有多個引數,一個回傳值
4、有多個引數,只有一條陳述句
型別推斷
函式式介面
場景
訓練
Java內置函式介面
Comsumer 消費型介面
Supplier 供給型介面
Function 函式型介面
Predicate 斷言型介面
擴展
總結
前言
為什么要用Lambda運算式?
Lambda是一個匿名函式,我們可以把Lambda運算式理解為是一段可以傳遞的代碼,將代碼像資料一樣傳遞,這樣可以寫出更簡潔、更靈活的代碼,作為一個更緊湊的代碼風格,使Java語言表達能力得到了提升
實體代碼
Lambda運算式最先替代的就是匿名內部類,假設原來我們寫一個Comparator比較函式,采用匿名內部類的方式
/**
* 原來使用匿名內部類
*/
public static void test() {
// 使用匿名內部類,重寫Intger的 compare方法
Comparator
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1, o2);
}
};
// 傳入比較的方法
TreeSet<Integer> ts = new TreeSet<>(comparator);
}
123456789101112131415
復制代碼
然后在采用Lambda運算式后
/**
* 使用Lambda運算式解決匿名內部類需要撰寫大量模板語言的問題
*/
public static void test2() {
Comparator
// 傳入比較的方法
TreeSet<Integer> ts = new TreeSet<>(comparator);
}
123456789
復制代碼
策略設計模式
假設我們現在有一個需求,就是查找出員工里面年齡超過35的,我們使用策略設計模式
/**
-
員工類
-
@author: 陌溪
-
@create: 2020-04-05-12:13
*/
public class Employee {
private String name;
private int age;
private double salary;// set get
}
12345678910111213
復制代碼
然后創建一個介面,這里就是判定條件
/** -
介面
-
@param
*/
public interface MyPredicte{
public boolean test(T t);
}
12345678
復制代碼
我們實作這個介面
/**
-
按年齡過濾
-
@author: 陌溪
-
@create: 2020-04-05-12:23
*/
public class FilterEmployeeByAge implements MyPredicte{ @Override
public boolean test(Employee employee) {
return employee.getAge() > 35;
}
}
12345678910111213
復制代碼
然后在具體的例子中使用
/**-
獲取當前公司員工年齡大于35
*/
public static void test3() {
Listemployees = Arrays.asList(
new Employee("張三", 18, 3333),
new Employee("李四", 38, 55555),
new Employee("王五", 50, 6666.66),
new Employee("趙六", 16, 77777.77),
new Employee("田七", 8, 8888.88)
);MyPredicte
mp = new FilterEmployeeByAge();
Listemps = new ArrayList<>();
for (Employee emp : emps) {
if(mp.test(emp)) {
emps.add(emp);
}
}
}
1234567891011121314151617181920
復制代碼
當某一天需求變更了,變成需要查找金額大于60000的,那么只需要在撰寫一個實作類即可
/**
-
-
按薪資過濾
-
@author: 輕狂書生FS
-
@create: 2020-10-05-12:23
*/
public class FilterEmployeeBySalary implements MyPredicte{ @Override
public boolean test(Employee employee) {
return employee.getSalary() > 60000;
}
}
1234567891011121314
復制代碼
那么具體使用只需要更改為
/**
* 獲取當前公司薪資大于60000
*/
public static void test3() {
List
new Employee("張三", 18, 3333),
new Employee("李四", 38, 55555),
new Employee("王五", 50, 6666.66),
new Employee("趙六", 16, 77777.77),
new Employee("田七", 8, 8888.88)
);
MyPredicte<Employee> mp = new FilterEmployeeBySalary();
List<Employee> emps = new ArrayList<>();
for (Employee emp : emps) {
if(mp.test(emp)) {
emps.add(emp);
}
}
}
1234567891011121314151617181920
復制代碼
這樣一個方法,被稱為策略設計模式
匿名內部類
使用上面的策略設計模式,我們會發現一個問題,就是每當我需要增加一個條件的時候,就需要增加一個實作類,如果條件多了的話,那么就會有很多實作類,那么為了優化,我們可以采取匿名內部類的方式
/**
* 優化方式,采用匿名內部類的方式
*/
public static void test5() {
List
new Employee("張三", 18, 3333),
new Employee("李四", 38, 55555),
new Employee("王五", 50, 6666.66),
new Employee("趙六", 16, 77777.77),
new Employee("田七", 8, 8888.88)
);
// 匿名內部類
filterEmployee(employees, new MyPredicte<Employee>() {
@Override
public boolean test(Employee employee) {
return employee.getSalary() <= 5000;
}
});
}
1234567891011121314151617181920
復制代碼
直接在內部類中,使用我們的過濾條件
Lambda運算式
/**
* 使用Lambda運算式優化
*/
public static void test6() {
List
new Employee("張三", 18, 3333),
new Employee("李四", 38, 55555),
new Employee("王五", 50, 6666.66),
new Employee("趙六", 16, 77777.77),
new Employee("田七", 8, 8888.88)
);
List<Employee> list = filterEmployee(employees, (e) -> e.getSalary() <= 5000);
list.forEach(System.out::println);
}
123456789101112131415
復制代碼
或者
/**
* 不使用策略模式
*/
public static void test7() {
List
new Employee("張三", 18, 3333),
new Employee("李四", 38, 55555),
new Employee("王五", 50, 6666.66),
new Employee("趙六", 16, 77777.77),
new Employee("田七", 8, 8888.88)
);
employees.stream().filter(e-> e.getSalary() >= 5000).limit(2).forEach(System.out::println);
System.out.println("=========");
employees.stream().map(Employee::getName).forEach(System.out::println);
}
12345678910111213141516
復制代碼
學習Lambda
Lambda運算式基礎語法:Java8中引入了一個新的運算子 “->” 該運算子稱為箭頭運算子 或 Lambda運算子
箭頭運算子將Lambda運算式拆分為兩部分:
左側:Lambda運算式的引數串列(可以想象成,是上面定義的介面中抽象方法引數的串列)
右側:Lambda運算式中,所需要執行的功能,即Lambda體(需要對抽象方法實作的功能)
語法格式
1、無參,無回傳值
格式:
() -> System.out.println(“hello”);
1
復制代碼
舉例:
public static void test() {
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("hello");
}
};
System.out.println("=========");
Runnable runnable = () -> {
System.out.println("hello lambda");
};
}
1234567891011121314
復制代碼
JDK1.8以后,呼叫Lambda外的值,不需要增加final欄位,它默認已經添加了final
int n = 10;
Runnable runnable = () -> {
System.out.println("hello lambda" + n);
};
1234
復制代碼
2、有一個引數,有回傳值
格式:
(x) -> System.out.println(x);
或 (一個引數時,小括號可以省略不寫)
x -> System.out.println(x);
123
復制代碼
實體:
public static void test2() {
Consumer
consumer.accept("我在bilibili");
}
1234
復制代碼
3、有多個引數,一個回傳值
/**
* 多個引數,有回傳值
/
public static void test3() {
Comparator
System.out.println("函式式介面");
return Integer.compare(x, y);
};
}
123456789
復制代碼
4、有多個引數,只有一條陳述句
這個時候,可以省略大括號 和 return
/
* 多個引數,函式體只有一條,并且有回傳值時
/
public static void test4() {
Comparator
}
1234567
復制代碼
型別推斷
Lambda中,運算式的引數串列的資料型別可以省略不寫,因為JVM編譯器通過背景關系推斷出,資料型別,即“型別推斷”,
(Integer x, Integer y) -> Integer.compare(x, y);
1
復制代碼
但是底層的型別檢查還是有的,只是JDK底層幫我們做了型別檢查這件事
函式式介面
Lambda運算式需要“函式式介面”的支持
函式式介面:介面中只有一個抽象方法的介面,稱為函式式介面,如:
/
- 函式式介面
/
public interface MyPredicte{ *
public boolean test(T t);
}
123456
復制代碼
可以使用注解 @FunctionalInterface 修飾的,則為函式式介面
/ - 介面,用于解決重復條件
- @param
*/
@FunctionalInterface
public interface MyPredicte{
public boolean test(T t);
}
123456789
復制代碼
場景
對一個數進行某種運算
首先創建一個函式式介面
@FunctionalInterface
public interface MyFun {
public Integer getValue(Integer value);
}
1234
復制代碼
然后在定義一個方法,把方法作為引數傳遞
/**
* 需求:對一個數進行運算
/
public static void test5() {
Integer value = https://www.cnblogs.com/rutaha/archive/2020/11/20/operation(100, (x) -> xx);
System.out.println(value);
}
public static Integer operation(Integer num, MyFun myFun) {
return myFun.getValue(num);
}
1234567891011
復制代碼
訓練
呼叫Collections.sort()方法,通過定制排序比較兩個Employee(先比較年齡比,年齡相同比較姓名),使用Lambda運算式
public static void test() {
List
new Employee("張三", 18, 3333),
new Employee("李四", 38, 55555),
new Employee("王五", 50, 6666.66),
new Employee("趙六", 16, 77777.77),
new Employee("田七", 8, 8888.88)
);
Collections.sort(employees, (e1, e2) -> {
if(e1.getAge() == e2.getAge()) {
return e1.getName().compareTo(e2.getName());
} else {
return Integer.compare(e1.getAge(), e2.getAge());
}
});
employees.stream().map(Employee::getName).forEach(System.out::println);
}
復制代碼
123456789101112131415161718
Java內置函式介面
Comsumer 消費型介面
格式:Comsumer
傳入引數,然后對引數進行操作,沒有回傳值
/**
* 消費型介面
/
public static void test() {
happy(1000, (m) -> System.out.println("消費成功:" + m + "元"));
}
public static void happy(double money, Consumer
consumer.accept(money);
}
123456789
復制代碼
Supplier 供給型介面
格式:Supplier
T get();
傳入引數,對引數進行操作,然后有回傳值
/
* 供給型介面,供給功能如何實作
*/
public static void test2() {
List
Integer a = (int)(Math.random() * 10);
return a;
});
list.stream().forEach(System.out::println);
}
/**
* 產生指定個數的整數
* @param n
* @return
*/
public static List<Integer> getNumList(Integer n, Supplier<Integer> supplier) {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < n; i++) {
list.add(supplier.get());
}
return list;
}
123456789101112131415161718192021222324
復制代碼
最后輸出結果
0
5
9
4
4
3
4
5
0
3
12345678910
復制代碼
Function 函式型介面
格式:Function<T,R>
R apply(T t);
/**
* 函式型介面
* Function<T, R>
*/
public static void test3() {
String str = strHandler("abcdefg", (x) -> {
return x.toUpperCase().substring(0, 5);
});
System.out.println(str);
}
/**
* 需求:用于處理字串
*/
public static String strHandler(String str, Function<String, String> function) {
// 使用apply方法進行處理,怎么處理需要具體實作
return function.apply(str);
}
123456789101112131415161718
復制代碼
輸出結果:
ABCDE
1
復制代碼
Predicate 斷言型介面
格式:Predicate
/**
* 斷言型介面(把長度大于3的str過濾出來)
*/
public static void test4() {
List
List
result.forEach(item -> {
System.out.println(item);
});
}
/**
* 將滿足條件的字串,放入到集合中
*/
public static List<String> strPredict(List<String> list, Predicate<String> predicate) {
List<String> result = new ArrayList<>();
list.forEach(item -> {
if(predicate.test(item)) {
result.add(item);
}
});
return result;
}
1234567891011121314151617181920212223
復制代碼
擴展
上述的四大核心介面,并不能被適用于一個特殊的應用場景,只能滿足大部分的需求
因為他們對于引數的參入有局限性

同時后面針對這樣的情況,后面也使用子介面,進行了解決

總結了2020面試題,這份面試題的包含的模塊分為19個模塊,分別是: Java 基礎、容器、多執行緒、反射、物件拷貝、Java Web 、例外、網路、設計模式、Spring/Spring MVC、Spring Boot/Spring Cloud、Hibernate、MyBatis、RabbitMQ、Kafka、Zookeeper、MySQL、Redis、JVM ,
關注公眾號:有故事的程式員,回復【電子書】獲取上述資料,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/225545.html
標籤:其他
上一篇:Python學習筆記8:面向物件
