目錄
第一節:java8新特性簡介
一、java8新特性的好處
1、速度更快
2、代碼更少
3、強大的streamAPI
4、便于并行
5、最大化的減少空指針異常optional
第二節:lambad表達式
一、lambad表達式的概念
二、為什麼使用lambad表達式
1、回顧匿名内部類早期的使用方式、并對比lambad的實作方式
2、結合一個小需求,将傳統實作對比lambad表達式實作
3、使用政策設計模式,對上述代碼進行優化
4、使用匿名内部類的方式,對上述代碼進行優化
5、使用lambad表達式,對上述代碼進行優化
6、使用stream,對上述代碼進行優化
三、lambad表達式基礎文法
1、lambad基礎文法概述
四、lambad文法的幾種格式
1、無參無傳回值
2、有一個參數,并且無傳回值
3、如接口中的抽象方法隻有一個參數,那麼lambad中的參數清單裡的小括号可以不寫
4、一個以上參數,有傳回值,并且lambad體中包含多條語句
5、若lambad中隻有一條語句,那麼return和大括号都可以省略
6、參數推導
五、lambad表達式與接口關系
1、函數式接口的支援
六、lambad表達式小練習
1、調用collections.sort()方法,通過定制排序比較兩個employee(先按年齡比,年齡相同按姓名比),使用lambad作為參數傳遞;
2、自定義練習題1
Java8的新特性中,有兩個特别出彩的地方,一個是lambad表達式,這是一種新的文法。另外,使用lambad結合(也可以不結合)streamAPI,可以使我們操作資料的時候,就像使用sql操作資料一樣便捷!甚至,比使用sql語句還要簡單!
第一節:java8新特性簡介
一、java8新特性的好處
1、速度更快
Java8對底層的資料結構和垃圾回收機制的底層都做了一定的優化,是以他的運作效率要比java8之前更快!
舉個例子:
在java8之前,map集合底層使用的是連結清單+數組去實作的。
Java8之後将其優化為連結清單+數組+紅黑樹結構。這種做法可以避免在極端的碰撞情況下導緻的效率低下,當某一個連結清單長度大于8,并且總容量大于64的時候,連結清單将會轉換為紅黑樹結構,這種結構,除了添加的時候慢一點,其他的操作效率都很高!
另外,在concurrentHashMap中,将之前的分段鎖,使用CAS無鎖算法進行了替換,CAS無鎖的效率大家都知道要比分段鎖高很多!
再比如,java8對底層的記憶體結構也做了一定的調整。他将原來的永久區替換成了元空間,即metaSpace。他使用的是實體記憶體,而不是配置設定的記憶體,這個好處是非常棒的,你實體空間多大,我元空間就可以是多大,他争奪占用的是機器的底層實體資源!
如此一來,垃圾回收機制運作的次數便減少了,也就相應的提高了一定的效率!這裡要提出一點,就是這種方式下OOM的發生機率便也随之的大大降低了!
2、代碼更少
新增的文法lambad表達式使代碼更加的簡潔!大大的提高了代碼的可讀性!
3、強大的streamAPI
這個地方是比較出彩的一個點,他大大的簡化了java對資料的操作,使得java在操作資料的時候,可以像sql一樣簡潔!
4、便于并行
Java8對于并行運作做了一定的優化和支援!
5、最大化的減少空指針異常optional
Java8中提供了一個容器類optional,該類中提供了一系列對空指針的操作,大大的簡少了空指針的異常!
第二節:lambad表達式
一、lambad表達式的概念
Lambad是一個匿名函數,我們可以把lambad表達式了解為一段可以傳遞的代碼(将代碼像資料一樣傳遞)。可以寫出更簡潔、更靈活的代碼。作為一種更緊湊的代碼風格,使java語言表達能力得到了提升!
二、為什麼使用lambad表達式
我們在這裡使用執行個體示範來說明,為什麼要使用lambad表達式!
1、回顧匿名内部類早期的使用方式、并對比lambad的實作方式
其實從上述對比的案例中,可以看出來,lambad已經大大的簡化了代碼的數量,如果這個還無法打動你,那麼我們接着看下面的對比案例;
package 為什麼要使用lambad表達式;
import java.util.Comparator;
import java.util.TreeSet;
/**
* 示範為什麼要引入lambad表達式1
* @author yangbao
*/
public class LambadImport1 {
/**
* 最早期的匿名内部類使用
*/
public void EarlyUseOfAnonymousInnerClasses() {
//建立一個用于比較數值大小的匿名内部類
Comparator<Integer> com = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1, o2);
}
};
//将匿名内部類作為參數進行傳遞
TreeSet<Integer> ts = new TreeSet<Integer>(com);
/**
* 分析:上述代碼,我們其實核心的,最有用的代碼,
* 其實就是匿名内部類中的:return Integer.compare(o1, o2);這一句
* 而其他的一些代碼,全部都是為這句代碼提供支援的,也就是說,真正
* 幹活的代碼,就那麼一句,然後你還要弄些有的沒有亂七八糟的代碼。
* 那麼這個時候,lambad就誕生了,他的誕生,就是為了解決掉這些
* 有的沒有亂七八糟的代碼!
*/
}
/**
* 使用lambad表達式實作匿名内部類
*/
public void UsingLambadExpressionsToImplementAnonymousInnerClasses() {
Comparator<Integer> com = (x,y)-> Integer.compare(x,y);
//将lambad作為參數進行傳遞
TreeSet<Integer> ts = new TreeSet<Integer>(com);
}
}
2、結合一個小需求,将傳統實作對比lambad表達式實作
我們給出一個小需求:擷取目前公司中員工年齡大于35歲的員工資訊!
這樣的需求在正常工作中是非常常見的,下面我們分别用幾種方式對其進行實作,來一一與lambad表達式的實作對比:
1)、最傳統的實作方式
package 為什麼要使用lambad表達式;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import 為什麼要使用lambad表達式.entity.Employee;
/**
* 示範為什麼要引入lambad表達式2
* 如果示範案例1還不足以說明lambad的好處,
* 那麼我們使用案例示範2來嘗試說明lambad的好處!
*
* 在這裡我們提出一個明确的需求:
* 擷取目前公司中員工年齡大于35歲的員工資訊!
*
* @author yangbao
*/
public class LambadImport2 {
//建立資料
private static List<Employee> employees = Arrays.asList(
new Employee("張三",18,9999.99),
new Employee("李四",38,5555.55),
new Employee("王五",50,6666.66),
new Employee("趙六",16,3333.33),
new Employee("田七", 8,7777.77)
);
/**
* 擷取目前公司中員工年齡大于35歲的員工資訊!
* @param employees
* @return
*/
public static List<Employee> filterEmployees(List<Employee> employees){
List<Employee> emps = new ArrayList<Employee>();
for(Employee emp:employees) {
if(emp.getAge()>=35) {
emps.add(emp);
}
}
return emps;
}
public static void main(String[] args) {
List<Employee> filterEmployees = filterEmployees(employees);
for(Employee e:filterEmployees) {
System.out.println(e);
}
}
}
運作效果:
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
2)、新增需求
好了,當我們将上面的第一個需求實作之後,又來了一個新的需求,這是很常見的吧:
擷取目前公司中員工工資大于5000的員工資訊。
那這個時候,就意味着我們還得寫一個方法,于是,這個類就變成了如下的樣子:
package 為什麼要使用lambad表達式;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import 為什麼要使用lambad表達式.entity.Employee;
/**
* 示範為什麼要引入lambad表達式2
* 如果示範案例1還不足以說明lambad的好處,
* 那麼我們使用案例示範2來嘗試說明lambad的好處!
*
* 在這裡我們提出一個明确的需求:
* 擷取目前公司中員工年齡大于35歲的員工資訊!
*
* @author yangbao
*/
public class LambadImport2 {
//建立資料
private static List<Employee> employees = Arrays.asList(
new Employee("張三",18,9999.99),
new Employee("李四",38,5555.55),
new Employee("王五",50,6666.66),
new Employee("趙六",16,3333.33),
new Employee("田七", 8,7777.77)
);
/**
* 擷取目前公司中員工年齡大于35歲的員工資訊!
* @param employees
* @return
*/
public static List<Employee> filterEmployees(List<Employee> employees){
List<Employee> emps = new ArrayList<Employee>();
for(Employee emp:employees) {
if(emp.getAge()>=35) {
emps.add(emp);
}
}
return emps;
}
/**
* 擷取目前公司中員工工資大于5000的員工資訊
* @param employees
* @return
*/
public static List<Employee> filterEmployeesSalary(List<Employee> employees){
List<Employee> emps = new ArrayList<Employee>();
for(Employee emp:employees) {
if(emp.getSalary()>=5000) {
emps.add(emp);
}
}
return emps;
}
public static void main(String[] args) {
System.out.println("擷取目前公司中員工年齡大于35歲的員工資訊:");
List<Employee> filterEmployees = filterEmployees(employees);
for(Employee e:filterEmployees) {
System.out.println(e);
}
System.out.println("擷取目前公司中員工工資大于5000的員工資訊:");
List<Employee> filterEmployeesSalary = filterEmployeesSalary(employees);
for(Employee e:filterEmployeesSalary) {
System.out.println(e);
}
}
}
運作效果:
擷取目前公司中員工年齡大于35歲的員工資訊:
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
擷取目前公司中員工工資大于5000的員工資訊:
Employee [name=張三, age=18, salary=9999.99]
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
Employee [name=田七, age=8, salary=7777.77]
實作出來的運作結果是沒有問題的,但是這個代碼中存在很多的備援代碼,filterEmployees和filterEmployeesSalary兩個方法,其實唯一一點不同的地方就是比較的字段不一樣!
其餘的代碼都一樣,那麼這個時候我們就不得不考慮對其進行抽取封裝了!
我們目前來說,對代碼最好的優化方式就是使用相應的設計模式,那麼我們就使用設計模式來對其進行一個優化:
3、使用政策設計模式,對上述代碼進行優化
1)、建立政策接口
package 為什麼要使用lambad表達式.inter;
public interface MyPredicate<T> {
/**
* 比較函數
* @param t
* @return
*/
public boolean compare(T t);
}
2)、建立實作類
package 為什麼要使用lambad表達式.inter.impl;
import 為什麼要使用lambad表達式.entity.Employee;
import 為什麼要使用lambad表達式.inter.MyPredicate;
public class FilterEmployeeByAge implements MyPredicate<Employee> {
/**
* 實作比較函數
*/
@Override
public boolean compare(Employee t) {
return t.getAge()>=35;
}
}
package 為什麼要使用lambad表達式.inter.impl;
import 為什麼要使用lambad表達式.entity.Employee;
import 為什麼要使用lambad表達式.inter.MyPredicate;
public class FilterEmployeeBySalary implements MyPredicate<Employee> {
/**
* 實作比較函數
*/
@Override
public boolean compare(Employee t) {
return t.getSalary()>=5000;
}
}
3)、根據不同的政策選擇不同的政策接口實作類作為參數
package 為什麼要使用lambad表達式;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import 為什麼要使用lambad表達式.entity.Employee;
import 為什麼要使用lambad表達式.inter.MyPredicate;
import 為什麼要使用lambad表達式.inter.impl.FilterEmployeeByAge;
import 為什麼要使用lambad表達式.inter.impl.FilterEmployeeBySalary;
/**
* 示範為什麼要引入lambad表達式2
* 如果示範案例1還不足以說明lambad的好處,
* 那麼我們使用案例示範2來嘗試說明lambad的好處!
*
* 在這裡我們提出一個明确的需求:
* 擷取目前公司中員工年齡大于35歲的員工資訊!
*
* @author yangbao
*/
public class LambadImport2 {
//建立資料
private static List<Employee> employees = Arrays.asList(
new Employee("張三",18,9999.99),
new Employee("李四",38,5555.55),
new Employee("王五",50,6666.66),
new Employee("趙六",16,3333.33),
new Employee("田七", 8,7777.77)
);
/**
* 擷取目前公司中員工年齡大于35歲的員工資訊!
* @param employees
* @return
*/
public static List<Employee> filterEmployees(List<Employee> employees){
List<Employee> emps = new ArrayList<Employee>();
for(Employee emp:employees) {
if(emp.getAge()>=35) {
emps.add(emp);
}
}
return emps;
}
/**
* 擷取目前公司中員工工資大于5000的員工資訊
* @param employees
* @return
*/
public static List<Employee> filterEmployeesSalary(List<Employee> employees){
List<Employee> emps = new ArrayList<Employee>();
for(Employee emp:employees) {
if(emp.getSalary()>=5000) {
emps.add(emp);
}
}
return emps;
}
/**
* 優化方式1
* @param employeesList
* @param mp
* @return
*/
public static List<Employee> filterEmployee(List<Employee> employeesList,MyPredicate<Employee> mp){
List<Employee> emps = new ArrayList<Employee>();
for(Employee e:employeesList) {
if(mp.compare(e)) {
emps.add(e);
}
}
return emps;
}
public static void main(String[] args) {
System.out.println("擷取目前公司中員工年齡大于35歲的員工資訊:");
List<Employee> filterEmployees = filterEmployees(employees);
for(Employee e:filterEmployees) {
System.out.println(e);
}
System.out.println("擷取目前公司中員工工資大于5000的員工資訊:");
List<Employee> filterEmployeesSalary = filterEmployeesSalary(employees);
for(Employee e:filterEmployeesSalary) {
System.out.println(e);
}
System.out.println("優化方式1:");
System.out.println("擷取目前公司中員工年齡大于35歲的員工資訊:");
List<Employee> filterEmployeeByAge = filterEmployee(employees,new FilterEmployeeByAge());
for(Employee e:filterEmployeeByAge) {
System.out.println(e);
}
System.out.println("擷取目前公司中員工工資大于5000的員工資訊:");
List<Employee> filterEmployeeBySalary = filterEmployee(employees,new FilterEmployeeBySalary());
for(Employee e:filterEmployeeBySalary) {
System.out.println(e);
}
}
}
4)、運作效果:
擷取目前公司中員工年齡大于35歲的員工資訊:
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
擷取目前公司中員工工資大于5000的員工資訊:
Employee [name=張三, age=18, salary=9999.99]
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
Employee [name=田七, age=8, salary=7777.77]
優化方式1:
擷取目前公司中員工年齡大于35歲的員工資訊:
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
擷取目前公司中員工工資大于5000的員工資訊:
Employee [name=張三, age=18, salary=9999.99]
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
Employee [name=田七, age=8, salary=7777.77]
5)、分析上述代碼的優缺點
那麼這麼做的好處是什麼呢?我們這裡的方法隻指向一個,即在實作中,隻有一個filterEmployee方法,而具體需要對比哪個字段大的值,隻需要傳遞進來相應的MyPredicate接口參數即可!也即是說,選擇相應的MyPredicate接口實作類作為參數就可以控制比較的字段!
如果你想按年齡進行過濾,那就将FilterEmployeeByAge類的執行個體作為參數傳遞進來;
如果你想按工資進行過濾,那就将FilterEmployeeBySalary類的執行個體作為參數傳遞進來;
這樣的話,如果新增一個需求,要求按照其他字段進行過濾的話,那麼我們隻需要編寫一個
MyPredicate接口的實作類,在實作類中進行具體邏輯的實作即可!
這個即使優點,同時也是缺點!因為沒增加一個需求,都需要編寫一個實作類,其實也是很不友好的!
但是目前來說,這基本上也就是最好的一種優化方式了!
4、使用匿名内部類的方式,對上述代碼進行優化
1)、代碼實作(接口不變)
package 為什麼要使用lambad表達式;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import 為什麼要使用lambad表達式.entity.Employee;
import 為什麼要使用lambad表達式.inter.MyPredicate;
import 為什麼要使用lambad表達式.inter.impl.FilterEmployeeByAge;
import 為什麼要使用lambad表達式.inter.impl.FilterEmployeeBySalary;
/**
* 示範為什麼要引入lambad表達式2
* 如果示範案例1還不足以說明lambad的好處,
* 那麼我們使用案例示範2來嘗試說明lambad的好處!
*
* 在這裡我們提出一個明确的需求:
* 擷取目前公司中員工年齡大于35歲的員工資訊!
*
* @author yangbao
*/
public class LambadImport2 {
//建立資料
private static List<Employee> employees = Arrays.asList(
new Employee("張三",18,9999.99),
new Employee("李四",38,5555.55),
new Employee("王五",50,6666.66),
new Employee("趙六",16,3333.33),
new Employee("田七", 8,7777.77)
);
/**
* 擷取目前公司中員工年齡大于35歲的員工資訊!
* @param employees
* @return
*/
public static List<Employee> filterEmployees(List<Employee> employees){
List<Employee> emps = new ArrayList<Employee>();
for(Employee emp:employees) {
if(emp.getAge()>=35) {
emps.add(emp);
}
}
return emps;
}
/**
* 擷取目前公司中員工工資大于5000的員工資訊
* @param employees
* @return
*/
public static List<Employee> filterEmployeesSalary(List<Employee> employees){
List<Employee> emps = new ArrayList<Employee>();
for(Employee emp:employees) {
if(emp.getSalary()>=5000) {
emps.add(emp);
}
}
return emps;
}
/**
* 優化方式1
* @param employeesList
* @param mp
* @return
*/
public static List<Employee> filterEmployee(List<Employee> employeesList,MyPredicate<Employee> mp){
List<Employee> emps = new ArrayList<Employee>();
for(Employee e:employeesList) {
if(mp.compare(e)) {
emps.add(e);
}
}
return emps;
}
public static void main(String[] args) {
System.out.println("擷取目前公司中員工年齡大于35歲的員工資訊:");
List<Employee> filterEmployees = filterEmployees(employees);
for(Employee e:filterEmployees) {
System.out.println(e);
}
System.out.println("擷取目前公司中員工工資大于5000的員工資訊:");
List<Employee> filterEmployeesSalary = filterEmployeesSalary(employees);
for(Employee e:filterEmployeesSalary) {
System.out.println(e);
}
System.out.println("優化方式1,使用政策模式對其進行優化:");
System.out.println("擷取目前公司中員工年齡大于35歲的員工資訊:");
List<Employee> filterEmployeeByAge = filterEmployee(employees,new FilterEmployeeByAge());
for(Employee e:filterEmployeeByAge) {
System.out.println(e);
}
System.out.println("擷取目前公司中員工工資大于5000的員工資訊:");
List<Employee> filterEmployeeBySalary = filterEmployee(employees,new FilterEmployeeBySalary());
for(Employee e:filterEmployeeBySalary) {
System.out.println(e);
}
System.out.println("優化方式2,使用匿名内部類的方式,對上述代碼進行優化:");
System.out.println("擷取目前公司中員工年齡大于35歲的員工資訊:");
List<Employee> earlyUseOfAnonymousInnerClassesByAgeList = filterEmployee(employees,new MyPredicate<Employee>() {
@Override
public boolean compare(Employee t) {
return t.getAge()>=35;
}
});
for(Employee e:earlyUseOfAnonymousInnerClassesByAgeList) {
System.out.println(e);
}
System.out.println("擷取目前公司中員工工資大于5000的員工資訊:");
List<Employee> earlyUseOfAnonymousInnerClassesListBySalaryList = filterEmployee(employees,new MyPredicate<Employee>() {
@Override
public boolean compare(Employee t) {
return t.getSalary()>=5000;
}
});
for(Employee e:earlyUseOfAnonymousInnerClassesListBySalaryList) {
System.out.println(e);
}
}
}
2)、運作效果:
擷取目前公司中員工年齡大于35歲的員工資訊:
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
擷取目前公司中員工工資大于5000的員工資訊:
Employee [name=張三, age=18, salary=9999.99]
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
Employee [name=田七, age=8, salary=7777.77]
優化方式1,使用政策模式對其進行優化:
擷取目前公司中員工年齡大于35歲的員工資訊:
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
擷取目前公司中員工工資大于5000的員工資訊:
Employee [name=張三, age=18, salary=9999.99]
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
Employee [name=田七, age=8, salary=7777.77]
優化方式2,使用匿名内部類的方式,對上述代碼進行優化:
擷取目前公司中員工年齡大于35歲的員工資訊:
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
擷取目前公司中員工工資大于5000的員工資訊:
Employee [name=張三, age=18, salary=9999.99]
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
Employee [name=田七, age=8, salary=7777.77]
3)、分析上述代碼的優缺點
優點:從上述實作的代碼來看,我們不再需要建立實作類了,而是在匿名内部類中對具體的邏輯進行處理!
缺點:我們前面示範過使用匿名内部類來對比lambad表達式,那個時候我們是不是說過,其實這個匿名内部類中,實際上起作用的代碼,就是實作方法中的内容,其餘的全部沒有用,隻是一個架子而已!那麼這個時候,我們就可以使用lambad表達式來對其進行優化了!
5、使用lambad表達式,對上述代碼進行優化
1)、代碼實作
package 為什麼要使用lambad表達式;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import 為什麼要使用lambad表達式.entity.Employee;
import 為什麼要使用lambad表達式.inter.MyPredicate;
import 為什麼要使用lambad表達式.inter.impl.FilterEmployeeByAge;
import 為什麼要使用lambad表達式.inter.impl.FilterEmployeeBySalary;
/**
* 示範為什麼要引入lambad表達式2
* 如果示範案例1還不足以說明lambad的好處,
* 那麼我們使用案例示範2來嘗試說明lambad的好處!
*
* 在這裡我們提出一個明确的需求:
* 擷取目前公司中員工年齡大于35歲的員工資訊!
*
* @author yangbao
*/
public class LambadImport2 {
//建立資料
private static List<Employee> employees = Arrays.asList(
new Employee("張三",18,9999.99),
new Employee("李四",38,5555.55),
new Employee("王五",50,6666.66),
new Employee("趙六",16,3333.33),
new Employee("田七", 8,7777.77)
);
/**
* 擷取目前公司中員工年齡大于35歲的員工資訊!
* @param employees
* @return
*/
public static List<Employee> filterEmployees(List<Employee> employees){
List<Employee> emps = new ArrayList<Employee>();
for(Employee emp:employees) {
if(emp.getAge()>=35) {
emps.add(emp);
}
}
return emps;
}
/**
* 擷取目前公司中員工工資大于5000的員工資訊
* @param employees
* @return
*/
public static List<Employee> filterEmployeesSalary(List<Employee> employees){
List<Employee> emps = new ArrayList<Employee>();
for(Employee emp:employees) {
if(emp.getSalary()>=5000) {
emps.add(emp);
}
}
return emps;
}
/**
* 優化方式1
* @param employeesList
* @param mp
* @return
*/
public static List<Employee> filterEmployee(List<Employee> employeesList,MyPredicate<Employee> mp){
List<Employee> emps = new ArrayList<Employee>();
for(Employee e:employeesList) {
if(mp.compare(e)) {
emps.add(e);
}
}
return emps;
}
public static void main(String[] args) {
System.out.println("擷取目前公司中員工年齡大于35歲的員工資訊:");
List<Employee> filterEmployees = filterEmployees(employees);
for(Employee e:filterEmployees) {
System.out.println(e);
}
System.out.println("擷取目前公司中員工工資大于5000的員工資訊:");
List<Employee> filterEmployeesSalary = filterEmployeesSalary(employees);
for(Employee e:filterEmployeesSalary) {
System.out.println(e);
}
System.out.println("優化方式1,使用政策模式對其進行優化:");
System.out.println("擷取目前公司中員工年齡大于35歲的員工資訊:");
List<Employee> filterEmployeeByAge = filterEmployee(employees,new FilterEmployeeByAge());
for(Employee e:filterEmployeeByAge) {
System.out.println(e);
}
System.out.println("擷取目前公司中員工工資大于5000的員工資訊:");
List<Employee> filterEmployeeBySalary = filterEmployee(employees,new FilterEmployeeBySalary());
for(Employee e:filterEmployeeBySalary) {
System.out.println(e);
}
System.out.println("優化方式2,使用匿名内部類的方式,對上述代碼進行優化:");
System.out.println("擷取目前公司中員工年齡大于35歲的員工資訊:");
List<Employee> earlyUseOfAnonymousInnerClassesByAgeList = filterEmployee(employees,new MyPredicate<Employee>() {
@Override
public boolean compare(Employee t) {
return t.getAge()>=35;
}
});
for(Employee e:earlyUseOfAnonymousInnerClassesByAgeList) {
System.out.println(e);
}
System.out.println("擷取目前公司中員工工資大于5000的員工資訊:");
List<Employee> earlyUseOfAnonymousInnerClassesListBySalaryList = filterEmployee(employees,new MyPredicate<Employee>() {
@Override
public boolean compare(Employee t) {
return t.getSalary()>=5000;
}
});
for(Employee e:earlyUseOfAnonymousInnerClassesListBySalaryList) {
System.out.println(e);
}
System.out.println("優化方式3,使用lambad表達式,對上述代碼進行優化:");
System.out.println("擷取目前公司中員工年齡大于35歲的員工資訊:");
List<Employee> lambadByAgeList = filterEmployee(employees,(e)->e.getAge()>=35);
lambadByAgeList.forEach(System.out::println);
System.out.println("擷取目前公司中員工工資大于5000的員工資訊:");
List<Employee> lambadBySalaryList = filterEmployee(employees,(e)->e.getSalary()>=5000);
lambadBySalaryList.forEach(System.out::println);
}
}
2)、運作效果
擷取目前公司中員工年齡大于35歲的員工資訊:
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
擷取目前公司中員工工資大于5000的員工資訊:
Employee [name=張三, age=18, salary=9999.99]
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
Employee [name=田七, age=8, salary=7777.77]
優化方式1,使用政策模式對其進行優化:
擷取目前公司中員工年齡大于35歲的員工資訊:
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
擷取目前公司中員工工資大于5000的員工資訊:
Employee [name=張三, age=18, salary=9999.99]
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
Employee [name=田七, age=8, salary=7777.77]
優化方式2,使用匿名内部類的方式,對上述代碼進行優化:
擷取目前公司中員工年齡大于35歲的員工資訊:
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
擷取目前公司中員工工資大于5000的員工資訊:
Employee [name=張三, age=18, salary=9999.99]
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
Employee [name=田七, age=8, salary=7777.77]
優化方式3,使用lambad表達式,對上述代碼進行優化:
擷取目前公司中員工年齡大于35歲的員工資訊:
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
擷取目前公司中員工工資大于5000的員工資訊:
Employee [name=張三, age=18, salary=9999.99]
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
Employee [name=田七, age=8, salary=7777.77]
3)、分析上述代碼的優缺點
優點:上述代碼,基本上已經将政策模式精簡到了極緻了,但是,優點就不言而喻了吧!
缺點:還是有人會不滿意,那麼沒關系,我們再往下看!
6、使用stream,對上述代碼進行優化
1)、代碼實作
package 為什麼要使用lambad表達式;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import 為什麼要使用lambad表達式.entity.Employee;
import 為什麼要使用lambad表達式.inter.MyPredicate;
import 為什麼要使用lambad表達式.inter.impl.FilterEmployeeByAge;
import 為什麼要使用lambad表達式.inter.impl.FilterEmployeeBySalary;
/**
* 示範為什麼要引入lambad表達式2
* 如果示範案例1還不足以說明lambad的好處,
* 那麼我們使用案例示範2來嘗試說明lambad的好處!
*
* 在這裡我們提出一個明确的需求:
* 擷取目前公司中員工年齡大于35歲的員工資訊!
*
* @author yangbao
*/
public class LambadImport2 {
//建立資料
private static List<Employee> employees = Arrays.asList(
new Employee("張三",18,9999.99),
new Employee("李四",38,5555.55),
new Employee("王五",50,6666.66),
new Employee("趙六",16,3333.33),
new Employee("田七", 8,7777.77)
);
/**
* 擷取目前公司中員工年齡大于35歲的員工資訊!
* @param employees
* @return
*/
public static List<Employee> filterEmployees(List<Employee> employees){
List<Employee> emps = new ArrayList<Employee>();
for(Employee emp:employees) {
if(emp.getAge()>=35) {
emps.add(emp);
}
}
return emps;
}
/**
* 擷取目前公司中員工工資大于5000的員工資訊
* @param employees
* @return
*/
public static List<Employee> filterEmployeesSalary(List<Employee> employees){
List<Employee> emps = new ArrayList<Employee>();
for(Employee emp:employees) {
if(emp.getSalary()>=5000) {
emps.add(emp);
}
}
return emps;
}
/**
* 優化方式1
* @param employeesList
* @param mp
* @return
*/
public static List<Employee> filterEmployee(List<Employee> employeesList,MyPredicate<Employee> mp){
List<Employee> emps = new ArrayList<Employee>();
for(Employee e:employeesList) {
if(mp.compare(e)) {
emps.add(e);
}
}
return emps;
}
public static void main(String[] args) {
System.out.println("擷取目前公司中員工年齡大于35歲的員工資訊:");
List<Employee> filterEmployees = filterEmployees(employees);
for(Employee e:filterEmployees) {
System.out.println(e);
}
System.out.println("擷取目前公司中員工工資大于5000的員工資訊:");
List<Employee> filterEmployeesSalary = filterEmployeesSalary(employees);
for(Employee e:filterEmployeesSalary) {
System.out.println(e);
}
System.out.println("優化方式1,使用政策模式對其進行優化:");
System.out.println("擷取目前公司中員工年齡大于35歲的員工資訊:");
List<Employee> filterEmployeeByAge = filterEmployee(employees,new FilterEmployeeByAge());
for(Employee e:filterEmployeeByAge) {
System.out.println(e);
}
System.out.println("擷取目前公司中員工工資大于5000的員工資訊:");
List<Employee> filterEmployeeBySalary = filterEmployee(employees,new FilterEmployeeBySalary());
for(Employee e:filterEmployeeBySalary) {
System.out.println(e);
}
System.out.println("優化方式2,使用匿名内部類的方式,對上述代碼進行優化:");
System.out.println("擷取目前公司中員工年齡大于35歲的員工資訊:");
List<Employee> earlyUseOfAnonymousInnerClassesByAgeList = filterEmployee(employees,new MyPredicate<Employee>() {
@Override
public boolean compare(Employee t) {
return t.getAge()>=35;
}
});
for(Employee e:earlyUseOfAnonymousInnerClassesByAgeList) {
System.out.println(e);
}
System.out.println("擷取目前公司中員工工資大于5000的員工資訊:");
List<Employee> earlyUseOfAnonymousInnerClassesListBySalaryList = filterEmployee(employees,new MyPredicate<Employee>() {
@Override
public boolean compare(Employee t) {
return t.getSalary()>=5000;
}
});
for(Employee e:earlyUseOfAnonymousInnerClassesListBySalaryList) {
System.out.println(e);
}
System.out.println("優化方式3,使用lambad表達式,對上述代碼進行優化:");
System.out.println("擷取目前公司中員工年齡大于35歲的員工資訊:");
List<Employee> lambadByAgeList = filterEmployee(employees,(e)->e.getAge()>=35);
lambadByAgeList.forEach(System.out::println);
System.out.println("擷取目前公司中員工工資大于5000的員工資訊:");
List<Employee> lambadBySalaryList = filterEmployee(employees,(e)->e.getSalary()>=5000);
lambadBySalaryList.forEach(System.out::println);
System.out.println("優化方式4,使用stream文法,對上述代碼進行優化:");
System.out.println("擷取目前公司中員工年齡大于35歲的員工資訊:");
employees.stream().filter((e)->e.getAge()>=35).forEach(System.out::println);
System.out.println("擷取目前公司中員工工資大于5000的員工資訊:");
employees.stream().filter((e)->e.getSalary()>=5000).forEach(System.out::println);
}
}
2)、運作效果
擷取目前公司中員工年齡大于35歲的員工資訊:
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
擷取目前公司中員工工資大于5000的員工資訊:
Employee [name=張三, age=18, salary=9999.99]
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
Employee [name=田七, age=8, salary=7777.77]
優化方式1,使用政策模式對其進行優化:
擷取目前公司中員工年齡大于35歲的員工資訊:
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
擷取目前公司中員工工資大于5000的員工資訊:
Employee [name=張三, age=18, salary=9999.99]
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
Employee [name=田七, age=8, salary=7777.77]
優化方式2,使用匿名内部類的方式,對上述代碼進行優化:
擷取目前公司中員工年齡大于35歲的員工資訊:
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
擷取目前公司中員工工資大于5000的員工資訊:
Employee [name=張三, age=18, salary=9999.99]
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
Employee [name=田七, age=8, salary=7777.77]
優化方式3,使用lambad表達式,對上述代碼進行優化:
擷取目前公司中員工年齡大于35歲的員工資訊:
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
擷取目前公司中員工工資大于5000的員工資訊:
Employee [name=張三, age=18, salary=9999.99]
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
Employee [name=田七, age=8, salary=7777.77]
優化方式4,使用stream文法,對上述代碼進行優化:
擷取目前公司中員工年齡大于35歲的員工資訊:
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
擷取目前公司中員工工資大于5000的員工資訊:
Employee [name=張三, age=18, salary=9999.99]
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
Employee [name=田七, age=8, salary=7777.77]
3)、分析上述代碼的優缺點
優點:代碼及其簡潔
缺點:需要學習
三、lambad表達式基礎文法
1、lambad基礎文法概述
Java8中引入了一個新的操作符“->”,該操作符稱為箭頭操作符或者lambad操作符,箭頭操作符将整個lambad表達式拆分成了兩個部分,分别是箭頭左側的部分和箭頭右側的部分:
1)、箭頭左側的部分
左側部分為lambad表達式的參數清單!
2)、箭頭右側的部分
右側部分為lambad體,該部分為lambad具體要執行的邏輯代碼!
我們通過上述的示範案例和文法概念,可以總結出來,所謂的lambad表達式,就是一種對接口的實作的簡易寫法!
public interface MyPredicate<T>{
//比較函數
Public Boolean compare(T t);
}
如上圖所示,我們lambad左側的參數清單,指的就是這個接口中方法的參數清單,要求與之一一對應;而右側的lambad體,指的就是實作類中該方法的實作中的邏輯代碼,見下圖中代碼的藍色部分:
package 為什麼要使用lambad表達式.inter.impl; import 為什麼要使用lambad表達式.entity.Employee; import 為什麼要使用lambad表達式.inter.MyPredicate; public class FilterEmployeeByAge implements MyPredicate<Employee> { @Override public boolean compare(Employee t) { return t.getAge()>=35; } } |
最後,我們結合文法和業務邏輯,便可實作一個lambad表達式:
List<Employee> lambadByAgeList = filterEmployee(employees,(e)->e.getAge()>=35); |
那麼這個時候我們就會有一個疑問,既然lambad表達式要對接口中的抽象方法做實作,那麼他具體要實作哪個抽象方法呢?
這個問題,就需要一個函數式接口來對其進行支援,那麼什麼是函數式接口呢?就是一個接口中,隻有一個抽象方法!這個我們後面再說,這裡先記一下這個點!
我們先簡單的了解lambad文法的幾種變換格式;
四、lambad文法的幾種格式
這裡再次強調一點,lambad表達式是對接口中的抽象類做具體實作的!
而我們接口中的抽象類,有很多種形式,有無慘的,有有參數的,有多參數的,有帶傳回值的,有不帶傳回值的,等等!
我們來了解一下lambad表達式對這幾種抽象類的實作時什麼樣子的!
1、無參無傳回值
我們知道Runnable接口就符合這樣的條件,我們以Runnable接口為例來進行示範:
1)、代碼實作:
package lambad表達式基礎文法; public class TestLambad1 { public static void main(String[] args) { System.out.println("調用原始實作方式"); originalImplementation(); System.out.println("調用lambad實作方式"); lambadlImplementation(); } public static void originalImplementation() { Runnable r = new Runnable() { @Override public void run() { System.out.println("hello world"); } }; r.run(); } public static void lambadlImplementation() { Runnable r = ()->System.out.println("hello lambad"); r.run(); } } |
2)、運作效果:
調用原始實作方式 hello world 調用lambad實作方式 hello lambad |
3)、總結:
Runnable r = () -> System.out.println("hello lambad");
紅色部分為方法的傳回值;
藍色部分為接口中的抽象方法的參數清單;
綠色部分為lambad符号;
褐色部分為接口中的抽象方法的實作邏輯代碼;
4)、注意事項
在局部内部類中使用到了同級别的局部變量的時候:
在jdk1.8以前,這個變量必須顯式的聲明為final類型的,但是在jdk1.8以後,無需顯式的将其聲明為final類型的,但是他本質上還是一個final類型的,他的值,不可以改變!
正确用法:
public static void originalImplementation() { int num = 0; Runnable r = new Runnable() { @Override public void run() { System.out.println("hello world"+num); } }; r.run(); } |
錯誤用法:
public static void originalImplementation() { int num = 0; Runnable r = new Runnable() { @Override public void run() { System.out.println("hello world"+num++); } }; r.run(); } |
同樣的,lambad也需要遵循這樣的原則:
正确使用:
public static void lambadlImplementation() { int num = 0; Runnable r = ()->System.out.println("hello lambad"+num); r.run(); } |
錯誤使用:
public static void lambadlImplementation() { int num = 0; Runnable r = ()->System.out.println("hello lambad"+num++); r.run(); } |
2、有一個參數,并且無傳回值
1)、代碼實作
package lambad表達式基礎文法; import java.util.function.Consumer; public class TestLambad1 { public static void main(String[] args) { lambadlImplementation2(); } public static void lambadlImplementation2() { Consumer<String> con = (x)->System.out.println(x); con.accept("你好楊保"); } } |
2)、運作效果
你好楊保 |
3)、總結
Consumer<String> con = (x)->System.out.println(x);
紅色部分:方法的傳回值;
藍色部分:參數清單,其中x可以為任何字元串;
綠色部分:lambad符号;
褐色部分:方法的實作邏輯代碼;
3、如接口中的抽象方法隻有一個參數,那麼lambad中的參數清單裡的小括号可以不寫
1)、代碼實作
package lambad表達式基礎文法; import java.util.function.Consumer; public class TestLambad1 { public static void main(String[] args) { lambadlImplementation3(); } public static void lambadlImplementation3() { Consumer<String> con = x->System.out.println(x); con.accept("你好楊保"); } } |
2)、運作效果
你好楊保 |
3)、總結
Consumer<String> con = x->System.out.println(x);
紅色部分:方法的傳回值;
藍色部分:參數清單,其中x可以為任何字元串;如果方法的參數隻有一個,小括号可以忽略不寫;
綠色部分:lambad符号;
褐色部分:方法的實作邏輯代碼;
4、一個以上參數,有傳回值,并且lambad體中包含多條語句
1)、代碼實作
package lambad表達式基礎文法; import java.util.Comparator; import java.util.function.Consumer; public class TestLambad1 { public static void main(String[] args) { lambadlImplementation4(); } public static void lambadlImplementation4() { Comparator<Integer> com = (x,y)->{ System.out.println("函數式接口"); return Integer.compare(x, y); }; int res = com.compare(1,2); System.out.println(res); } } |
2)、運作效果
函數式接口 -1 |
3)、總結
Comparator<Integer> com = (x,y)->{
System.out.println("函數式接口");
return Integer.compare(x, y);
};
紅色部分:接口的執行個體對象;
藍色部分:接口中抽象方法的參數清單,其中x,y類似于占位符,寫什麼字元串放在這裡都可以;
綠色部分:lambad符号;
褐色部分:接口中抽象方法的實作邏輯代碼,如果該實作邏輯需要多行代碼,那麼必須使用大括号對其進行包裹!
5、若lambad中隻有一條語句,那麼return和大括号都可以省略
1)、代碼實作
package lambad表達式基礎文法; import java.util.Comparator; import java.util.function.Consumer; public class TestLambad1 { public static void main(String[] args) { lambadlImplementation5(); } public static void lambadlImplementation5() { Comparator<Integer> com = (x,y)->Integer.compare(x, y); int res = com.compare(1,2); System.out.println(res); } } |
2)、運作效果
-1 |
3)、總結
Comparator<Integer> com = (x,y)->Integer.compare(x, y);
紅色部分:接口的執行個體對象;
藍色部分:接口中抽象方法的參數清單,如果隻有一個參數的話,小括号可以省略;
綠色部分:lambad符号;
褐色部分:接口中抽象方法的實作邏輯代碼,如果該方法需要傳回值,并且lambad中隻有一句代碼,那麼return可以省略不寫,同時{}大括号也可以省略不寫;
6、參數推導
Lambad表達式的參數清單的資料類型可以省略不寫,因為JVM編譯器可以通過上下文推斷出資料類型,即:參數推斷;
1)、代碼實作
package lambad表達式基礎文法; import java.util.Comparator; import java.util.function.Consumer; public class TestLambad1 { public static void main(String[] args) { lambadlImplementation6(); } public static void lambadlImplementation6() { Comparator<Integer> com = (Integer x,Integer y)->Integer.compare(x, y); int res = com.compare(1,2); System.out.println(res); } } |
2)、運作效果
-1 |
3)、總結
Comparator<Integer> com = (Integer x,Integer y)->Integer.compare(x, y);
紅色部分:方法的傳回值;
藍色部分:參數清單,其中x可以為任何字元串;如果方法的參數隻有一個,小括号可以忽略不寫;這裡是寫全了的樣子,是可以加上參數類型的;
綠色部分:lambad符号;
褐色部分:方法的實作邏輯代碼;
五、lambad表達式與接口關系
1、函數式接口的支援
我們前面說過,lambad是對接口中的方法進行實作,并且接口中的方法還不能多,多了就區分不了了,那麼針對這個地方,我們給與解釋說明;
首先,lambad需要函數式接口的支援,那麼什麼是函數式接口呢?
若接口中隻有一個抽象方法的接口,那麼我們就稱其為函數式接口;
我們可以使用注解@FunctionalInterface标注某個接口為函數式接口;
使用該注解之後,可以對該接口進行檢查,檢查其是否為函數式接口;
其實,這就是lambad的限制條件;
備足:lambad+政策模式,是一種非常友好的實作之一;
六、lambad表達式小練習
1、調用collections.sort()方法,通過定制排序比較兩個employee(先按年齡比,年齡相同按姓名比),使用lambad作為參數傳遞;
1)、代碼實作
package 聯系題; import java.util.Arrays; import java.util.Collections; import java.util.List; import 為什麼要使用lambad表達式.entity.Employee; public class TestLambad { //建立資料 private static List<Employee> employeesList = Arrays.asList( new Employee("張三",18,9999.99), new Employee("李四",38,5555.55), new Employee("王五",50,6666.66), new Employee("趙六",16,3333.33), new Employee("田七", 8,7777.77) ); public static void test1() { Collections.sort(employeesList, (e1,e2)->{ if(e1.getAge()==e2.getAge()) { return e1.getName().compareTo(e2.getName()); }else { return Integer.compare(e1.getAge(),e2.getAge()); } }); } public static void main(String[] args) { test1(); employeesList.forEach(e->System.out.println(e)); } } |
2)、運作效果:
Employee [name=田七, age=8, salary=7777.77] Employee [name=趙六, age=16, salary=3333.33] Employee [name=張三, age=18, salary=9999.99] Employee [name=李四, age=38, salary=5555.55] Employee [name=王五, age=50, salary=6666.66] |
2、自定義練習題1
聲明一個帶有兩個泛型的函數式接口,泛型為<T,R>,T為參數,R為傳回值;
接口中聲明抽象方法;
在TestLambad類中聲明方法,使用接口作為參數,計算兩個long類型參數的和;
再計算兩個long類型參數的積;
1)、代碼實作
package 聯系題; import java.util.Arrays; import java.util.Collections; import java.util.List; import 為什麼要使用lambad表達式.entity.Employee; import 聯系題.inter.MyFun; import 聯系題.inter.MyFunction; public class TestLambad { public static void test3() { Long longHadnler1 = longHadnler(100l,200l,(l1,l2)->l1+l2); System.out.println(longHadnler1); Long longHadnler2 = longHadnler(100l,200l,(l1,l2)->l1*l2); System.out.println(longHadnler2); } public static Long longHadnler(Long l1,Long l2,MyFun<Long,Long> mf) { return mf.getValue(l1,l2); } public static void main(String[] args) { test3(); } } |
2)、運作效果
300 20000 |