給定一個字符串元素列表,,如下所示: ['1', '2', 'bilibili', 'of', 'codesheep', '5', 'at', 'BILIBILI', 'codesheep', '23', 'CHEERS', '6']
里面有數(shù)字型字符串,,有字母型字符串;字符串里有大寫,,也有小寫,;字符串長度也有長有短 現(xiàn)在要寫代碼完成一個小功能: 我想找出所有 長度>=5的字符串,并且忽略大小寫,、去除重復字符串,,然后按字母排序,最后用“愛心?”連接成一個字符串輸出,!
喲,,就這點需求能難倒我?三分鐘之類必搞定,! 首先我寫一個函數(shù),,判斷輸入字符串到底是字母還是數(shù)字 publicstaticBoolean isNum( String str ) {
for( int i=0; i<str.length(); i++ ) {
if(!Character.isDigit(str.charAt(i))) {
returnfalse;
}
}
returntrue;
}
接下來我一頓SAO操作: // 先定義一個具備按字母排序功能的Set容器,Set本身即可去重
Set<String> stringSet = newTreeSet<String>(
newComparator<String>() {
@Override
publicint compare(String o1, String o2) {
return o1.compareTo(o2); // 按字母順序排列
}
}
);
// 以下for循環(huán)完成元素去重,、大小寫轉(zhuǎn)換、長度判斷等操作
for( int i=0; i<list.size(); i++ ) {
String s = list.get(i);
if( !isNum(s) && s.length()>=5) {
String sLower = s.toLowerCase(); // 統(tǒng)一轉(zhuǎn)小寫
stringSet.add( sLower );
}
}
// 以下for循環(huán)完成連詞成句
StringBuilder result = newStringBuilder();
for( String s : stringSet ) {
result.append( s );
result.append('?'); // 用“愛心”連接符連接
}
String finalResult = result.substring(0,result.length()-1).toString(); // 去掉最后一個多余連接符
System.out.println( finalResult );
最后輸出結(jié)果為: bilibili?cheers?codesheep
啪啪啪,,打臉 我原以為這個功能我只需要3分鐘即可寫完并運行出結(jié)果,,而實際對時我發(fā)現(xiàn)我居然花了5分鐘。,。,。 而且我現(xiàn)在是一看到for循環(huán)遍歷,我頭就痛,,上面代碼倒還好,,假如列表層級變復雜,俄羅斯套娃式的for循環(huán) 誰扛得住,。
沒錯,自Java 8開始,,引入了函數(shù)式編程范式,,這對于咱這種底層勞動密集型碼畜來說,簡直解放了雙手,,代碼幾乎少寫一半,,從此真正實現(xiàn)編碼5分鐘,劃水2小時,! 針對上面的作業(yè),,用Java 8的 Stream 流式操作,僅需一行代碼就可以搞定,,for循環(huán)啥的統(tǒng)統(tǒng)灰飛煙滅,。 String result = list.stream()// 首先將列表轉(zhuǎn)化為Stream流
.filter( i -> !isNum(i) )// 首先篩選出字母型字符串
.filter( i -> i.length() >= 5)// 其次篩選出長度>=5的字符串
.map( i -> i.toLowerCase() )// 字符串統(tǒng)一轉(zhuǎn)小寫
.distinct() // 去重操作來一下
.sorted( Comparator.naturalOrder() ) // 字符串排序來一下
.collect( Collectors.joining('?') ); // 連詞成句來一下,完美,!
System.out.println(result);
怎么樣,,這代碼信噪比可以吧
上面其實已經(jīng)通過舉栗的方式闡述了Java 8函數(shù)式編程范式:Stream流 的優(yōu)雅和強大,尤其在處理集合時,,幾本一步到位,,嘎嘣脆。 當然Stream也僅僅只是Java 8函數(shù)式編程接口的一個而已,,除了Stream接口,,還有其他非常強大的函數(shù)式編程接口,比如: Consumer 接口
Optional 接口
Function 接口
每個接口我們都來舉一個好理解的例子,,看完保證你難以拒絕,! 一、Consumer接口 顧名思義,,它是“消費者的含義”,,接受參數(shù)而不返回值,舉個最最常見的栗子: 平時我們打印字符串,,本質(zhì)也是接受一個參數(shù)并打印出來,,我們一般想都不想,會這樣寫: System.out.println('hello world'); // 打印 hello world
System.out.println('hello codesheep'); // 打印 hello codesheep
System.out.println('bilibili cheers'); // 打印 bilibili cheers
一旦你用了 Consumer 之后,,總感覺更加優(yōu)雅一些 Consumer c = System.out::println;
c.accept('hello world'); // 打印 hello world
c.accept('hello codesheep'); // 打印 hello codesheep
c.accept('bilibili cheers'); // 打印 bilibili cheers
而且 Consumer 還可以用聯(lián)用,,達到多重處理的效果,比如: c.andThen(c).andThen(c).accept('hello world');
// 會連續(xù)打印 3次:hello world
當然本例只是打印字符串,,比較簡單,,若業(yè)務更加復雜, Consumer 復用帶來的便利性還是不小的。 二,、Function接口 Function 接口代表的含義是“函數(shù)”,,其實和上面的 Consumer 有點像,不過 Function 既有輸入,,也有輸出,,使用更加靈活,舉例:
比如我想對一個整數(shù)先乘以 2 ,,再計算平方值 Function<Integer,Integer> f1 = i -> i+i; // 乘以2功能
Function<Integer,Integer> f2 = i -> i*i; // 平方功能
Consumer c = System.out::println; // 打印功能
c.accept( f1.andThen(f2).apply(2) ); // 三種功能組合:打印結(jié)果 16
別的不說,,這個炫技操作還是可以的! 三,、Optional接口 Optional 本質(zhì)是個容器,,你可以將你的變量交由它進行封裝,這樣我們就不用顯式對原變量進行 null 值檢測,,防止出現(xiàn)各種空指針異常,。舉例:
我們想寫一個獲取學生某個課程考試分數(shù)的函數(shù):getScore() publicInteger getScore( Student student ) {
if( student != null) { // 第一層 null判空
Subject subject = student.getSubject();
if( subject != null) { // 第二層 null判空
return subject.score;
}
}
returnnull;
}
這樣寫倒不是不可以,但我們作為一個“嚴謹且良心的”后端工程師,,這么多嵌套的 if 判空多少有點扎眼,! 為此我們必須引入 Optional : publicInteger getScore( Student student ) {
returnOptional.ofNullable(student)
.map( Student::getSubject )
.map( Subject::getScore )
.orElse(null);
}
漂亮!嵌套的if/else判空灰飛煙滅,!
好啦,,本文就拋磚引玉到這里了,大家可以在自己的代碼中用函數(shù)式編程范式嘗試做小規(guī)模重構(gòu),,相信用起來還是非常甜蜜的,。 立個Flag,以后寫代碼,,估計我會很少使用for循環(huán)了(滑稽),,Stream流用起來簡直不要太爽啊。,。,。 開個玩笑,函數(shù)式編程范式雖然用起來很爽,,但也最好根據(jù)實際業(yè)務情況來決定是否使用,,畢竟大面積的動態(tài)范式代碼還是挺難看懂和維護的,總之就一句話,,理性使用,不要濫用,。 2020.01.01晚
●編號1162,,輸入編號直達本文
●輸入m獲取文章目錄 分享程序員找工作經(jīng)驗 程序員筆試、面試題
|