您好,我是湘王,這是我的博客園,歡迎您來,歡迎您再來~ Lambda表達式雖然將介面作為代碼塊賦值給了變數,但如果僅僅只是Lambda表達式,還無法讓Java由量變引起質變。真正讓Lambda能夠發揮出巨大威力的,就是流式計算。 所謂流式計算,就是讓數據像在流水線上一樣,從一道工序流轉到下一道工序。 ...
您好,我是湘王,這是我的博客園,歡迎您來,歡迎您再來~
Lambda表達式雖然將介面作為代碼塊賦值給了變數,但如果僅僅只是Lambda表達式,還無法讓Java由量變引起質變。真正讓Lambda能夠發揮出巨大威力的,就是流式計算。
所謂流式計算,就是讓數據像在流水線上一樣,從一道工序流轉到下一道工序。就像這樣:
如果把數據處理的方式比作流水線,那麼Spark、Storm和Flink就是目前市面上頭部的三家工廠。它們有各種各樣的數據裝配間(也就是各種處理數據的運算元),將數據按照所需加工成型。所以,不懂流式計算根本就做不了大數據開發。上面那張圖,如果換成流式計算的,就是這樣:
Lambda表達式就變成了一個個的數據裝配間。
還是以實際的代碼例子來說明。假如有這樣的代碼:
/**
* 雇員數據
*
* @author 湘王
*/
public class Employee {
public enum Type { MANAGER, SELLER, OFFICER };
private String name;
private String genger;
private Integer age;
private boolean married;
private Type type;
public Employee(final String name, final String genger, final Integer age, final boolean married, final Type type) {
super();
this.name = name;
this.genger = genger;
this.age = age;
this.married = married;
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGenger() {
return genger;
}
public void setGenger(String genger) {
this.genger = genger;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public boolean isMarried() {
return married;
}
public void setMarried(boolean married) {
this.married = married;
}
public Type getType() {
return type;
}
public void setType(Type type) {
this.type = type;
}
@Override
public String toString() {
return this.name + "(" + this.genger + ")-" + this.age;
}
}
如果想篩選28歲以下的員工,並按年齡排序,用老辦法只能這麼做:
List<Employee> employees = Arrays.asList(
new Employee("張勇", "男", 28, true, Employee.Type.MANAGER),
new Employee("李強", "男", 22, false, Employee.Type.SELLER),
new Employee("王武", "男", 32, false, Employee.Type.SELLER),
new Employee("梅麗", "女", 26, true, Employee.Type.OFFICER),
new Employee("鄭帥", "男", 29, false, Employee.Type.OFFICER),
new Employee("曾美", "女", 27, true, Employee.Type.SELLER),
new Employee("郝俊", "男", 22, true, Employee.Type.SELLER),
new Employee("方圓", "女", 24, false, Employee.Type.SELLER)
);
// 傳統篩選數據的方法
// 篩選28歲以下的員工
List<Employee> list1 = new ArrayList<>();
for(Employee employee : employees) {
if (employee.getAge() < 28) {
list1.add(employee);
}
}
// 按年齡排序
list1.sort(new Comparator<Employee>() {
@Override
public int compare(Employee o1, Employee o2) {
return o1.getAge().compareTo(o2.getAge());
}
});
如果要轉換成Lmabda表達式的話,就是這樣:
/**
* 雇員函數式介面
*
* @author 湘王
*/
@FunctionalInterface
public interface EmployeeInterface<T> {
boolean select(T t);
}
public static List<Employee> filter(List<Employee> employees, EmployeeInterface<Employee> ei) {
List<Employee> list = new ArrayList<>();
for(Employee employee : employees) {
if (ei.select(employee)) {
list.add(employee);
}
}
return list;
}
// 使用Lambda表達式得到28歲以下的員工
List<Employee> list2 = filter(employees, employee -> employee.getAge() < 28);
// 按年齡排序
list2.sort((e1, e2) -> e1.getAge().compareTo(e2.getAge()));
可以看到,這雖然用了Lambda表達式替代了舊的方法,但可能要寫大量的函數式介面,Lambda淪為雞肋,完全談不上簡便快速,更別說優雅!
所以,這時候如果用流式計算,那簡直不要太優雅:
// Lambda表達式 + 流式計算
List<Employee> list3 = employees
// 生成「流」
.stream()
// 過濾
.filter(emp -> emp.getAge() < 28)
// 排序
.sorted((o1, o2) -> o1.getAge().compareTo(o2.getAge()))
// 生成新的結果集合
.collect(Collectors.toList());
僅僅幾行代碼就搞定了,完全沒有之前那種「傻大黑粗」的感覺了。
上面的代碼,可以用這幅圖來還原:
1、先用filter運算元(流式計算中的函數,或者方法,在大數據中統稱為運算元,我也習慣這麼稱呼)將符合年齡條件的雇員篩選出來;
2、再按照年齡從低到高排序;
3、將排好序的員工列表輸出出來。
就是這麼簡單粗暴!
就像藏寶圖一樣,只有將Lambda表達式和流式計算這兩張碎片拼起來,才是完整的Java函數式編程。
所有的流式計算運算元可以分為兩大類:中間操作和終端操作。
1、中間操作:返回另一個流,如filter、map、flatMap等;
2、終端操作:從流水線中生成結果,如collect、count、reduce、forEach等。
現在,咱們已經找到了函數式編程這個寶藏。那麼再回到最初的問題:當要實現某寶、某東和某哈哈的員工聯誼並解決單身問題時,有更好的辦法嗎?
當然有,而且只用一行代碼就可以搞定:
List<Employee> unMarriedList4 = list.stream().filter(company -> Company.Type.BIG == company.getType()).flatMap(companys -> companys.getEmployees().stream()).filter(Employee::isMarried).sorted(Comparator.comparing(Employee::getAge)).collect(Collectors.toList());
感謝您的大駕光臨!咨詢技術、產品、運營和管理相關問題,請關註後留言。歡迎騷擾,不勝榮幸~