国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Java8學(xué)習(xí)小記

CHENGKANG / 2309人閱讀

摘要:但有一個(gè)限制它們不能修改定義的方法的局部變量的內(nèi)容。如前所述,這種限制存在的原因在于局部變量保存在棧上,并且隱式表示它們僅限于其所在線程。

2014年,Oracle發(fā)布了Java8新版本。對(duì)于Java來(lái)說(shuō),這顯然是一個(gè)具有里程碑意義的版本。尤其是那函數(shù)式編程的功能,避開(kāi)了Java那煩瑣的語(yǔ)法所帶來(lái)的麻煩。

這可以算是一篇Java8的學(xué)習(xí)筆記。將Java8一些常見(jiàn)的一些特性作了一個(gè)概要的筆記。

行為參數(shù)化(Lambda以及方法引用)

為了編寫可重用的方法,比如filter,你需要為其指定一個(gè)參數(shù),它能夠精確地描述過(guò)濾條件。雖然Java專家們使用之前的版本也能達(dá)到同樣的目的(將過(guò)濾條件封裝成類的一個(gè)方法,傳遞該類的一個(gè)實(shí)例),但這種方案卻很難推廣,因?yàn)樗ǔ7浅S纺[,既難于編寫,也不易于維護(hù)。

Java 8通過(guò)借鑒函數(shù)式編程,提供了一種新的方式——通過(guò)向方法傳遞代碼片段來(lái)解決這一問(wèn)題。這種新的方法非常方便地提供了兩種變體。

傳遞一個(gè)Lambda表達(dá)式,即一段精簡(jiǎn)的代碼片段,比如

    apple -> apple.getWeight() > 150

傳遞一個(gè)方法引用,該方法引用指向了一個(gè)現(xiàn)有的方法,比如這樣的代碼:

    Apple::isHeavy

這些值具有類似Function、Predicate或者BiFunction這樣的類型,值的接收方可以通過(guò)apply、test或其他類似的方法執(zhí)行這些方法。Lambda表達(dá)式自身是一個(gè)相當(dāng)酷炫的概念,不過(guò)Java 8對(duì)它們的使用方式——將它們與全新的Stream API相結(jié)合,最終把它們推向了新一代Java的核心。

閉包
你可能已經(jīng)聽(tīng)說(shuō)過(guò)閉包(closure,不要和Clojure編程語(yǔ)言混淆)這個(gè)詞,你可能會(huì)想Lambda是否滿足閉包的定義。用科學(xué)的說(shuō)法來(lái)說(shuō),閉包就是一個(gè)函數(shù)的實(shí)例,且它可以無(wú)限制地訪問(wèn)那個(gè)函數(shù)的非本地變量。例如,閉包可以作為參數(shù)傳遞給另一個(gè)函數(shù)。它也可以訪問(wèn)和修改其作用域之外的變量?,F(xiàn)在,Java 8的Lambda和匿名類可以做類似于閉包的事情:它們可以作為參數(shù)傳遞給方法,并且可以訪問(wèn)其作用域之外的變量。但有一個(gè)限制:它們不能修改定義Lambda的方法的局部變量的內(nèi)容。這些變量必須是隱式最終的??梢哉J(rèn)為L(zhǎng)ambda是對(duì)值封閉,而不是對(duì)變量封閉。如前所述,這種限制存在的原因在于局部變量保存在棧上,并且隱式表示它們僅限于其所在線程。如果允許捕獲可改變的局部變量,就會(huì)引發(fā)造成線程不安全的新的可能性,而這是我們不想看到的(實(shí)例變量可以,因?yàn)樗鼈儽4嬖诙阎?,而堆是在線程之間共享的)。
函數(shù)接口

Java 8之前,接口主要用于定義方法簽名,現(xiàn)在它們還能為接口的使用者提供方法的默認(rèn)實(shí)現(xiàn),如果接口的設(shè)計(jì)者認(rèn)為接口中聲明的某個(gè)方法并不需要每一個(gè)接口的用戶顯式地提供實(shí)現(xiàn),他就可以考慮在接口的方法聲明中為其定義默認(rèn)方法。

對(duì)類庫(kù)的設(shè)計(jì)者而言,這是個(gè)偉大的新工具,原因很簡(jiǎn)單,它提供的能力能幫助類庫(kù)的設(shè)計(jì)者們定義新的操作,增強(qiáng)接口的能力,類庫(kù)的用戶們(即那些實(shí)現(xiàn)該接口的程序員們)不需要花費(fèi)額外的精力重新實(shí)現(xiàn)該方法。因此,默認(rèn)方法與庫(kù)的用戶也有關(guān)系,它們屏蔽了將來(lái)的變化對(duì)用戶的影響。

在接口上添加注解:@FunctionalInterface。即可聲明該接口為函數(shù)接口。

如果你去看看新的Java API,會(huì)發(fā)現(xiàn)函數(shù)式接口帶有@FunctionalInterface的標(biāo)注。這個(gè)標(biāo)注用于表示該接口會(huì)設(shè)計(jì)成一個(gè)函數(shù)式接口。如果你用@FunctionalInterface定義了一個(gè)接口,而它卻不是函數(shù)式接口的話,編譯器將返回一個(gè)提示原因的錯(cuò)誤。例如,錯(cuò)誤消息可能是“Multiple non-overriding abstract methods found in interface Foo”,表明存在多個(gè)抽象方法。請(qǐng)注意,@FunctionalInterface不是必需的,但對(duì)于為此設(shè)計(jì)的接口而言,使用它是比較好的做法。它就像是@Override標(biāo)注表示方法被重寫了。

