說 Lambda 寫的代碼像屎山,其實就是代碼不夠干凈嘛。說到底并不是不會用 Lambda 本身的 API,而是用的方式不對。
Java Lambda 本身提供了非常豐富的方法庫,大多數時候我們常用的方法也就為數不多的那幾個。Lambda 的使用方法之前專門寫過文章,8000字,讓你徹底了解 Java 8 的 Lambda、函數式接口、Stream 用法和原理。在掘金社區已經獲得了將近600個贊,1200多個收藏。
之所以被diss,也大概并不是你用了其中某個不常用的方法(那樣別人可能覺得你見多識廣)。更多的時候可能是因為這幾個原因:
先來看一段代碼,也就是經常被人(除自己外的所有人)說的屎山代碼。
private static List<SimpleUser> dirtyLambda(){ List<User> userList = User.buildUserList(30); List<SimpleUser> simpleUserList = userList.stream() .filter(user -> { return user.getGender().equals(1) && user.getAge() >= 18 && user.getAge() <= 45; }) .map(user -> { SimpleUser su = new SimpleUser(); su.setName(user.getName()); su.setAge(user.getAge()); Optional<Address> addressOptional = user.getAddressList().stream() .findFirst(); if (addressOptional.isPresent()) { su.setProvince(addressOptional.get().getProvince()); } return su; }) .sorted(Comparator.comparingInt(SimpleUser::getAge)) .collect(Collectors.toList()); return simpleUserList;}
如果不做解釋,是不是臟話馬上就要出來了。這其實在屎山代碼中也最多拍個中等,最起碼該換行的換行了,比如那個filter 中的三個并列條件,恐怕你是沒見過與或非排列組合的寫法,加上不怎么換行,那是真的讓人抓狂。
如果你覺得這代碼還可以,那有可能你也這么寫過。
不瞞各位,這樣的代碼我曾經寫過,而且一天之內不知道寫了多少行。曾經有一個需求,一個很復雜的報表,100多個變量+圖表+表格,什么最大值、最小值、環比、同比、正序、倒序、top3、top5、top10等等,就是各種能想到的維度統統算一遍。有經驗的同學一看就知道,這妥妥的體力活兒啊,但是時間只有一天,沒辦法,越寫越煩躁,直接躺平了,比上面這種更屎的代碼一段接一段的寫啊。寫完別說改了,看都不敢看啊。
說回正題,上面那個代碼的邏輯是這樣的:
那怎么做才能讓代碼變得清晰易懂,告別屎山 Lambda 呢?
不管你用什么辦法,只要做到下面這3點,Lambda 代碼塊立馬變清晰,最后一點可以適度放寬。
這其實沒什么好說的,本身代碼規約中就要求最好不寫超大方法,也就是行數過多的方法,更何況是在 Lambda 中。在函數式編程中,你寫的代碼其實是在小括號中,作為參數的形式出現的,一個多行的參數,不敢想啊。
不超過5行可不是說把換行符去掉,把之前的100行直接邊 1 行啊。而是下面這樣子,stream()就算一行了, 之后每個.function()都算一行,加起來不超過5行。
userList.stream() .filter() .filter() .map() .collect(Collectors.toList());
不要一個stream() 后面跟3個filter,4個map,再來個排序,再整個分組,有那么復雜的業務嗎,如果有,想想可能在上層設計的時候就出現問題了。
不要出現花括號,這其實就是縮短代碼行數的一個根本方法。用這個方法,強制你將邏輯抽離出來,這樣,你的代碼邏輯就會馬上變清晰,立竿見影。
拿前面的那端代碼舉個例子,其中map方法將 User轉換為SimpleUser,里面有賦值操作,還有一些判斷邏輯。
.map(user -> { SimpleUser su = new SimpleUser(); su.setName(user.getName()); su.setAge(user.getAge()); Optional<Address> addressOptional = user.getAddressList().stream() .findFirst(); if (addressOptional.isPresent()) { su.setProvince(addressOptional.get().getProvince()); } return su;})
直接將一段抽取成方法,在 IDEA 中操作也非常方便。選中花括號中的代碼,然后右鍵->Refactor->Extract Method,直接抽取出方法,連名字都幫忙取號了。
圖片
同樣的,filter()中的三個條件判斷也抽離出來。然后效果就是下面這樣,每一行的意圖都很清晰,誰還會說不能理解。
private static List<SimpleUser> dirtyLambda(){ List<User> userList = User.buildUserList(30); List<SimpleUser> simpleUserList = userList.stream() .filter(user -> filterUser(user)) .map(user -> getSimpleUser(user)) .sorted(Comparator.comparingInt(SimpleUser::getAge)) .collect(Collectors.toList()); return simpleUserList; } private static boolean filterUser(User user) { return user.getGender().equals(1) && user.getAge() >= 18 && user.getAge() <= 45; } private static SimpleUser getSimpleUser(User user) { SimpleUser su = new SimpleUser(); su.setName(user.getName()); su.setAge(user.getAge()); Optional<Address> addressOptional = user.getAddressList().stream() .findFirst(); if (addressOptional.isPresent()) { su.setProvince(addressOptional.get().getProvince()); } return su; }
再進一步,就是將 ->也干掉,雖然 ->后面沒有花括號已經很簡潔了,但是去掉->就不只是簡潔了,而是優雅了。
不用->,取而代之的是 ::,最終,去掉->后的代碼是下面這樣子。
private static List<SimpleUser> dirtyLambda(){ List<User> userList = User.buildUserList(30); return userList.stream() .filter(CleanLambda::filterUser) .map(CleanLambda::getSimpleUser) .sorted(Comparator.comparingInt(SimpleUser::getAge)) .collect(Collectors.toList());}private static boolean filterUser(User user) { return user.getGender().equals(1) && user.getAge() >= 18 && user.getAge() <= 45;}private static SimpleUser getSimpleUser(User user) { SimpleUser su = new SimpleUser(); su.setName(user.getName()); su.setAge(user.getAge()); Optional<Address> addressOptional = user.getAddressList().stream() .findFirst(); addressOptional.ifPresent(address -> su.setProvince(address.getProvince())); return su;}
本文只是拋磚引玉,并沒有介紹太細節的 Lambda 用法。授人以魚不如授人以漁,聰明人早就這樣寫了,更聰明的人已經去改代碼了。
本文鏈接:http://www.www897cc.com/showinfo-26-38109-0.html被人說 Lambda 代碼像...,那是沒用下面這三個方法
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com
上一篇: 數據處理利器:Pandas帶你游刃有余操控結構化數據
下一篇: 源碼解密協程隊列和線程隊列的實現原理