Ordering是Guava類庫提供的一個犀利強大的比較器工具,Guava的Ordering和JDK Comparator相比功能更強。它非常容易擴展,可以輕松構造復雜的comparator,然后用在容器的比較、排序等操作中。
本質上來說,Ordering 實例無非就是一個特殊的Comparator 實例。Ordering只是需要依賴于一個比較器(例如,Collections.max)的方法,并使其可作為實例方法。另外,Ordering提供了鏈式方法調用和加強現有的比較器。
下面我們看看Ordering中的一些具體方法和簡單的使用實例。
常見的靜態方法:
natural():使用Comparable類型的自然順序, 例如:整數從小到大,字符串是按字典順序;
usingToString() :使用toString()返回的字符串按字典順序進行排序;
arbitrary() :返回一個所有對象的任意順序, 即compare(a, b) == 0 就是 a == b (identity equality)。 本身的排序是沒有任何含義, 但是在VM的生命周期是一個常量。
簡單實例:
import java.util.List; import org.junit.Test; import com.google.common.collect.Lists; import com.google.common.collect.Ordering; public class OrderingTest { @Test public void testStaticOrdering(){ List<String> list = Lists.newArrayList(); list.add("peida"); list.add("jerry"); list.add("harry"); list.add("eva"); list.add("jhon"); list.add("neron"); System.out.println("list:"+ list);
Ordering<String> naturalOrdering = Ordering.natural(); Ordering<Object> usingToStringOrdering = Ordering.usingToString(); Ordering<Object> arbitraryOrdering = Ordering.arbitrary(); System.out.println("naturalOrdering:"+ naturalOrdering.sortedCopy(list)); System.out.println("usingToStringOrdering:"+ usingToStringOrdering.sortedCopy(list)); System.out.println("arbitraryOrdering:"+ arbitraryOrdering.sortedCopy(list)); } }
輸出:
list:[peida, jerry, harry, eva, jhon, neron]
naturalOrdering:[eva, harry, jerry, jhon, neron, peida]
usingToStringOrdering:[eva, harry, jerry, jhon, neron, peida]
arbitraryOrdering:[neron, harry, eva, jerry, peida, jhon]
操作方法:
reverse(): 返回與當前Ordering相反的排序:
nullsFirst(): 返回一個將null放在non-null元素之前的Ordering,其他的和原始的Ordering一樣;
nullsLast():返回一個將null放在non-null元素之后的Ordering,其他的和原始的Ordering一樣;
compound(Comparator):返回一個使用Comparator的Ordering,Comparator作為第二排序元素,例如對bug列表進行排序,先根據bug的級別,再根據優先級進行排序;
lexicographical():返回一個按照字典元素迭代的Ordering;
onResultOf(Function):將function應用在各個元素上之后, 在使用原始ordering進行排序;
greatestOf(Iterable iterable, int k):返回指定的第k個可迭代的最大的元素,按照這個從最大到最小的順序。是不穩定的。
leastOf(Iterable<E> iterable,int k):返回指定的第k個可迭代的最小的元素,按照這個從最小到最大的順序。是不穩定的。
isOrdered(Iterable):是否有序,Iterable不能少于2個元素。
isStrictlyOrdered(Iterable):是否嚴格有序。請注意,Iterable不能少于兩個元素。
sortedCopy(Iterable):返回指定的元素作為一個列表的排序副本。
package com.peidasoft.guava.base; import java.util.List; import org.junit.Test; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.google.common.collect.Ordering; public class OrderingTest { @Test public void testOrdering(){ List<String> list = Lists.newArrayList(); list.add("peida"); list.add("jerry"); list.add("harry"); list.add("eva"); list.add("jhon"); list.add("neron"); System.out.println("list:"+ list); Ordering<String> naturalOrdering = Ordering.natural(); System.out.println("naturalOrdering:"+ naturalOrdering.sortedCopy(list)); List<Integer> listReduce= Lists.newArrayList(); for(int i=9;i>0;i--){ listReduce.add(i); } List<Integer> listtest= Lists.newArrayList(); listtest.add(1); listtest.add(1); listtest.add(1); listtest.add(2); Ordering<Integer> naturalIntReduceOrdering = Ordering.natural(); System.out.println("listtest:"+ listtest); System.out.println(naturalIntReduceOrdering.isOrdered(listtest)); System.out.println(naturalIntReduceOrdering.isStrictlyOrdered(listtest)); System.out.println("naturalIntReduceOrdering:"+ naturalIntReduceOrdering.sortedCopy(listReduce)); System.out.println("listReduce:"+ listReduce); System.out.println(naturalIntReduceOrdering.isOrdered(naturalIntReduceOrdering.sortedCopy(listReduce))); System.out.println(naturalIntReduceOrdering.isStrictlyOrdered(naturalIntReduceOrdering.sortedCopy(listReduce))); Ordering<String> natural = Ordering.natural(); List<String> abc = ImmutableList.of("a", "b", "c"); System.out.println(natural.isOrdered(abc)); System.out.println(natural.isStrictlyOrdered(abc)); System.out.println("isOrdered reverse :"+ natural.reverse().isOrdered(abc)); List<String> cba = ImmutableList.of("c", "b", "a"); System.out.println(natural.isOrdered(cba)); System.out.println(natural.isStrictlyOrdered(cba)); System.out.println(cba = natural.sortedCopy(cba)); System.out.println("max:"+natural.max(cba)); System.out.println("min:"+natural.min(cba)); System.out.println("leastOf:"+natural.leastOf(cba, 2)); System.out.println("naturalOrdering:"+ naturalOrdering.sortedCopy(list)); System.out.println("leastOf list:"+naturalOrdering.leastOf(list, 3)); System.out.println("greatestOf:"+naturalOrdering.greatestOf(list, 3)); System.out.println("reverse list :"+ naturalOrdering.reverse().sortedCopy(list)); System.out.println("isOrdered list :"+ naturalOrdering.isOrdered(list)); System.out.println("isOrdered list :"+ naturalOrdering.reverse().isOrdered(list)); list.add(null); System.out.println(" add null list:"+list); System.out.println("nullsFirst list :"+ naturalOrdering.nullsFirst().sortedCopy(list)); System.out.println("nullsLast list :"+ naturalOrdering.nullsLast().sortedCopy(list)); } } //============輸出============== list:[peida, jerry, harry, eva, jhon, neron] naturalOrdering:[eva, harry, jerry, jhon, neron, peida] listtest:[1, 1, 1, 2] true false naturalIntReduceOrdering:[1, 2, 3, 4, 5, 6, 7, 8, 9] listReduce:[9, 8, 7, 6, 5, 4, 3, 2, 1] true true true true isOrdered reverse :false false false [a, b, c] max:c min:a leastOf:[a, b] naturalOrdering:[eva, harry, jerry, jhon, neron, peida] leastOf list:[eva, harry, jerry] greatestOf:[peida, neron, jhon] reverse list :[peida, neron, jhon, jerry, harry, eva] isOrdered list :false isOrdered list :false add null list:[peida, jerry, harry, eva, jhon, neron, null] nullsFirst list :[null, eva, harry, jerry, jhon, neron, peida] nullsLast list :[eva, harry, jerry, jhon, neron, peida, null]
轉自:http://singo107.iteye.com/blog/1175084
數據庫事務的隔離級別有4個,由低到高依次為Read uncommitted 、Read committed 、Repeatable read 、Serializable ,這四個級別可以逐個解決臟讀 、不可重復讀 、幻讀 這幾類問題。
√: 可能出現 ×: 不會出現
臟讀 | 不可重復讀 | 幻讀 | |
Read uncommitted | √ | √ | √ |
Read committed | × | √ | √ |
Repeatable read | × | × | √ |
Serializable | × | × | × |
注意:我們討論隔離級別的場景,主要是在多個事務并發 的情況下,因此,接下來的講解都圍繞事務并發。
公司發工資了,領導把5000元打到singo的賬號上,但是該事務并未提交,而singo正好去查看賬戶,發現工資已經到賬,是5000元整,非常高 興。可是不幸的是,領導發現發給singo的工資金額不對,是2000元,于是迅速回滾了事務,修改金額后,將事務提交,最后singo實際的工資只有 2000元,singo空歡喜一場。
出現上述情況,即我們所說的臟讀 ,兩個并發的事務,“事務A:領導給singo發工資”、“事務B:singo查詢工資賬戶”,事務B讀取了事務A尚未提交的數據。
當隔離級別設置為Read uncommitted 時,就可能出現臟讀,如何避免臟讀,請看下一個隔離級別。
singo拿著工資卡去消費,系統讀取到卡里確實有2000元,而此時她的老婆也正好在網上轉賬,把singo工資卡的2000元轉到另一賬戶,并在 singo之前提交了事務,當singo扣款時,系統檢查到singo的工資卡已經沒有錢,扣款失敗,singo十分納悶,明明卡里有錢,為 何......
出現上述情況,即我們所說的不可重復讀 ,兩個并發的事務,“事務A:singo消費”、“事務B:singo的老婆網上轉賬”,事務A事先讀取了數據,事務B緊接了更新了數據,并提交了事務,而事務A再次讀取該數據時,數據已經發生了改變。
當隔離級別設置為Read committed 時,避免了臟讀,但是可能會造成不可重復讀。
大多數數據庫的默認級別就是Read committed,比如Sql Server , Oracle。如何解決不可重復讀這一問題,請看下一個隔離級別。
當隔離級別設置為Repeatable read 時,可以避免不可重復讀。當singo拿著工資卡去消費時,一旦系統開始讀取工資卡信息(即事務開始),singo的老婆就不可能對該記錄進行修改,也就是singo的老婆不能在此時轉賬。
雖然Repeatable read避免了不可重復讀,但還有可能出現幻讀 。
singo的老婆工作在銀行部門,她時常通過銀行內部系統查看singo的信用卡消費記錄。有一天,她正在查詢到singo當月信用卡的總消費金額 (select sum(amount) from transaction where month = 本月)為80元,而singo此時正好在外面胡吃海塞后在收銀臺買單,消費1000元,即新增了一條1000元的消費記錄(insert transaction ... ),并提交了事務,隨后singo的老婆將singo當月信用卡消費的明細打印到A4紙上,卻發現消費總額為1080元,singo的老婆很詫異,以為出 現了幻覺,幻讀就這樣產生了。
注:Mysql的默認隔離級別就是Repeatable read。
Serializable 是最高的事務隔離級別,同時代價也花費最高,性能很低,一般很少使用,在該級別下,事務順序執行,不僅可以避免臟讀、不可重復讀,還避免了幻像讀。
Google是一個非常優秀的公司。他們做出了很多令人稱贊的東西—既是公司外部,人們可以看到的東西,也是公司內部。有一些在公司內部并不屬于保密的事情,在外部并沒有給予足夠廣泛的討論。這就是我今天要說的。
讓Google的程序如此優秀的一個最重要的事情看起來是非常的簡單:代碼審查。并不是只有Google做這個事情—代碼審查已經被廣泛的認可為一種非常好的做法,很多人都在這樣做。但我還沒有看到第二家這樣大的公司能把這種事情運用的如此普遍。在Google,沒有程序,任何產品、任何項目的程序代碼,可以在沒有經過有效的代碼審查前提交到代碼庫里的。
所有人都要經過代碼審查。并且很正規的:這種事情應該成為任何重要的軟件開發工作中一個基本制度。并不單指產品程序——所有東西。它不需要很多的工作,但它的效果是巨大的。
從代碼審查里能得到什么?
很顯然:在代碼提交前,用第二群眼睛檢查一遍,防止bug混入。這是對其最常見的理解,是對代碼審查的好處的最廣泛的認識。但是,依我的經驗來看,這反倒是它最不重要的一點。人們確實在代碼審查中找到了bug。可是,這些在代碼審查中能發現的絕大部分bug,很顯然,都是微不足道的bug,程序的作者花幾分鐘的時間就能發現它們。真正需要花時間去發現的bug不是在代碼審查里能找到的。
代碼審查的最大的功用是純社會性的。如果你在編程,而且知道將會有同事檢查你的代碼,你編程態度就完全不一樣了。你寫出的代碼將更加整潔,有更好的注釋,更好的程序結構——因為你知道,那個你很在意的人將會查看你的程序。沒有代碼審查,你知道人們最終還是會看你的程序。但這種事情不是立即發生的事,它不會給你帶來同等的緊迫感,它不會給你相同的個人評判的那種感受。
還有一個非常重要的好處。代碼審查能傳播知識。在很多的開發團隊里,經常每一個人負責一個核心模塊,每個人都只關注他自己的那個模塊。除非是同事的模塊影響了自己的程序,他們從不相互交流。這種情況的后果是,每個模塊只有一個人熟悉里面的代碼。如果這個人休假或——但愿不是——辭職了,其他人則束手無策。通過代碼審查,至少會有兩個人熟悉這些程序——作者,以及審查者。審查者并不能像程序的作者一樣對程序十分了解——但他會熟悉程序的設計和架構,這是極其重要的。
當然,沒有什么事情能簡單的做下來的。依我的經驗,在你能正確的進行代碼審查前,你需要花時間鍛煉學習。我發現人們在代碼審查時經常會犯一些錯誤,導致不少麻煩——尤其在一些缺乏經驗的審查者中經常的出現,他們給了人們一個很遭的代碼審查的體驗,成為了人們接受代碼審查制度的一個障礙。
最重要的一個原則:代碼審查用意是在代碼提交前找到其中的問題——你要發現是它的正確。在代碼審查中最常犯的錯誤——幾乎每個新手都會犯的錯誤——是,審查者根據自己的編程習慣來評判別人的代碼。
對于一個問題,通常我們能找出十幾種方法去解決。對于一種解決方案,我們能有百萬種編碼方案來實現它。作為一個審查者,你的任務不是來確保被審查的代碼都采用的是你的編碼風格——因為它不可能跟你寫的一樣。作為一段代碼的審查者的任務是確保由作者自己寫出的代碼是正確的。一旦這個原則被打破,你最終將會倍感折磨,深受挫折——這可不是我們想要的結果。
問題在于,這種錯誤是如此的普遍而易犯。如果你是個程序員,當你遇到一個問題,你能想到一種解決方案——你就把你想到的方案作為標準答案。但事情不是這樣的——作為一個好的審查者,你需要明白這個道理。
代碼審查的第二個易犯的毛病是,人們覺得有壓力,感覺非要說點什么才好。你知道作者用了大量的時間和精力來實現這些程序——不該說點什么嗎?
不,你不需要。
只說一句“哇,不錯呀”,任何時候都不會不合適。如果你總是力圖找出一點什么東西來批評,你這樣做的結果只會損害自己的威望。當你不厭其煩的找出一些東西來,只是為了說些什么,被審查人就會知道,你說這些話只是為了填補寂靜。你的評論將不再被人重視。
第三是速度。你不能匆匆忙忙的進行一次代碼審查——但你也要能迅速的完成。你的同伴在等你。如果你和你的同事并不想花太多時間進行代碼復查,你們很快的完成,那被審查者會覺得很沮喪,這種代碼審查帶來的只有失望的感覺。就好象是打攪了大家,使大家放下手頭的工作來進行審查。事情不該是這樣。你并不需要推掉手頭上的任何事情來做代碼審查。但如果中途耽誤了幾個小時,你中間還要休息一會,喝杯茶,沖個澡,或談會兒閑話。當你回到審查現場,你可以繼續下去,把事情做完。如果你真是這樣,我想沒有人愿意在那干等著你。