Lambdas及函數(shù)式接口的例子:

使用案例 Lambda例子 對(duì)應(yīng)的函數(shù)式接口
布爾表達(dá)式 (List list) -> list.isEmpty() Predicate>
創(chuàng)建對(duì)象 () -> new Apple(10) Supplier
消費(fèi)一個(gè)對(duì)象 (Apple a) ->System.out.println(a.getWeight()) Consumer
從一個(gè)對(duì)象中選擇/提取 (String s) -> s.length() Function或ToIntFunction
合并兩個(gè)值 (int a, int b) -> a * b IntBinaryOperator
比較兩個(gè)對(duì)象 (Apple a1, Apple a2) ->a1.getWeight().compareTo(a2.getWeight()) Comparator或BiFunction或ToIntBiFunction
簡(jiǎn)介

要討論流,我們先來(lái)談?wù)劶?,這是最容易上手的方式了。Java 8中的集合支持一個(gè)新的stream方法,它會(huì)返回一個(gè)流(接口定義在java.util.stream.Stream里)。你在后面會(huì)看到,還有很多其他的方法可以得到流,比如利用數(shù)值范圍或從I/O資源生成流元素。

那么,流到底是什么呢?簡(jiǎn)短的定義就是“從支持?jǐn)?shù)據(jù)處理操作的源生成的元素序列”。讓我們一步步剖析這個(gè)定義。

元素序列——就像集合一樣,流也提供了一個(gè)接口,可以訪問(wèn)特定元素類型的一組有序值。因?yàn)榧鲜菙?shù)據(jù)結(jié)構(gòu),所以它的主要目的是以特定的時(shí)間/空間復(fù)雜度存儲(chǔ)和訪問(wèn)元素(如ArrayList 與 LinkedList)。但流的目的在于表達(dá)計(jì)算,比如你前面見(jiàn)到的filter、sorted和map。集合講的是數(shù)據(jù),流講的是計(jì)算。我們會(huì)在后面幾節(jié)中詳細(xì)解釋這個(gè)思想。

源——流會(huì)使用一個(gè)提供數(shù)據(jù)的源,如集合、數(shù)組或輸入/輸出資源。 請(qǐng)注意,從有序集合生成流時(shí)會(huì)保留原有的順序。由列表生成的流,其元素順序與列表一致。

數(shù)據(jù)處理操作——流的數(shù)據(jù)處理功能支持類似于數(shù)據(jù)庫(kù)的操作,以及函數(shù)式編程語(yǔ)言中的常用操作,如filter、map、reduce、find、match、sort等。流操作可以順序執(zhí)行,也可并行執(zhí)行。

此外,流操作有兩個(gè)重要的特點(diǎn)。

流水線——很多流操作本身會(huì)返回一個(gè)流,這樣多個(gè)操作就可以鏈接起來(lái),形成一個(gè)大的流水線。這讓我們下一章中的一些優(yōu)化成為可能,如延遲和短路。流水線的操作可以看作對(duì)數(shù)據(jù)源進(jìn)行數(shù)據(jù)庫(kù)式查詢。

內(nèi)部迭代——與使用迭代器顯式迭代的集合不同,流的迭代操作是在背后進(jìn)行的。

流與集合

Java現(xiàn)有的集合概念和新的流概念都提供了接口,來(lái)配合代表元素型有序值的數(shù)據(jù)接口。所謂有序,就是說(shuō)我們一般是按順序取用值,而不是隨機(jī)取用的。那這兩者有什么區(qū)別呢?

我們先來(lái)打個(gè)直觀的比方吧。比如說(shuō)存在DVD里的電影,這就是一個(gè)集合(也許是字節(jié),也許是幀,這個(gè)無(wú)所謂),因?yàn)樗苏麄€(gè)數(shù)據(jù)結(jié)構(gòu)。現(xiàn)在再來(lái)想想在互聯(lián)網(wǎng)上通過(guò)視頻流看同樣的電影?,F(xiàn)在這是一個(gè)流(字節(jié)流或幀流)。流媒體視頻播放器只要提前下載用戶觀看位置的那幾幀就可以了,這樣不用等到流中大部分值計(jì)算出來(lái),你就可以顯示流的開(kāi)始部分了(想想觀看直播足球賽)。特別要注意,視頻播放器可能沒(méi)有將整個(gè)流作為集合,保存所需要的內(nèi)存緩沖區(qū)——而且要是非得等到最后一幀出現(xiàn)才能開(kāi)始看,那等待的時(shí)間就太長(zhǎng)了。出于實(shí)現(xiàn)的考慮,你也可以讓視頻播放器把流的一部分緩存在集合里,但和概念上的差異不是一回事。

