生活随笔
收集整理的這篇文章主要介紹了
[Google Guava] 8-区间
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
原文鏈接?譯文鏈接?譯文:沈義揚(yáng)
范例
| 2 | Iterable belowMedian =Iterables.filter(scores,Range.lessThan(median)); |
| 4 | Range validGrades = Range.closed(1,?12); |
| 5 | for(int?grade : ContiguousSet.create(validGrades, DiscreteDomain.integers())) { |
簡(jiǎn)介
區(qū)間,有時(shí)也稱為范圍,是特定域中的凸性(非正式說法為連續(xù)的或不中斷的)部分。在形式上,凸性表示對(duì)a<=b<=c, range.contains(a)且range.contains(c)意味著range.contains(b)。
區(qū)間可以延伸至無(wú)限——例如,范圍”x>3″包括任意大于3的值——也可以被限制為有限,如” 2<=x<5″。Guava用更緊湊的方法表示范圍,有數(shù)學(xué)背景的程序員對(duì)此是耳熟能詳?shù)?#xff1a;
- (a..b) = {x | a < x < b}
- [a..b] = {x | a <= x <= b}
- [a..b) = {x | a <= x < b}
- (a..b] = {x | a < x <= b}
- (a..+∞) = {x | x > a}
- [a..+∞) = {x | x >= a}
- (-∞..b) = {x | x < b}
- (-∞..b] = {x | x <= b}
- (-∞..+∞) = 所有值
上面的a、b稱為端點(diǎn) 。為了提高一致性,Guava中的Range要求上端點(diǎn)不能小于下端點(diǎn)。上下端點(diǎn)有可能是相等的,但要求區(qū)間是閉區(qū)間或半開半閉區(qū)間(至少有一個(gè)端點(diǎn)是包含在區(qū)間中的):
- [a..a]:單元素區(qū)間
- [a..a); (a..a]:空區(qū)間,但它們是有效的
- (a..a):無(wú)效區(qū)間
Guava用類型Range<C>表示區(qū)間。所有區(qū)間實(shí)現(xiàn)都是不可變類型。
構(gòu)建區(qū)間
區(qū)間實(shí)例可以由Range類的靜態(tài)方法獲取:
| (a..b) | open(C, C) |
| [a..b] | closed(C, C) |
| [a..b) | closedOpen(C, C) |
| (a..b] | openClosed(C, C) |
| (a..+∞) | greaterThan(C) |
| [a..+∞) | atLeast(C) |
| (-∞..b) | lessThan(C) |
| (-∞..b] | atMost(C) |
| (-∞..+∞) | all() |
| 1 | Range.closed("left",?"right");?//字典序在"left"和"right"之間的字符串,閉區(qū)間 |
| 2 | Range.lessThan(4.0);?//嚴(yán)格小于4.0的double值 |
此外,也可以明確地指定邊界類型來構(gòu)造區(qū)間:
| 有界區(qū)間 | range(C, BoundType, C, ? BoundType) |
| 無(wú)上界區(qū)間:((a..+∞) 或[a..+∞)) | downTo(C, BoundType) |
| 無(wú)下界區(qū)間:((-∞..b) 或(-∞..b]) | upTo(C, BoundType) |
這里的BoundType是一個(gè)枚舉類型,包含CLOSED和OPEN兩個(gè)值。
| 1 | Range.downTo(4, boundType);// (a..+∞)或[a..+∞),取決于boundType |
| 2 | Range.range(1, CLOSED,?4, OPEN);// [1..4),等同于Range.closedOpen(1, 4) |
區(qū)間運(yùn)算
Range的基本運(yùn)算是它的contains(C)?方法,和你期望的一樣,它用來區(qū)間判斷是否包含某個(gè)值。此外,Range實(shí)例也可以當(dāng)作Predicate,并且在函數(shù)式編程中使用(譯者注:見第4章)。任何Range實(shí)例也都支持containsAll(Iterable<? extends C>)方法:
| 1 | Range.closed(1,?3).contains(2);//return true |
| 2 | Range.closed(1,?3).contains(4);//return false |
| 3 | Range.lessThan(5).contains(5);?//return false |
| 4 | Range.closed(1,?4).containsAll(Ints.asList(1,?2,?3));?//return true |
查詢運(yùn)算
Range類提供了以下方法來 查看區(qū)間的端點(diǎn):
- hasLowerBound()和hasUpperBound():判斷區(qū)間是否有特定邊界,或是無(wú)限的;
- lowerBoundType()和upperBoundType():返回區(qū)間邊界類型,CLOSED或OPEN;如果區(qū)間沒有對(duì)應(yīng)的邊界,拋出IllegalStateException;
- lowerEndpoint()和upperEndpoint():返回區(qū)間的端點(diǎn)值;如果區(qū)間沒有對(duì)應(yīng)的邊界,拋出IllegalStateException;
- isEmpty():判斷是否為空區(qū)間。
| 1 | Range.closedOpen(4,?4).isEmpty();?// returns true |
| 2 | Range.openClosed(4,?4).isEmpty();?// returns true |
| 3 | Range.closed(4,?4).isEmpty();?// returns false |
| 4 | Range.open(4,?4).isEmpty();?// Range.open throws IllegalArgumentException |
| 5 | Range.closed(3,?10).lowerEndpoint();?// returns 3 |
| 6 | Range.open(3,?10).lowerEndpoint();?// returns 3 |
| 7 | Range.closed(3,?10).lowerBoundType();?// returns CLOSED |
| 8 | Range.open(3,?10).upperBoundType();?// returns OPEN |
關(guān)系運(yùn)算
包含[enclose]
區(qū)間之間的最基本關(guān)系就是包含[encloses(Range)]:如果內(nèi)區(qū)間的邊界沒有超出外區(qū)間的邊界,則外區(qū)間包含內(nèi)區(qū)間。包含判斷的結(jié)果完全取決于區(qū)間端點(diǎn)的比較!
- [3..6] 包含[4..5] ;
- (3..6) 包含(3..6) ;
- [3..6] 包含[4..4),雖然后者是空區(qū)間;
- (3..6]不 包含[3..6] ;
- [4..5]不 包含(3..6),雖然前者包含了后者的所有值,離散域[discrete domains]可以解決這個(gè)問題(見8.5節(jié));
- [3..6]不 包含(1..1],雖然前者包含了后者的所有值。
包含是一種偏序關(guān)系[partial ordering]。基于包含關(guān)系的概念,Range還提供了以下運(yùn)算方法。
相連[isConnected]
Range.isConnected(Range)判斷區(qū)間是否是相連的。具體來說,isConnected測(cè)試是否有區(qū)間同時(shí)包含于這兩個(gè)區(qū)間,這等同于數(shù)學(xué)上的定義”兩個(gè)區(qū)間的并集是連續(xù)集合的形式”(空區(qū)間的特殊情況除外)。
相連是一種自反的[reflexive]、對(duì)稱的[symmetric]關(guān)系。
| 1 | Range.closed(3,?5).isConnected(Range.open(5,?10));?// returns true |
| 2 | Range.closed(0,?9).isConnected(Range.closed(3,?4));?// returns true |
| 3 | Range.closed(0,?5).isConnected(Range.closed(3,?9));?// returns true |
| 4 | Range.open(3,?5).isConnected(Range.open(5,?10));?// returns false |
| 5 | Range.closed(1,?5).isConnected(Range.closed(6,?10));?// returns false |
交集[intersection]
Range.intersection(Range)返回兩個(gè)區(qū)間的交集:既包含于第一個(gè)區(qū)間,又包含于另一個(gè)區(qū)間的最大區(qū)間。當(dāng)且僅當(dāng)兩個(gè)區(qū)間是相連的,它們才有交集。如果兩個(gè)區(qū)間沒有交集,該方法將拋出IllegalArgumentException。
交集是可互換的[commutative] 、關(guān)聯(lián)的[associative] 運(yùn)算[operation]。
| 1 | Range.closed(3,?5).intersection(Range.open(5,?10));?// returns (5, 5] |
| 2 | Range.closed(0,?9).intersection(Range.closed(3,?4));?// returns [3, 4] |
| 3 | Range.closed(0,?5).intersection(Range.closed(3,?9));?// returns [3, 5] |
| 4 | Range.open(3,?5).intersection(Range.open(5,?10));?// throws IAE |
| 5 | Range.closed(1,?5).intersection(Range.closed(6,?10));?// throws IAE |
跨區(qū)間[span]
Range.span(Range)返回”同時(shí)包括兩個(gè)區(qū)間的最小區(qū)間”,如果兩個(gè)區(qū)間相連,那就是它們的并集。
span是可互換的[commutative] 、關(guān)聯(lián)的[associative] 、閉合的[closed]運(yùn)算[operation]。
| 1 | Range.closed(3,?5).span(Range.open(5,?10));?// returns [3, 10) |
| 2 | Range.closed(0,?9).span(Range.closed(3,?4));?// returns [0, 9] |
| 3 | Range.closed(0,?5).span(Range.closed(3,?9));?// returns [0, 9] |
| 4 | Range.open(3,?5).span(Range.open(5,?10));?// returns (3, 10) |
| 5 | Range.closed(1,?5).span(Range.closed(6,?10));?// returns [1, 10] |
離散域
部分(但不是全部)可比較類型是離散的,即區(qū)間的上下邊界都是可枚舉的。
在Guava中,用DiscreteDomain<C>實(shí)現(xiàn)類型C的離散形式操作。一個(gè)離散域總是代表某種類型值的全集;它不能代表類似”素?cái)?shù)”、”長(zhǎng)度為5的字符串”或”午夜的時(shí)間戳”這樣的局部域。
DiscreteDomain提供的離散域?qū)嵗?#xff1a;
| 類型 | 離散域 |
| Integer | integers() |
| Long | longs() |
一旦獲取了DiscreteDomain實(shí)例,你就可以使用下面的Range運(yùn)算方法:
- ContiguousSet.create(range, domain):用ImmutableSortedSet<C>形式表示Range<C>中符合離散域定義的元素,并增加一些額外操作——譯者注:實(shí)際返回ImmutableSortedSet的子類ContiguousSet。(對(duì)無(wú)限區(qū)間不起作用,除非類型C本身是有限的,比如int就是可枚舉的)
- canonical(domain):把離散域轉(zhuǎn)為區(qū)間的”規(guī)范形式”。如果ContiguousSet.create(a, domain).equals(ContiguousSet.create(b, domain))并且!a.isEmpty(),則有a.canonical(domain).equals(b.canonical(domain))。(這并不意味著a.equals(b))
| 1 | ImmutableSortedSet set = ContigousSet.create(Range.open(1,?5), iscreteDomain.integers()); |
| 3 | ContiguousSet.create(Range.greaterThan(0), DiscreteDomain.integers()); |
| 4 | //set包含[1, 2, ..., Integer.MAX_VALUE] |
注意,ContiguousSet.create并沒有真的構(gòu)造了整個(gè)集合,而是返回了set形式的區(qū)間視圖。
你自己的離散域
你可以創(chuàng)建自己的離散域,但必須記住DiscreteDomain契約的幾個(gè)重要方面。
- 一個(gè)離散域總是代表某種類型值的全集;它不能代表類似”素?cái)?shù)”或”長(zhǎng)度為5的字符串”這樣的局部域。所以舉例來說,你無(wú)法構(gòu)造一個(gè)DiscreteDomain以表示精確到秒的JODA DateTime日期集合:因?yàn)槟菍o(wú)法包含JODA DateTime的所有值。
- DiscreteDomain可能是無(wú)限的——比如BigInteger DiscreteDomain。這種情況下,你應(yīng)當(dāng)用minValue()和maxValue()的默認(rèn)實(shí)現(xiàn),它們會(huì)拋出NoSuchElementException。但Guava禁止把無(wú)限區(qū)間傳入ContiguousSet.create——譯者注:那明顯得不到一個(gè)可枚舉的集合。
如果我需要一個(gè)Comparator呢?
我們想要在Range的可用性與API復(fù)雜性之間找到特定的平衡,這部分導(dǎo)致了我們沒有提供基于Comparator的接口:我們不需要操心區(qū)間是怎樣基于不同Comparator互動(dòng)的;所有API簽名都是簡(jiǎn)單明確的;這樣更好。
另一方面,如果你需要任意Comparator,可以按下列其中一項(xiàng)來做:
- 使用通用的Predicate接口,而不是Range類。(Range實(shí)現(xiàn)了Predicate接口,因此可以用Predicates.compose(range, function)獲取Predicate實(shí)例)
- 使用包裝類以定義期望的排序。
譯者注:實(shí)際上Range規(guī)定元素類型必須是Comparable,這已經(jīng)滿足了大多數(shù)需求。如果需要自定義特殊的比較邏輯,可以用Predicates.compose(range, function)組合比較的function。
原創(chuàng)文章,轉(zhuǎn)載請(qǐng)注明:?轉(zhuǎn)載自并發(fā)編程網(wǎng) – ifeve.com本文鏈接地址:?[Google Guava] 8-區(qū)間
from:?http://ifeve.com/google-guava-ranges/?
總結(jié)
以上是生活随笔為你收集整理的[Google Guava] 8-区间的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。