摘要:是在嘗試讓擁有跟類似的語法。在中使用,需要顯示得將集合轉(zhuǎn)成的步驟,而在中則免去了這樣的步驟。中的語句只能針對常量起作用,而使用模式匹配則可以對另一個函數(shù)的返回結(jié)果起作用,功能非常搶到。
Hystrix是Netflix開源的限流、熔斷降級組件,去年發(fā)現(xiàn)Hystrix已經(jīng)不再更新了,而在github主頁上將我引導(dǎo)到了另一個替代項目——resilience4j,這個項目是基于Java 8開發(fā)的,并且只使用了vavr庫,也就是我們今天要介紹的主角。
既然要談vavr,那么先要談為什么要使用vavr,vavr是為了增強(qiáng)Java的函數(shù)式編程體驗的,那么這里先介紹下Java中的函數(shù)式編程。
Java 8引入了函數(shù)式編程范式,思路是:將函數(shù)作為其他函數(shù)的參數(shù)傳遞,其實在Java 8之前,Java也支持類似的功能,但是需要使用接口實現(xiàn)多態(tài),或者使用匿名類實現(xiàn)。不管是接口還是匿名類,都有很多模板代碼,因此Java 8引入了Lambda表達(dá)式,正式支持函數(shù)式編程。
比方說,我們要實現(xiàn)一個比較器來比較兩個對象的大小,在Java 8之前,只能使用下面的代碼:
CompartorbyWeight = new Comparator () { public int compare(Apple a1, Apple a2) { return a1.getWeight().compareTo(a2.getWeight()); } }
上面的代碼使用Lambda表達(dá)式可以寫成下面這樣(IDEA會提示你做代碼的簡化):
ComparatorbyWeight = (Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight());
關(guān)于Lambda表達(dá)式,你需要掌握的知識點(diǎn)有:
Lambda表達(dá)式可以理解為是一種匿名函數(shù):它沒有名稱,但是又參數(shù)列表、函數(shù)主體、返回類型,可能還有一個可以拋出的異常列表;
函數(shù)式接口就是僅僅聲明了一個抽象方法的接口;
@FunctionalInterface注解對于函數(shù)式接口的作用,類似于@Override對于被重寫的方法——不是必須的,但是用了有助于提升代碼的可讀性,因此如果你在開發(fā)中自己定義函數(shù)式接口,最好也使用這個注解修飾;
Java 8自帶一些常用的函數(shù)式接口,放在java.util.function包里,包括Predicate
受限于 Java 標(biāo)準(zhǔn)庫的通用性要求和二進(jìn)制文件大小,Java 標(biāo)準(zhǔn)庫對函數(shù)式編程的 API 支持相對比較有限。函數(shù)的聲明只提供了 Function 和 BiFunction 兩種,流上所支持的操作的數(shù)量也較少?;谶@些原因,你也許需要vavr
來幫助你更好得使用Java 8進(jìn)行函數(shù)式開發(fā)。
vavr是在嘗試讓Java擁有跟Scala類似的語法。vavr提供了不可變的集合框架;更好的函數(shù)式編程特性;元組。
Vavr實現(xiàn)了一套新的Java集合框架來匹配函數(shù)式編程范式,vavr提供的集合都是不可變的。在Java中使用Stream,需要顯示得將集合轉(zhuǎn)成steam的步驟,而在vavr中則免去了這樣的步驟。
vavr的List是不可變的鏈表,在該鏈表對象上的操作都會生成一個新的鏈表對象。
使用Java 8的代碼:
Arrays.asList(1, 2, 3).stream().reduce((i, j) -> i + j); IntStream.of(1, 2, 3).sum();
使用vavr實現(xiàn)相同的功能,則更加直接:
//io.vavr.collection.List List.of(1, 2, 3).sum();
vavr的Stream是惰性鏈表,元素只有在必要的時候才會參與計算,因此大部分操作都可以在常量時間內(nèi)完成。
函數(shù)(Functions)Java 8提供了接受一個參數(shù)的函數(shù)式接口Function和接受兩個參數(shù)的函數(shù)式接口BiFunction,vavr則提供了最多可以接受8個參數(shù)的函數(shù)式接口:Function0、Function1、Function2、Function3、Function4……Function8。
vavr還提供了更多函數(shù)式編程的特性:
組合(Composition)
在數(shù)學(xué)上,函數(shù)組合可以用兩個函數(shù)形成第三個函數(shù),例如函數(shù)f:X->Y和函數(shù)g:Y->Z可以組合成h:g(f(x)),表示X->Z。這里看個組合的例子:
public class VavrFunctionExample { @Test public void testCompose() { //使用andThen Function1plusOne = a -> a + 1; Function1 multiplyByTwo = a -> a * 2; Function1 add1AndMultiplyBy2 = plusOne.andThen(multiplyByTwo); Assert.assertEquals(6, add1AndMultiplyBy2.apply(2).intValue()); //使用compose Function1 add1AndMultiplyBy2WithCompose = multiplyByTwo.compose(plusOne); Assert.assertEquals(6, add1AndMultiplyBy2WithCompose.apply(2).intValue()); } }
Lifting
你是不是常常寫這種代碼:調(diào)用一個函數(shù),判斷它的返回值是否符合需求,或者需要catch所有異常以防異常情況,甚至是catch(Throwable t)。Lifting特性就是為了解決這個問題而存在的,可以在內(nèi)部處理異常情況,并將異常轉(zhuǎn)換成一個特殊的結(jié)果None,這樣函數(shù)外部就可以用統(tǒng)一的模式去處理函數(shù)結(jié)果。舉個例子:
public class VavrFunctionExample { @Test public void testLifting() { Function2divide = (a, b) -> a / b; Function2 > safeDivide = Function2.lift(divide); // = None Option i1 = safeDivide.apply(1, 0); Assert.assertEquals("None", i1.toString()); // = Some(2) Option i2 = safeDivide.apply(4, 2); Assert.assertEquals(2, i2.get().intValue()); } }
柯里化方法(Curring)
柯里化(Currying)指的是將原來接受多個參數(shù)的函數(shù)變成新的接受一個參數(shù)的函數(shù)的過程。對于Java來說,可以方便得提供默認(rèn)值方法,這里看個例子:
public class VavrFunctionExample { @Test public void testCurried() { Function2sum = (a, b) -> a + b; Function1 add2 = sum.curried().apply(2); Assert.assertEquals(6, add2.apply(4).intValue()); } }
記憶化方法(Memorization)
這是一種緩存,某個方法只需要執(zhí)行一次,后面都會返回第一次的結(jié)果;但是在實際應(yīng)用中用到的地方應(yīng)該不多。
public class VavrFunctionExample { @Test public void testMemorize() { Function0模式匹配hashCache = Function0.of(Math::random).memoized(); double randomValue1 = hashCache.apply(); double randomValue2 = hashCache.apply(); Assert.assertTrue(randomValue1 == randomValue1); } }
模式匹配是函數(shù)式編程語言中的概念,目前Java中還不支持這個特性,使用vavr可以用Java寫模式匹配的代碼。Java中的switch...case語句只能針對常量起作用,而使用模式匹配則可以對另一個函數(shù)的返回結(jié)果起作用,功能非常搶到。下面的例子分別給出了使用if、switch...case、模式匹配三個語法實現(xiàn)同樣功能的例子,可以看出,模式匹配有助于減少代碼行數(shù)。
import org.junit.Test; import static io.vavr.API.$; import static io.vavr.API.Case; import static io.vavr.API.Match; import static org.junit.Assert.assertEquals; public class VavrPatternExample { @Test public void whenIfWorksAsMatcher_thenCorrect() { int input = 3; String output; if (input == 0) { output = "zero"; } if (input == 1) { output = "one"; } if (input == 2) { output = "two"; } if (input == 3) { output = "three"; } else { output = "unknown"; } assertEquals("three", output); } @Test public void whenSwitchWorksAsMatcher_thenCorrect() { int input = 2; String output; switch (input) { case 0: output = "zero"; break; case 1: output = "one"; break; case 2: output = "two"; break; case 3: output = "three"; break; default: output = "unknown"; break; } assertEquals("two", output); } @Test public void whenMatchworks_thenCorrect() { int input = 2; String output = Match(input).of( Case($(1), "one"), Case($(2), "two"), Case($(3), "three"), Case($(), "?")); assertEquals("two", output); } }參考資料
《Java 8實戰(zhàn)》
https://github.com/resilience4j/resilience4j
https://www.baeldung.com/vavr
https://www.vavr.io/vavr-docs/
本號專注于后端技術(shù)、JVM問題排查和優(yōu)化、Java面試題、個人成長和自我管理等主題,為讀者提供一線開發(fā)者的工作和成長經(jīng)驗,期待你能在這里有所收獲。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/75053.html
摘要:面向?qū)ο蟪R姷脑O(shè)計模式有策略模式模板方法觀察者模式責(zé)任鏈模式以及工廠模式,使用表達(dá)式函數(shù)式編程思維有助于避免面向?qū)ο箝_發(fā)中的那些固定代碼。 本文是一篇《Java 8實戰(zhàn)》的閱讀筆記,閱讀大約需要5分鐘。 有點(diǎn)標(biāo)題黨,但是這確實是我最近使用Lambda表達(dá)式的感受。設(shè)計模式是過去的一些好的經(jīng)驗和套路的總結(jié),但是好的語言特性可以讓開發(fā)者不去考慮這些設(shè)計模式。面向?qū)ο蟪R姷脑O(shè)計模式有策略模式...
摘要:問對于程序員修煉之道你有下一步的計劃嗎程序員修煉之道這個項目很好,寫作的過程也很愉快。而最上層的程序員則是時刻對技藝以及技術(shù)的本質(zhì)著迷。這也是的一大優(yōu)勢。 非商業(yè)轉(zhuǎn)載請注明作譯者、出處,并保留本文的原始鏈接:http://www.ituring.com.cn/article/127453 Ben Evans是jClarity的聯(lián)合創(chuàng)始人。其公司致力于開發(fā)可以為開發(fā)和運(yùn)維團(tuán)隊提...
摘要:通過如下命令發(fā)布控制臺,運(yùn)行編寫的默認(rèn)程序。默認(rèn)禁用,啟用它需要打開并取消注釋以下行。啟用數(shù)據(jù)庫啟動應(yīng)用程序的數(shù)據(jù)庫,框架提供了內(nèi)置的數(shù)據(jù)庫的支持。當(dāng)用戶發(fā)出請求到,一個新的將被創(chuàng)建。方法為給定的獲取,把這個轉(zhuǎn)換成格式并返回響應(yīng)。 編者注:我們發(fā)現(xiàn)了有趣的系列文章《30天學(xué)習(xí)30種新技術(shù)》,正在翻譯,一天一篇更新,年終禮包。下面是第 30 天的內(nèi)容。 今天是最后一天,我決定學(xué)習(xí)一...
摘要:本文介紹和點(diǎn)評上的等并發(fā)編程模型。異步更適合并發(fā)編程。同步使線程阻塞,導(dǎo)致等待?;灸P瓦@是最簡單的模型,創(chuàng)建線程來執(zhí)行一個任務(wù),完畢后銷毀線程。響應(yīng)式編程是一種面向數(shù)據(jù)流和變化傳播的編程模式。起源于電信領(lǐng)域的的編程模型。 本文介紹和點(diǎn)評JVM上的Thread, Thread Pool, Future, Rx, async-await, Fiber, Actor等并發(fā)編程模型。本人經(jīng)驗...
摘要:本文介紹和點(diǎn)評上的等并發(fā)編程模型。異步更適合并發(fā)編程。同步使線程阻塞,導(dǎo)致等待?;灸P瓦@是最簡單的模型,創(chuàng)建線程來執(zhí)行一個任務(wù),完畢后銷毀線程。響應(yīng)式編程是一種面向數(shù)據(jù)流和變化傳播的編程模式。起源于電信領(lǐng)域的的編程模型。 本文介紹和點(diǎn)評JVM上的Thread, Thread Pool, Future, Rx, async-await, Fiber, Actor等并發(fā)編程模型。本人經(jīng)驗...
閱讀 1216·2021-09-03 10:44
閱讀 617·2019-08-30 13:13
閱讀 2808·2019-08-30 13:11
閱讀 1976·2019-08-30 12:59
閱讀 1043·2019-08-29 15:32
閱讀 1607·2019-08-29 15:25
閱讀 1003·2019-08-29 12:24
閱讀 1290·2019-08-27 10:58