粗略地說(shuō),集合與流之間的差異就在于什么時(shí)候進(jìn)行計(jì)算。集合是一個(gè)內(nèi)存中的數(shù)據(jù)結(jié)構(gòu),它包含數(shù)據(jù)結(jié)構(gòu)中目前所有的值——集合中的每個(gè)元素都得先算出來(lái)才能添加到集合中。(你可以往集合里加?xùn)|西或者刪東西,但是不管什么時(shí)候,集合中的每個(gè)元素都是放在內(nèi)存里的,元素都得先算出來(lái)才能成為集合的一部分。)

相比之下,流則是在概念上固定的數(shù)據(jù)結(jié)構(gòu)(你不能添加或刪除元素),其元素則是按需計(jì)算的。 這對(duì)編程有很大的好處。在第6章中,我們將展示構(gòu)建一個(gè)質(zhì)數(shù)流(2, 3, 5, 7, 11, …)有多簡(jiǎn)單,盡管質(zhì)數(shù)有無(wú)窮多個(gè)。這個(gè)思想就是用戶僅僅從流中提取需要的值,而這些值——在用戶看不見(jiàn)的地方——只會(huì)按需生成。這是一種生產(chǎn)者-消費(fèi)者的關(guān)系。從另一個(gè)角度來(lái)說(shuō),流就像是一個(gè)延遲創(chuàng)建的集合:只有在消費(fèi)者要求的時(shí)候才會(huì)計(jì)算值(用管理學(xué)的話說(shuō)這就是需求驅(qū)動(dòng),甚至是實(shí)時(shí)制造)。

與此相反,集合則是急切創(chuàng)建的(供應(yīng)商驅(qū)動(dòng):先把倉(cāng)庫(kù)裝滿,再開(kāi)始賣,就像那些曇花一現(xiàn)的圣誕新玩意兒一樣)。以質(zhì)數(shù)為例,要是想創(chuàng)建一個(gè)包含所有質(zhì)數(shù)的集合,那這個(gè)程序算起來(lái)就沒(méi)完沒(méi)了了,因?yàn)榭傆行碌馁|(zhì)數(shù)要算,然后把它加到集合里面。當(dāng)然這個(gè)集合是永遠(yuǎn)也創(chuàng)建不完的,消費(fèi)者這輩子都見(jiàn)不著了。

流的操作
操作 類型 返回類型 使用的類型、函數(shù)式接口 函數(shù)描述符
filter 中間 Stream Predicate T -> boolean
distinct 中間(有狀態(tài)-無(wú)界) Stream `` ``
skip 中間(有狀態(tài)-有界) Stream long ``
limit 中間(有狀態(tài)-有界) Stream long ``
map 中間 Stream Function T -> R
flatMap 中間 Stream Function> T -> Stream
sorted 中間(有狀態(tài)-無(wú)界) Stream Comparator (T, T) -> int
anyMatch 終端 boolean Predicate T -> boolean
noneMatch 終端 boolean Predicate T -> boolean
allMatch 終端 boolean Predicate T -> boolean
findAny 終端 Optional `` ``
findFirst 終端 Optional `` ``
forEach 終端 void Consumer T -> void
collect 終端 R Collector ``
reduce`` 終端(有狀態(tài)-有界) Optional BinaryOperator (T, T)-> T
count 終端 long `` ``
預(yù)定義收集器

Collectors類提供的工廠方法(例如groupingBy)創(chuàng)建的收集器。它們主要提供了三大功能:

將流元素歸約和匯總為一個(gè)值

元素分組

元素分區(qū)

Collectors類的靜態(tài)工廠方法

工廠方法 返回類型 用于
toList List 把流中所有項(xiàng)目收集到一個(gè)List

使用示例:

List dishes = menuStream.collect(toList());
工廠方法 返回類型 用于
toSet Set 把流中所有項(xiàng)目收集到一個(gè)Set,刪除重復(fù)項(xiàng)

使用示例:

Set dishes = menuStream.collect(toSet());
工廠方法 返回類型 用于
toCollection Collection 把流中所有項(xiàng)目收集到給定的供應(yīng)源創(chuàng)建的集合

使用示例:

Collection dishes = menuStream.collect(toCollection(),ArrayList::new);
工廠方法 返回類型 用于
counting Long 計(jì)算流中元素的個(gè)數(shù)

使用示例:

long howManyDishes = menuStream.collect(counting());
工廠方法 返回類型 用于
summingInt Integer 對(duì)流中項(xiàng)目的一個(gè)整數(shù)屬性求和

使用示例:

int totalCalories =
    menuStream.collect(summingInt(Dish::getCalories));
工廠方法 返回類型 用于
averagingInt Double 計(jì)算流中項(xiàng)目Integer屬性的平均值

使用示例:

double avgCalories =
    menuStream.collect(averagingInt(Dish::getCalories));
工廠方法 返回類型 用于
summarizingInt IntSummaryStatistics 收集關(guān)于流中項(xiàng)目Integer屬性的統(tǒng)計(jì)值,例如最大、最小、總和與平均值

使用示例:

IntSummaryStatistics menuStatistics =
    menuStream.collect(summarizingInt(Dish::getCalories));
工廠方法 返回類型 用于
joining` String 連接對(duì)流中每個(gè)項(xiàng)目調(diào)用toString方法所生成的字符串

使用示例:

String shortMenu =
    menuStream.map(Dish::getName).collect(joining(", "));
工廠方法 返回類型 用于
maxBy Optional 一個(gè)包裹了流中按照給定比較器選出的最大元素的Optional,或如果流為空則為Optional.empty()

使用示例:

Optional fattest =
    menuStream.collect(maxBy(comparingInt(Dish::getCalories)));
工廠方法 返回類型 用于
minBy Optional 一個(gè)包裹了流中按照給定比較器選出的最小元素的Optional,或如果流為空則為Optional.empty()

使用示例:

Optional lightest =
    menuStream.collect(minBy(comparingInt(Dish::getCalories)));
工廠方法 返回類型 用于
reducing 歸約操作產(chǎn)生的類型 從一個(gè)作為累加器的初始值開(kāi)始,利用BinaryOperator與流中的元素逐個(gè)結(jié)合,從而將流歸約為單個(gè)值

使用示例:

int totalCalories =
     menuStream.collect(reducing(0, Dish::getCalories, Integer::sum));
工廠方法 返回類型 用于
collectingAndThen 轉(zhuǎn)換函數(shù)返回的類型 包裹另一個(gè)收集器,對(duì)其結(jié)果應(yīng)用轉(zhuǎn)換函數(shù)

使用示例:

int howManyDishes =
    menuStream.collect(collectingAndThen(toList(), List::size));
工廠方法 返回類型 用于
groupingBy Map> 根據(jù)項(xiàng)目的一個(gè)屬性的值對(duì)流中的項(xiàng)目作問(wèn)組,并將屬性值作為結(jié)果Map的鍵

使用示例:

Map> dishesByType =
    menuStream.collect(groupingBy(Dish::getType));
工廠方法 返回類型 用于
partitioningBy Map> 根據(jù)對(duì)流中每個(gè)項(xiàng)目應(yīng)用謂詞的結(jié)果來(lái)對(duì)項(xiàng)目進(jìn)行分區(qū)

使用示例:

Map> vegetarianDishes =
    menuStream.collect(partitioningBy(Dish::isVegetarian));
并行流

在Java 7之前,并行處理數(shù)據(jù)集合非常麻煩。第一,你得明確地把包含數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu)分成若干子部分。第二,你要給每個(gè)子部分分配一個(gè)獨(dú)立的線程。第三,你需要在恰當(dāng)?shù)臅r(shí)候?qū)λ鼈冞M(jìn)行同步來(lái)避免不希望出現(xiàn)的競(jìng)爭(zhēng)條件,等待所有線程完成,最后把這些部分結(jié)果合并起來(lái)。Java 7引入了一個(gè)叫作分支/合并的框架,讓這些操作更穩(wěn)定、更不易出錯(cuò)。

我們簡(jiǎn)要地提到了Stream接口可以讓你非常方便地處理它的元素:可以通過(guò)對(duì)收集源調(diào)用parallelStream方法來(lái)把集合轉(zhuǎn)換為并行流。并行流就是一個(gè)把內(nèi)容分成多個(gè)數(shù)據(jù)塊,并用不同的線程分別處理每個(gè)數(shù)據(jù)塊的流。這樣一來(lái),你就可以自動(dòng)把給定操作的工作負(fù)荷分配給多核處理器的所有內(nèi)核,讓它們都忙起來(lái)。

高效使用并行流

一般而言,想給出任何關(guān)于什么時(shí)候該用并行流的定量建議都是不可能也毫無(wú)意義的,因?yàn)槿魏晤愃朴凇皟H當(dāng)至少有一千個(gè)(或一百萬(wàn)個(gè)或隨便什么數(shù)字)元素的時(shí)候才用并行流)”的建議對(duì)于某臺(tái)特定機(jī)器上的某個(gè)特定操作可能是對(duì)的,但在略有差異的另一種情況下可能就是大錯(cuò)特錯(cuò)。盡管如此,我們至少可以提出一些定性意見(jiàn),幫你決定某個(gè)特定情況下是否有必要使用并行流。

如果有疑問(wèn),測(cè)量。把順序流轉(zhuǎn)成并行流輕而易舉,但卻不一定是好事。我們?cè)诒竟?jié)中已經(jīng)指出,并行流并不總是比順序流快。此外,并行流有時(shí)候會(huì)和你的直覺(jué)不一致,所以在考慮選擇順序流還是并行流時(shí),第一個(gè)也是最重要的建議就是用適當(dāng)?shù)幕鶞?zhǔn)來(lái)檢查其性能。

留意裝箱。自動(dòng)裝箱和拆箱操作會(huì)大大降低性能。Java 8中有原始類型流(IntStream、LongStream、DoubleStream)來(lái)避免這種操作,但凡有可能都應(yīng)該用這些流。

有些操作本身在并行流上的性能就比順序流差。特別是limit和findFirst等依賴于元素順序的操作,它們?cè)诓⑿辛魃蠄?zhí)行的代價(jià)非常大。例如,findAny會(huì)比f(wàn)indFirst性能好,因?yàn)樗灰欢ㄒ错樞騺?lái)執(zhí)行。你總是可以調(diào)用unordered方法來(lái)把有序流變成無(wú)序流。那么,如果你需要流中的n 個(gè)元素而不是專門要前n 個(gè)的話,對(duì)無(wú)序并行流調(diào)用limit可能會(huì)比單個(gè)有序流(比如數(shù)據(jù)源是一個(gè)List)更高效。

還要考慮流的操作流水線的總計(jì)算成本。設(shè) N 是要處理的元素的總數(shù),Q 是一個(gè)元素通過(guò)流水線的大致處理成本,則 N*Q 就是這個(gè)對(duì)成本的一個(gè)粗略的定性估計(jì)。Q 值較高就意味著使用并行流時(shí)性能好的可能性比較大。

對(duì)于較小的數(shù)據(jù)量,選擇并行流幾乎從來(lái)都不是一個(gè)好的決定。并行處理少數(shù)幾個(gè)元素的好處還抵不上并行化造成的額外開(kāi)銷。

要考慮流背后的數(shù)據(jù)結(jié)構(gòu)是否易于分解。例如,ArrayList的拆分效率比LinkedList高得多,因?yàn)榍罢哂貌恢闅v就可以平均拆分,而后者則必須遍歷。另外,用range工廠方法創(chuàng)建的原始類型流也可以快速分解。

流自身的特點(diǎn),以及流水線中的中間操作修改流的方式,都可能會(huì)改變分解過(guò)程的性能。例如,一個(gè)SIZED流可以分成大小相等的兩部分,這樣每個(gè)部分都可以比較高效地并行處理,但篩選操作可能丟棄的元素個(gè)數(shù)卻無(wú)法預(yù)測(cè),導(dǎo)致流本身的大小未知。

還要考慮終端操作中合并步驟的代價(jià)是大是?。ɡ鏑ollector中的combiner方法)。如果這一步代價(jià)很大,那么組合每個(gè)子流產(chǎn)生的部分結(jié)果所付出的代價(jià)就可能會(huì)超出通過(guò)并行流得到的性能提升。

流的數(shù)據(jù)源和可分解性
可分解性
ArrayList 極佳
LinkedList
IntStream.range 極佳
Stream.iterate
HashSet
TreeSet
Optional

Java 8的庫(kù)提供了Optional類,這個(gè)類允許你在代碼中指定哪一個(gè)變量的值既可能是類型T的值,也可能是由靜態(tài)方法Optional.empty表示的缺失值。無(wú)論是對(duì)于理解程序邏輯,抑或是對(duì)于編寫產(chǎn)品文檔而言,這都是一個(gè)重大的好消息,你現(xiàn)在可以通過(guò)一種數(shù)據(jù)類型表示顯式缺失的值——使用空指針的問(wèn)題在于你無(wú)法確切了解出現(xiàn)空指針的原因,它是預(yù)期的情況,還是說(shuō)由于之前的某一次計(jì)算出錯(cuò)導(dǎo)致的一個(gè)偶然性的空值,有了Optional之后你就不需要再使用之前容易出錯(cuò)的空指針來(lái)表示缺失的值了。

Optional類的方法
方法 描述
empty 返回一個(gè)空的Optional實(shí)例
filter 如果值存在并且滿足提供的謂詞,就返回包含該值的Optional對(duì)象;否則返回一個(gè)空的Optional對(duì)象
flatMap 如果值存在,就對(duì)該值執(zhí)行提供的mapping函數(shù)調(diào)用,返回一個(gè)Optional類型的值,否則就返回一個(gè)空的Optional對(duì)象
get 如果該值存在,將該值用Optional封裝返回,否則拋出一個(gè)NoSuchElementException異常
ifPresent 如果值存在,就執(zhí)行使用該值的方法調(diào)用,否則什么也不做
isPresent 如果值存在就返回true,否則返回false
map 如果值存在,就對(duì)該值執(zhí)行提供的mapping函數(shù)調(diào)用
of 將指定值用Optional封裝之后返回,如果該值為null,則拋出一個(gè)NullPointerException異常
ofNullable 將指定值用Optional封裝之后返回,如果該值為null,則返回一個(gè)空的Optional對(duì)象
orElse 如果有值則將其返回,否則返回一個(gè)默認(rèn)值
orElseGet 如果有值則將其返回,否則返回一個(gè)由指定的Supplier接口生成的值
orElseThrow 如果有值則將其返回,否則拋出一個(gè)由指定的Supplier接口生成的異常
小結(jié)

null引用在歷史上被引入到程序設(shè)計(jì)語(yǔ)言中,目的是為了表示變量值的缺失。

Java 8中引入了一個(gè)新的類java.util.Optional,對(duì)存在或缺失的變量值進(jìn)行建模。

你可以使用靜態(tài)工廠方法Optional.empty、Optional.of以及Optional.ofNullable創(chuàng)建Optional對(duì)象。

Optional類支持多種方法,比如map、flatMap、filter,它們?cè)诟拍钌吓cStream類中對(duì)應(yīng)的方法十分相似。

使用Optional會(huì)迫使你更積極地解引用Optional對(duì)象,以應(yīng)對(duì)變量值缺失的問(wèn)題,最終,你能更有效地防止代碼中出現(xiàn)不期而至的空指針異常。

使用Optional能幫助你設(shè)計(jì)更好的API,用戶只需要閱讀方法簽名,就能了解該方法是否接受一個(gè)Optional類型的值。

CompletableFuture

Java從Java 5版本就提供了Future接口。Future對(duì)于充分利用多核處理能力是非常有益的,因?yàn)樗试S一個(gè)任務(wù)在一個(gè)新的核上生成一個(gè)新的子線程,新生成的任務(wù)可以和原來(lái)的任務(wù)同時(shí)運(yùn)行。原來(lái)的任務(wù)需要結(jié)果時(shí),它可以通過(guò)get方法等待Future運(yùn)行結(jié)束(生成其計(jì)算的結(jié)果值)。

Future接口的局限性

我們知道Future接口提供了方法來(lái)檢測(cè)異步計(jì)算是否已經(jīng)結(jié)束(使用isDone方法),等待異步操作結(jié)束,以及獲取計(jì)算的結(jié)果。但是這些特性還不足以讓你編寫簡(jiǎn)潔的并發(fā)代碼。比如,我們很難表述Future結(jié)果之間的依賴性;從文字描述上這很簡(jiǎn)單,“當(dāng)長(zhǎng)時(shí)間計(jì)算任務(wù)完成時(shí),請(qǐng)將該計(jì)算的結(jié)果通知到另一個(gè)長(zhǎng)時(shí)間運(yùn)行的計(jì)算任務(wù),這兩個(gè)計(jì)算任務(wù)都完成后,將計(jì)算的結(jié)果與另一個(gè)查詢操作結(jié)果合并”。但是,使用Future中提供的方法完成這樣的操作又是另外一回事。這也是我們需要更具描述能力的特性的原因,比如下面這些。

將兩個(gè)異步計(jì)算合并為一個(gè)——這兩個(gè)異步計(jì)算之間相互獨(dú)立,同時(shí)第二個(gè)又依賴于第一個(gè)的結(jié)果。

等待Future集合中的所有任務(wù)都完成。

僅等待Future集合中最快結(jié)束的任務(wù)完成(有可能因?yàn)樗鼈冊(cè)噲D通過(guò)不同的方式計(jì)算同一個(gè)值),并返回它的結(jié)果。

通過(guò)編程方式完成一個(gè)Future任務(wù)的執(zhí)行(即以手工設(shè)定異步操作結(jié)果的方式)。

應(yīng)對(duì)Future的完成事件(即當(dāng)Future的完成事件發(fā)生時(shí)會(huì)收到通知,并能使用Future計(jì)算的結(jié)果進(jìn)行下一步的操作,不只是簡(jiǎn)單地阻塞等待操作的結(jié)果)。

CompletableFuture 詳解

一個(gè)非常有用,不過(guò)不那么精確的格言這么說(shuō):“Completable-Future對(duì)于Future的意義就像Stream之于Collection?!弊屛覀儽容^一下這二者。

通過(guò)Stream你可以對(duì)一系列的操作進(jìn)行流水線,通過(guò)map、filter或者其他類似的方法提供行為參數(shù)化,它可有效避免使用迭代器時(shí)總是出現(xiàn)模板代碼。

類似地,CompletableFuture提供了像thenCompose、thenCombine、allOf這樣的操作,對(duì)Future涉及的通用設(shè)計(jì)模式提供了函數(shù)式編程的細(xì)粒度控制,有助于避免使用命令式編程的模板代碼。

新的日期和時(shí)間API

Java的API提供了很多有用的組件,能幫助你構(gòu)建復(fù)雜的應(yīng)用。不過(guò),Java API也不總是完美的。我們相信大多數(shù)有經(jīng)驗(yàn)的程序員都會(huì)贊同Java 8之前的庫(kù)對(duì)日期和時(shí)間的支持就非常不理想。然而,你也不用太擔(dān)心:Java 8中引入全新的日期和時(shí)間API就是要解決這一問(wèn)題。

LocalDate

LocalTime

LocalDateTime

Instant

Duration

Period

使用LocalDate和LocalTime還有LocalDateTime

開(kāi)始使用新的日期和時(shí)間API時(shí),你最先碰到的可能是LocalDate類。該類的實(shí)例是一個(gè)不可變對(duì)象,它只提供了簡(jiǎn)單的日期,并不含當(dāng)天的時(shí)間信息。另外,它也不附帶任何與時(shí)區(qū)相關(guān)的信息。

你可以通過(guò)靜態(tài)工廠方法of創(chuàng)建一個(gè)LocalDate實(shí)例。LocalDate實(shí)例提供了多種方法來(lái)讀取常用的值,比如年份、月份、星期幾等,如下所示。

LocalDate date = LocalDate.of(2014, 3, 18);    ←─2014-03-18
int year = date.getYear();    ←─2014
Month month = date.getMonth();    ←─MARCH
int day = date.getDayOfMonth();    ←─18
DayOfWeek dow = date.getDayOfWeek();    ←─TUESDAY
int len = date.lengthOfMonth();    ←─31 (days in March)
boolean leap = date.isLeapYear();    ←─false (not a leap year)
//你還可以使用工廠方法從系統(tǒng)時(shí)鐘中獲取當(dāng)前的日期:
LocalDate today = LocalDate.now();

LocalTime和LocalDateTime都提供了類似的方法。

機(jī)器的日期和時(shí)間格式

作為人,我們習(xí)慣于以星期幾、幾號(hào)、幾點(diǎn)、幾分這樣的方式理解日期和時(shí)間。毫無(wú)疑問(wèn),這種方式對(duì)于計(jì)算機(jī)而言并不容易理解。從計(jì)算機(jī)的角度來(lái)看,建模時(shí)間最自然的格式是表示一個(gè)持續(xù)時(shí)間段上某個(gè)點(diǎn)的單一大整型數(shù)。這也是新的java.time.Instant類對(duì)時(shí)間建模的方式,基本上它是以Unix元年時(shí)間(傳統(tǒng)的設(shè)定為UTC時(shí)區(qū)1970年1月1日午夜時(shí)分)開(kāi)始所經(jīng)歷的秒數(shù)進(jìn)行計(jì)算。

你可以通過(guò)向靜態(tài)工廠方法ofEpochSecond傳遞一個(gè)代表秒數(shù)的值創(chuàng)建一個(gè)該類的實(shí)例。靜態(tài)工廠方法ofEpochSecond還有一個(gè)增強(qiáng)的重載版本,它接收第二個(gè)以納秒為單位的參數(shù)值,對(duì)傳入作為秒數(shù)的參數(shù)進(jìn)行調(diào)整。重載的版本會(huì)調(diào)整納秒?yún)?shù),確保保存的納秒分片在0到999 999 999之間。這意味著下面這些對(duì)ofEpochSecond工廠方法的調(diào)用會(huì)返回幾乎同樣的Instant對(duì)象:

Instant.ofEpochSecond(3);
Instant.ofEpochSecond(3, 0);
Instant.ofEpochSecond(2, 1_000_000_000);    ←─2 秒之后再加上100萬(wàn)納秒(1秒)
Instant.ofEpochSecond(4, -1_000_000_000);    ←─4秒之前的100萬(wàn)納秒(1秒)

正如你已經(jīng)在LocalDate及其他為便于閱讀而設(shè)計(jì)的日期-時(shí)間類中所看到的那樣,Instant類也支持靜態(tài)工廠方法now,它能夠幫你獲取當(dāng)前時(shí)刻的時(shí)間戳。我們想要特別強(qiáng)調(diào)一點(diǎn),Instant的設(shè)計(jì)初衷是為了便于機(jī)器使用。它包含的是由秒及納秒所構(gòu)成的數(shù)字。所以,它無(wú)法處理那些我們非常容易理解的時(shí)間單位。比如下面這段語(yǔ)句:

int day = Instant.now().get(ChronoField.DAY_OF_MONTH);
它會(huì)拋出下面這樣的異常:

java.time.temporal.UnsupportedTemporalTypeException: Unsupported field:

 DayOfMonth

但是你可以通過(guò)Duration和Period類使用Instant,接下來(lái)我們會(huì)對(duì)這部分內(nèi)容進(jìn)行介紹。

定義Duration或Period

目前為止,你看到的所有類都實(shí)現(xiàn)了Temporal接口,Temporal接口定義了如何讀取和操縱為時(shí)間建模的對(duì)象的值。之前的介紹中,我們已經(jīng)了解了創(chuàng)建Temporal實(shí)例的幾種方法。很自然地你會(huì)想到,我們需要?jiǎng)?chuàng)建兩個(gè)Temporal對(duì)象之間的duration。Duration類的靜態(tài)工廠方法between就是為這個(gè)目的而設(shè)計(jì)的。你可以創(chuàng)建兩個(gè)LocalTimes對(duì)象、兩個(gè)LocalDateTimes對(duì)象,或者兩個(gè)Instant對(duì)象之間的duration,如下所示:

Duration d1 = Duration.between(time1, time2);
Duration d1 = Duration.between(dateTime1, dateTime2);
Duration d2 = Duration.between(instant1, instant2);

由于LocalDateTime和Instant是為不同的目的而設(shè)計(jì)的,一個(gè)是為了便于人閱讀使用,另一個(gè)是為了便于機(jī)器處理,所以你不能將二者混用。如果你試圖在這兩類對(duì)象之間創(chuàng)建duration,會(huì)觸發(fā)一個(gè)DateTimeException異常。此外,由于Duration類主要用于以秒和納秒衡量時(shí)間的長(zhǎng)短,你不能僅向between方法傳遞一個(gè)LocalDate對(duì)象做參數(shù)。

如果你需要以年、月或者日的方式對(duì)多個(gè)時(shí)間單位建模,可以使用Period類。使用該類的工廠方法between,你可以使用得到兩個(gè)LocalDate之間的時(shí)長(zhǎng),如下所示:

Period tenDays = Period.between(LocalDate.of(2014, 3, 8),
                                LocalDate.of(2014, 3, 18));

最后,Duration和Period類都提供了很多非常方便的工廠類,直接創(chuàng)建對(duì)應(yīng)的實(shí)例;換句話說(shuō),就像下面這段代碼那樣,不再是只能以兩個(gè)temporal對(duì)象的差值的方式來(lái)定義它們的對(duì)象。

創(chuàng)建Duration和Period對(duì)象

Duration threeMinutes = Duration.ofMinutes(3);
Duration threeMinutes = Duration.of(3, ChronoUnit.MINUTES);

Period tenDays = Period.ofDays(10);
Period threeWeeks = Period.ofWeeks(3);
Period twoYearsSixMonthsOneDay = Period.of(2, 6, 1);

Duration類和Period類共享了很多相似的方法:

方法名 是否是靜態(tài)方法 方法描述
between 創(chuàng)建兩個(gè)時(shí)間點(diǎn)之間的interval
from 由一個(gè)臨時(shí)時(shí)間點(diǎn)創(chuàng)建interval
of 由它的組成部分創(chuàng)建interval的實(shí)例
parse 由字符串創(chuàng)建interval的實(shí)例
addTo 創(chuàng)建該interval的副本,并將其疊加到某個(gè)指定的temporal對(duì)象
get 讀取該interval的狀態(tài)
isNegative 檢查該interval是否為負(fù)值,不包含零
isZero 檢查該interval的時(shí)長(zhǎng)是否為零
minus 通過(guò)減去一定的時(shí)間創(chuàng)建該interval的副本
multipliedBy 將interval的值乘以某個(gè)標(biāo)量創(chuàng)建該interval的副本
negated 以忽略某個(gè)時(shí)長(zhǎng)的方式創(chuàng)建該interval的副本
plus 以增加某個(gè)指定的時(shí)長(zhǎng)的方式創(chuàng)建該interval的副本
subtractFrom 從指定的temporal對(duì)象中減去該interval

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/66043.html

相關(guān)文章

  • 是,入坑小記

    摘要:種一顆樹(shù)最好的時(shí)機(jī)是十年前,其次是現(xiàn)在經(jīng)過(guò)一段刻骨的升本歷程,來(lái)到了西華大學(xué)。計(jì)劃是前進(jìn)的路線圖免除對(duì)于以后學(xué)習(xí)的各自夸大的計(jì)劃,從實(shí)際出發(fā)找到適合自己的前進(jìn)的路線圖。今年我歲,年輕。 種一顆樹(shù)最好的時(shí)機(jī)是十年前,其次是現(xiàn)在 經(jīng)過(guò)一段刻骨的升本歷程,來(lái)到了西華大學(xué)。明顯能感覺(jué)到自己又有了新的...

    CoXie 評(píng)論0 收藏0
  • Sublime text3學(xué)習(xí)小記(macOS系統(tǒng)下的安裝使用)

    摘要:等待其安裝完成后關(guān)閉程序,重新啟動(dòng),點(diǎn)開(kāi)菜單可見(jiàn)項(xiàng),說(shuō)明插件管理包已安裝成功。在出現(xiàn)的懸浮對(duì)話框中輸入然后點(diǎn)選下面的插件,就會(huì)自動(dòng)開(kāi)始安裝,請(qǐng)耐心等待?!咀ⅲ阂韵聝?nèi)容參考https://blog.csdn.net/stilling2006/article/details/54376743】 一、認(rèn)識(shí)Sublime text 1、一款跨平臺(tái)代碼編輯器,在Linux、OSX和Windows下均可...

    Paul_King 評(píng)論0 收藏0
  • Vue2學(xué)習(xí)小記-給Vue2路由導(dǎo)航鉤子和axios攔截器做個(gè)封裝

    摘要:寫在前面最近在學(xué)習(xí),遇到有些頁(yè)面請(qǐng)求數(shù)據(jù)需要用戶登錄權(quán)限服務(wù)器響應(yīng)不符預(yù)期的問(wèn)題,但是總不能每個(gè)頁(yè)面都做單獨(dú)處理吧,于是想到提供了攔截器這個(gè)好東西,再于是就出現(xiàn)了本文。 1.寫在前面 最近在學(xué)習(xí)Vue2,遇到有些頁(yè)面請(qǐng)求數(shù)據(jù)需要用戶登錄權(quán)限、服務(wù)器響應(yīng)不符預(yù)期的問(wèn)題,但是總不能每個(gè)頁(yè)面都做單獨(dú)處理吧,于是想到axios提供了攔截器這個(gè)好東西,再于是就出現(xiàn)了本文。 2.具體需求 用戶鑒...

    Tikitoo 評(píng)論0 收藏0
  • 騰訊云Codeigniter小記

    摘要:前段時(shí)間為了抓取網(wǎng)絡(luò)文本數(shù)據(jù),申請(qǐng)了騰訊云學(xué)生機(jī),用的框架弄了一段時(shí)間。這個(gè)用戶既是不可登錄的操作系統(tǒng)用戶,也是數(shù)據(jù)庫(kù)用戶。設(shè)置數(shù)據(jù)庫(kù)用戶密碼為了能夠讓和數(shù)據(jù)庫(kù)相連接,需要設(shè)置數(shù)據(jù)庫(kù)用戶密碼。 打讀研之后,更加關(guān)注算法的學(xué)習(xí),Web開(kāi)發(fā)這一塊便落下了,平時(shí)也通過(guò)微信公眾號(hào)關(guān)注了些,常常感慨,技術(shù)的更迭真是日新月異。 前段時(shí)間為了抓取網(wǎng)絡(luò)文本數(shù)據(jù),申請(qǐng)了騰訊云學(xué)生機(jī),用Python的Sc...

    Ocean 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<