google guava 入門教程
Guava(瓜娃)學習筆記 (程式碼下載地址)
Guava工程包含了若干被google的java專案廣泛依賴的核心庫,例如:集合 [collections] 、快取 [caching] 、原生型別支援 [primitives support] 、併發庫 [concurrency libraries] 、通用註解 [commonannotations] 、字串處理 [string processing] 、I/O 等等。所有這些工具每天都在被Google的工程師應用在產品服務中。
這些高質量的API可以使你的java程式碼更加優雅,更加簡潔,讓你的工作更加輕鬆愉悅,下面我們來開啟Java程式設計學習之旅。
原始碼包的簡單說明:
com.google.common.annotations:普通註解型別。
com.google.common.base:基本工具類庫和介面。
com.google.common.cache:快取工具包,非常簡單易用且功能強大的JVM內快取。
com.google.common.collect:帶泛型的集合介面擴充套件和實現,以及工具類,這裡你會發現很多好玩的集合。
com.google.common.eventbus:釋出訂閱風格的事件匯流排。
com.google.common.hash: 雜湊工具包。
com.google.common.io:I/O工具包。
com.google.common.math:原始算術型別和超大數的運算工具包。
com.google.common.net:網路工具包。
com.google.common.primitives:八種原始型別和無符號型別的靜態工具包。
com.google.common.reflect:反射工具包。
com.google.common.util.concurrent:多執行緒工具包。
1. 基本工具(Basic utilities)
1) 使用和避免null(Optional)
null會引起歧義,會造成讓人迷惑的錯誤,有時也會讓人感到不爽。Guava中的許多工具遇到null時,會拒絕或者馬上報錯,而不是盲目的接受。
鑑於此google的guava庫中提供了Optional介面來使null快速失敗,即在可能為null的物件上做了一層封裝,在使用Optional靜態方法of時,如果傳入的引數為null就丟擲NullPointerException異常。
在Guava中Optional類就是用來強制提醒程式設計師,注意對Null的判斷。
Optional的另外幾個方法
Optional<T>.of(T) 為Optional賦值,當T為Null直接拋NullPointException,建議這個方法在呼叫的時候直接傳常量,不要傳變數
Optional<T>.fromNullable(T) 為Optional賦值,當T為Null則使用預設值。建議與or方法一起用,風騷無比
Optional<T>.absent() 為Optional賦值,採用預設值
T or(T) 當Optional的值為null時,使用or賦予的值返回。與fromNullable是一對好基友
T get() 當Optional的值為null時,丟擲IllegalStateException,返回Optional的值
boolean isPresent() 如果Optional存在值,則返回True
T orNull() 當Optional的值為null時,則返回Null。否則返回Optional的值
Set<T> asSet() 將Optional中的值轉為一個Set返回,當然只有一個值啦,或者為空,當值為null時。
使用Optional的意義?
使用Optional除了賦予null語義,增加了可讀性,最大的優點在於它一種傻瓜式的防護,Optional迫使你積極思考引用缺失的情況,因為你必須顯式地從Optional獲取引用。直接使用null很容易讓人忘掉某些情形,儘管FindBugs可以幫助查詢null相關的問題,但是我們還是認為它並不能準確地定位問題根源。
2) 前提條件(Preconditions)
使方法的條件檢查更簡單。
Guava在Preconditions類中提供了若干前置條件判斷的實用方法,我們強烈建議在Eclipse中靜態匯入這些方法。每個方法都有三個變種:
a) 沒有額外引數:丟擲的異常中沒有錯誤訊息;
b) 有一個Object物件作為額外引數:丟擲的異常使用Object.toString() 作為錯誤訊息;
c) 有一個String物件作為額外引數,並且有一組任意數量的附加Object物件:這個變種處理異常訊息的方式有點類似printf,但考慮GWT的相容性和效率,只支援%s指示符。
例如:檢視原始碼列印幫助
checkArgument(i>= 0, “Argument was %s but expected nonnegative”, i);
checkArgument(i< j, “Expected i < j, but %s > %s”, i, j);
方法宣告(不包括額外引數) |
描述 |
檢查失敗時丟擲的異常 |
checkArgument(boolean) |
檢查boolean是否為true,用來檢查傳遞給方法的引數。 |
IllegalArgumentException |
檢查value是否為null,該方法直接返回value,因此可以內嵌使用checkNotNull。 |
NullPointerException |
|
用來檢查物件的某些狀態。 |
IllegalStateException |
|
檢查index作為索引值對某個列表、字串或陣列是否有效。index>=0 && index<size * |
IndexOutOfBoundsException |
|
檢查index作為位置值對某個列表、字串或陣列是否有效。index>=0 && index<=size * |
IndexOutOfBoundsException |
|
checkPositionIndexes(int start, int end, int size) |
檢查[start, end]表示的位置範圍對某個列表、字串或陣列是否有效* |
IndexOutOfBoundsException |
3) 常見的物件方法(Objects)
簡化Object方法實現,如hashCode()和toString();
a) equals
當一個物件中的欄位可以為null時,實現Object.equals方法會很痛苦,因為不得不分別對它們進行null檢查。使用Objects.equal幫助你執行null敏感的equals判斷,從而避免丟擲NullPointerException。
b) hashCode
用物件的所有欄位作雜湊[hash]運算應當更簡單。Guava的Objects.hashCode(Object…)會對傳入的欄位序列計算出合理的、順序敏感的雜湊值。你可以使用Objects.hashCode(field1, field2, …, fieldn)來代替手動計算雜湊值。
c) toString
好的toString方法在除錯時是無價之寶,但是編寫toString方法有時候卻很痛苦。使用 Objects.toStringHelper可以輕鬆編寫有用的toString方法。
4) 排序
Guava強大的”流暢風格比較器”,具體到下章會介紹到。
5) Throwable類
簡化了異常和錯誤的傳播與檢查;
guava類庫中的Throwables提供了一些異常處理的靜態方法,這些方法的從功能上分為兩類,一類是幫你丟擲異常,另外一類是幫你處理異常。
RuntimeException propagate(Throwable) |
如果Throwable是Error或RuntimeException,直接丟擲;否則把Throwable包裝成RuntimeException丟擲。返回型別是RuntimeException,所以你可以像上面說的那樣寫成throw Throwables.propagate(t),Java編譯器會意識到這行程式碼保證丟擲異常。 |
void propagateIfInstanceOf( Throwable, Class<X extends Exception>) throws X |
Throwable型別為X才丟擲 |
void propagateIfPossible( Throwable) |
Throwable型別為Error或RuntimeException才丟擲 |
void propagateIfPossible( Throwable, Class<X extends Throwable>) throws X |
Throwable型別為X, Error或RuntimeException才丟擲 |
2. 集合(Collections)
介紹guava對jdk集合類的擴充套件,包括不可變集合,新集合型別: multisets, multimaps, tables, bidirectional maps等,強大的集合工具類: 提供java.util.Collections中沒有的集合工具,擴充套件工具類:讓實現和擴充套件集合類變得更容易,比如建立Collection的裝飾器,或實現迭代器
集合API的使用, 可以簡化集合的建立和初始化;
guava API 提供了有用的新的集合型別,協同已經存在的java集合工作的很好。
分別是 MultiMap, MultiSet, Table, BiMap,ClassToInstanceMap
1) google guava的不可變集合
不可變物件有很多優點:
a) 當物件被不可信的庫呼叫時,不可變形式是安全的。
b) 當不可變物件被對個執行緒呼叫時,不存在競態條件問題;
c) 不可變集合不需要考慮變化,因此可以節約時間和空間,所有不可變集合都比可變集合形式有更好的記憶體利用率(分析和測試細節);
d) 不可變物件因為有固定不變,可以用作常量來安全使用。
總結:資料不可變;不需要同步邏輯;執行緒安全;自由共享;容易設計和實現;記憶體和時間高效
建立物件的不可拷貝是一項很好的防禦性程式設計技巧,Guava為所有JDK標準集合型別和Guava新集合型別都提供了簡單易用的不可變版本。
JDK也提供了可以將集合變成不可變的方法,Collections.unmodifiableXXX,但是被認為是不好的。
a) 笨重而且累贅:不能舒適地用在所有想做防禦性拷貝的場景;
b) 不安全:要保證沒人通過原集合的引用進行修改,返回的集合才是事實上不可變的;
c) 低效:包裝過的集合仍然保有可變集合的開銷,比如併發修改的檢查、散列表的額外空間,等等。
提示:guava不可變集合的實現都不接受null值,經過對google內部程式碼的研究發現,google內部只有不超過5%的情況下集合中允許了null值,其他情況下都不允許。如果我們相用null的不可變集合,那我們就用jdk中的集合類進行操作,然後進行集合工具類的處理Collections.unmodifiableXXX。
細節:關聯可變集合和不可變集合
可變集合介面 |
屬於jdk還是guava |
不可變版本 |
Collection |
JDK |
ImmutableCollection |
List |
JDK |
ImmutableList |
Set |
JDK |
ImmutableSet |
SortedSet/NavigableSet |
JDK |
ImmutableSortedSet |
Map |
JDK |
ImmutableMap |
SortedMultiset |
Guava |
ImmutableSortedMultiset |
Multimap |
Guava |
ImmutableMultimap |
ListMultimap |
Guava |
ImmutableListMultimap |
SetMultimap |
Guava |
ImmutableSetMultimap |
BiMap |
Guava |
ImmutableBiMap |
ClassToInstanceMap |
Guava |
ImmutableClassToInstanceMap |
Table |
Guava |
ImmutableTable |
2) google guava集合之Multiset
Multiset看似是一個Set,但是實質上它不是一個Set,它沒有繼承Set介面,它繼承的是Collection<E>介面,你可以向Multiset中新增重複的元素,Multiset會對新增的元素做一個計數。
它本質上是一個Set加一個元素計數器。
顯然計數不是問題,Multiset還提供了add和remove的過載方法,可以在add或這remove的同時指定計數的值。
常用實現 Multiset 介面的類有:
HashMultiset: 元素存放於 HashMap
LinkedHashMultiset:元素存放於 LinkedHashMap,即元素的排列順序由第一次放入的順序決定
TreeMultiset:元素被排序存放於TreeMap
EnumMultiset: 元素必須是 enum 型別
ImmutableMultiset:不可修改的 Mutiset
看到這裡你可能已經發現 GuavaCollections 都是以 create 或是 of 這樣的靜態方法來構造物件。這是因為這些集合類大多有多個引數的私有構造方法,由於引數數目很多,客戶程式碼程式設計師使用起來就很不方便。而且以這種方式可以返回原型別的子型別物件。另外,對於建立範型物件來講,這種方式更加簡潔。
3) google guava的BiMap:雙向Map
我們知道Map是一種鍵值對對映,這個對映是鍵到值的對映,而BiMap首先也是一種Map,他的特別之處在於,既提供鍵到值的對映,也提供值到鍵的對映,所以它是雙向Map.
BiMap的常用實現有:
HashBiMap: key 集合與 value 集合都有 HashMap 實現
EnumBiMap: key 與 value 都必須是 enum 型別
ImmutableBiMap: 不可修改的 BiMap
4) google guava的Multimaps:一鍵多值的Map
有時候我們需要這樣的資料型別Map<String,Collection<String>>,guava中的Multimap就是為了解決這類問題的。
Multimap提供了豐富的實現,所以你可以用它來替代程式裡的Map<K, Collection<V>>,具體的實現如下:
實現 |
Key實現 |
Value實現 |
ArrayListMultimap |
HashMap |
ArrayList |
HashMultimap |
HashMap |
HashSet |
LinkedListMultimap |
LinkedHashMap |
LinkedList |
LinkedHashMultimap |
LinkedHashMap |
LinkedHashSet |
TreeMultimap |
TreeMap |
TreeSet |
ImmutableListMultimap |
ImmutableMap |
ImmutableList |
ImmutableSetMultimap |
ImmutableMap |
ImmutableSet |
5) google guava集合之Table
在guava庫中還提供了一種二維表結構:Table。使用Table可以實現二維矩陣的資料結構,可以是稀溜矩陣。
通常來說,當你想使用多個鍵做索引的時候,你可能會用類似Map<FirstName, Map<LastName, Person>>的實現,這種方式很醜陋,使用上也不友好。Guava為此提供了新集合型別Table,它有兩個支援所有型別的鍵:”行”和”列”。Table提供多種檢視,以便你從各種角度使用它:
rowMap():用Map<R, Map<C, V>>表現Table<R, C,V>。同樣的, rowKeySet()返回”行”的集合Set<R>。
row(r) :用Map<C, V>返回給定”行”的所有列,對這個map進行的寫操作也將寫入Table中。
類似的列訪問方法:columnMap()、columnKeySet()、column(c)。(基於列的訪問會比基於的行訪問稍微低效點)
cellSet():用元素型別為Table.Cell<R, C, V>的Set表現Table<R,C, V>。Cell類似於Map.Entry,但它是用行和列兩個鍵區分的。
6) Guava集合:使用Iterators簡化Iterator操作
Iterators是Guava中對Iterator迭代器操作的幫助類,這個類提供了很多有用的方法來簡化Iterator的操作。
7) ClassToInstanceMap可以實現map的key值是多個型別
有的時候,你的map的key並不是一種型別,他們是很多型別,你想通過對映他們得到這種型別,guava提供了ClassToInstanceMap滿足了這個目的。
除了繼承自Map介面,ClassToInstaceMap提供了方法 TgetInstance(Class<T>) 和 T putInstance(Class<T>, T),消除了強制型別轉換。
8) Ordering犀利的比較器
Ordering是Guava類庫提供的一個犀利強大的比較器工具,Guava的Ordering和JDK Comparator相比功能更強。它非常容易擴充套件,可以輕鬆構造複雜的comparator,然後用在容器的比較、排序等操作中。
本質上來說,Ordering例項無非就是一個特殊的Comparator 例項。Ordering只是需要依賴於一個比較器(例如,Collections.max)的方法,並使其可作為例項方法。另外,Ordering提供了鏈式方法呼叫和加強現有的比較器。
常見的靜態方法:
natural():使用Comparable型別的自然順序,例如:整數從小到大,字串是按字典順序;
usingToString() :使用toString()返回的字串按字典順序進行排序;
arbitrary() :返回一個所有物件的任意順序,即compare(a, b) == 0 就是 a == b (identity equality)。 本身的排序是沒有任何含義, 但是在VM的生命週期是一個常量。
9) ComparisonChain比較
實現一個比較器[Comparator],或者直接實現Comparable介面有時也傷不起。考慮一下這種情況:
class Studentimplements Comparable<Student>{
private String lastName;
private String firstName;
private int zipCode;
//jdk
public int compareTo(Student other) {
int cmp =lastName.compareTo(other.lastName);
if (cmp != 0) {
return cmp;
}
cmp = firstName.compareTo(other.firstName);
if (cmp != 0) {
return cmp;
}
return Integer.compare(zipCode, other.zipCode);
}
}
這部分程式碼太瑣碎了,因此很容易搞亂,也很難除錯。我們應該能把這種程式碼變得更優雅,為此,Guava提供了ComparisonChain。
ComparisonChain執行一種懶比較:它執行比較操作直至發現非零的結果,在那之後的比較輸入將被忽略。
//guava比較優雅
public int compareTo(Student other) {
returnComparisonChain.start()
.compare(this.lastName,other.lastName)
.compare(this.firstName,other.firstName)
.compare(this.zipCode,other.zipCode, Ordering.natural().nullsLast())
.result();
}
這種Fluent介面風格的可讀性更高,發生錯誤編碼的機率更小,並且能避免做不必要的工作。
3. 快取(Caches)
google guava框架提供了記憶體快取的功能,可以很方便的快取物件,設定生命週期, 及快取物件的弱引用強應用 軟引用等
google guava中有cache包,此包提供記憶體快取功能。記憶體快取需要考慮很多問題,包括併發問題,快取失效機制,記憶體不夠用時快取釋放,快取的命中率,快取的移除等等。當然這些東西guava都考慮到了。
guava的記憶體快取非常強大,可以設定各種選項,而且很輕量,使用方便。另外還提供了下面一些方法,來方便各種需要:
ImmutableMap<K, V> getAllPresent(Iterable<?> keys) 一次獲得多個鍵的快取值
put和putAll方法向快取中新增一個或者多個快取項
invalidate 和 invalidateAll方法從快取中移除快取項
asMap()方法獲得快取資料的ConcurrentMap<K, V>快照
cleanUp()清空快取
refresh(Key) 重新整理快取,即重新取快取資料,更新快取
2) google guava快取分析
guava快取過期時間分為兩種,一種是從寫入時開始計時,一種是從最後訪問時間開始計時,而且guava快取的過期時間是設定到整個一組快取上的;這和EHCache,redis,memcached等不同,這些快取系統設定都將快取時間設定到了單個快取上。
guava快取設計成了一組物件一個快取例項,這樣做的好處是一組物件設定一組快取策略,你可以根據不同的業務來設定不同的快取策略,包括弱引用,軟引用,過期時間,最大項數等。另外一點好處是你可以根據不同的組來統計快取的命中率,這樣更有意義一些。
這樣做也是有缺點的,缺點是首先是每個快取組都需要宣告不同的快取例項,具體到業務程式中可能就是每個業務物件一個快取了。這樣就把不同的業務快取分散到不同的業務系統中了,不太好管理。
4. 函式式風格(Functional idioms)
5. 併發(Concurrency)
併發程式設計是一個難題,但是一個強大而簡單的抽象可以顯著的簡化併發的編寫。出於這樣的考慮,Guava 定義了 ListenableFuture介面並繼承了JDK concurrent包下的Future 介面。
1) Guava併發:ListenableFuture使用介紹以及示例
ListenableFuture顧名思義就是可以監聽的Future,它是對java原生Future的擴充套件增強,本文介紹ListenableFuture的用法和擴充套件實現
ListenableFuture顧名思義就是可以監聽的Future,它是對java原生Future的擴充套件增強。我們知道Future表示一個非同步計算任務,當任務完成時可以得到計算結果。如果我們希望一旦計算完成就拿到結果展示給使用者或者做另外的計算,就必須使用另一個執行緒不斷的查詢計算狀態。這樣做,程式碼複雜,而且效率低下。使用ListenableFuture Guava幫我們檢測Future是否完成了,如果完成就自動呼叫回撥函式,這樣可以減少併發程式的複雜度。
另外ListenableFuture還有其他幾種內建實現:
SettableFuture:不需要實現一個方法來計算返回值,而只需要返回一個固定值來做為返回值,可以通過程式設定此Future的返回值或者異常資訊
CheckedFuture:這是一個繼承自ListenableFuture介面,他提供了checkedGet()方法,此方法在Future執行發生異常時,可以丟擲指定型別的異常。
2) Guava併發:RateLimiter限制資源的併發訪問執行緒數
RateLimiter類似於JDK的訊號量Semphore,他用來限制對資源併發訪問的執行緒數
RateLimiter類似於JDK的訊號量Semphore,他用來限制對資源併發訪問的執行緒數。
RateLimiterlimiter = RateLimiter.create(4.0);//每秒不超過4個任務被提交
limiter.acquire(); //請求RateLimiter,超過permits會被阻塞
executor.submit(runnable);//提交任務
也可以以非阻塞的形式來使用:
If(limiter.tryAcquire()){ //未請求到limiter則立即返回false
doSomething();
}else{
doSomethingElse();
}
3) Guava併發:使用Monitor控制併發
Monitor就像java原生的synchronized,ReentrantLock一樣,每次只允許一個執行緒執行程式碼塊,且可重佔用,每一次佔用要對應一次退出佔用。
/**
* 通過Monitor的Guard進行條件阻塞
*/
public classMonitorSample {
private List<String> list = new ArrayList<String>();
private static final int MAX_SIZE = 10;
private Monitor monitor = new Monitor();
private Monitor.Guard listBelowCapacity = new Monitor.Guard(monitor) {
@Override
public boolean isSatisfied() {
return list.size() < MAX_SIZE;
}
};
public void addToList(String item) throws InterruptedException {
monitor.enterWhen(listBelowCapacity); //Guard(形如Condition),不滿足則阻塞,而且我們並沒有在Guard進行任何通知操作
try {
list.add(item);
} finally {
monitor.leave();
}
}
}
就如上面,我們通過if條件來判斷是否可進入Monitor程式碼塊,並再try/finally中釋放:
if(monitor.enterIf(guardCondition)) {
try {
doWork();
}finally {
monitor.leave();
}
}
其他的Monitor訪問方法:
Monitor.enter //進入Monitor塊,將阻塞其他執行緒直到Monitor.leave
Monitor.tryEnter//嘗試進入Monitor塊,true表示可以進入, false表示不能,並且不會一直阻塞
Monitor.tryEnterIf//根據條件嘗試進入Monitor塊
這幾個方法都有對應的超時設定版本。
6. 字串處理(Strings)
1) 聯結器(Joiner)
用分隔符把字串序列連線起來也可能會遇上不必要的麻煩。如果字串序列中含有null,那連線操作會更難。Fluent風格的Joiner讓連線字串更簡單。
警告:joiner例項總是不可變的。用來定義joiner目標語義的配置方法總會返回一個新的joiner例項。這使得joiner例項都是執行緒安全的,你可以將其定義為staticfinal常量。
2) 拆分器(Splitter)
JDK內建的字串拆分工具有一些古怪的特性。比如,String.split悄悄丟棄了尾部的分隔符。例如:
”,a,,b,”.split(“,”) //””, “a”, “”, “b” 只有尾部的空字串被忽略了
Splitter使用令人放心的、直白的流暢API模式對這些混亂的特性作了完全的掌控。
a) 拆分器工廠:
方法
描述
Splitter.on(char)
按單個字元拆分
Splitter.on(CharMatcher)
按字元匹配器拆分
Splitter.on(String)
按字串拆分
Splitter.on(Pattern)
Splitter.onPattern(String)
按正則表示式拆分
Splitter.fixedLength(int)
按固定長度拆分;最後一段可能比給定長度短,但不會為空。
b) 拆分器修飾符:
方法 |
描述 |
omitEmptyStrings() |
從結果中自動忽略空字串 |
trimResults() |
移除結果字串的前導空白和尾部空白 |
trimResults(CharMatcher) |
給定匹配器,移除結果字串的前導匹配字元和尾部匹配字元 |
limit(int) |
限制拆分出的字串數量 |
如果你想要拆分器返回List,只要使用Lists.newArrayList(splitter.split(string))或類似方法。 警告:splitter例項總是不可變的。用來定義splitter目標語義的配置方法總會返回一個新的splitter例項。這使得splitter例項都是執行緒安全的,你可以將其定義為static final常量。
3) 字元匹配器(CharMatcher)
然而使用CharMatcher的好處更在於它提供了一系列方法,讓你對字元作特定型別的操作:修剪[trim]、摺疊[collapse]、移除[remove]、保留[retain]等等。CharMatcher例項首先代表概念1:怎麼才算匹配字元?然後它還提供了很多操作概念2:如何處理這些匹配字元?這樣的設計使得API複雜度的線性增加可以帶來靈活性和功能兩方面的增長。
注:CharMatcher只處理char型別代表的字元;它不能理解0x10000到0x10FFFF的Unicode增補字元。這些邏輯字元以代理對[surrogatepairs]的形式編碼進字串,而CharMatcher只能將這種邏輯字元看待成兩個獨立的字元。
4) 字符集(Charsets)
Charsets針對所有Java平臺都要保證支援的六種字符集提供了常量引用。嘗試使用這些常量,而不是通過名稱獲取字符集例項。
5) 大小寫格式(CaseFormat)
CaseFormat被用來方便地在各種ASCII大小寫規範間轉換字串——比如,程式語言的命名規範。CaseFormat支援的格式如下:
格式
範例
LOWER_CAMEL
lowerCamel
LOWER_HYPHEN
lower-hyphen
LOWER_UNDERSCORE
lower_underscore
UPPER_CAMEL
UpperCamel
UPPER_UNDERSCORE
UPPER_UNDERSCORE
CaseFormat的用法很直接:
CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL,”CONSTANT_NAME”
)); // returns “constantName”
我們CaseFormat在某些時候尤其有用,比如編寫程式碼生成器的時候。
7. 原生型別(Primitives)
Java的原生型別也稱原始型別,也是基本資料型別byte、short、int、long、float、double、char和boolean。
在從Guava查詢原生型別方法之前,可以先查查Arrays類,或者對應的基礎型別包裝類,如Integer。
原生型別不能當作物件或泛型的型別引數使用,這意味著許多通用方法都不能應用於它們。Guava提供了若干通用工具,包括原生型別陣列與集合API的互動,原生型別和位元組陣列的相互轉換,以及對某些原生型別的無符號形式的支援。
原生型別
Guava工具類(都在com.google.common.primitives包)
byte
Bytes, SignedBytes, UnsignedBytes
short
Shorts
int
Ints, UnsignedInteger, UnsignedInts
long
Longs, UnsignedLong, UnsignedLongs
float
Floats
double
Doubles
char
Chars
boolean
Booleans
Bytes工具類沒有定義任何區分有符號和無符號位元組的方法,而是把它們都放到了SignedBytes和UnsignedBytes工具類中,因為位元組型別的符號性比起其它型別要略微含糊一些。
int和long的無符號形式方法在UnsignedInts和UnsignedLongs類中,但由於這兩個型別的大多數用法都是有符號的,Ints和Longs類按照有符號形式處理方法的輸入引數。
此外,Guava為int和long的無符號形式提供了包裝類,即UnsignedInteger和UnsignedLong,以幫助你使用型別系統,以極小的效能消耗對有符號和無符號值進行強制轉換。
原生型別陣列工具:
方法簽名
描述
List<Wrapper> asList(prim… backingArray)
把陣列轉為相應包裝類的List
prim[] toArray(Collection<Wrapper> collection)
把集合拷貝為陣列,和collection.toArray()一樣執行緒安全
prim[] concat(prim[]… arrays)
串聯多個原生型別陣列
boolean contains(prim[] array, prim target)
判斷原生型別陣列是否包含給定值
int indexOf(prim[] array, prim target)
給定值在陣列中首次出現處的索引,若不包含此值返回-1
int lastIndexOf(prim[] array, prim target)
給定值在陣列最後出現的索引,若不包含此值返回-1
prim min(prim… array)
陣列中最小的值
prim max(prim… array)
陣列中最大的值
String join(String separator, prim… array)
把陣列用給定分隔符連線為字串
Comparator<prim[]> lexicographicalComparator()
按字典序比較原生型別陣列的Comparator
*符號無關方法存在於Bytes, Shorts, Ints, Longs, Floats, Doubles, Chars, Booleans。而UnsignedInts,UnsignedLongs, SignedBytes, 或UnsignedBytes不存在。
*符號相關方法存在於SignedBytes, UnsignedBytes, Shorts, Ints, Longs, Floats, Doubles,Chars, Booleans, UnsignedInts, UnsignedLongs。而Bytes不存在。
通用工具方法:
方法簽名
描述
int compare(prim a, prim b)
傳統的Comparator.compare方法,但針對原生型別。JDK7的原生型別包裝類也提供這樣的方法
prim checkedCast(long value)
把給定long值轉為某一原生型別,若給定值不符合該原生型別,則丟擲IllegalArgumentException
prim saturatedCast(long value)
把給定long值轉為某一原生型別,若給定值不符合則使用最接近的原生型別值
*這裡的整型包括byte, short, int, long。不包括char, boolean, float, 或double。
位元組轉換方法:
Guava提供了若干方法,用來把原生型別按大位元組序與位元組陣列相互轉換。所有這些方法都是符號無關的,此外Booleans沒有提供任何下面的方法。
方法簽名或欄位簽名
描述
int BYTES
常量:表示該原生型別需要的位元組數
prim fromByteArray(byte[] bytes)
使用位元組陣列的前Prims.BYTES個位元組,按大位元組序返回原生型別值;如果bytes.length <= Prims.BYTES,丟擲IAE
prim fromBytes(byte b1, …, byte bk)
接受Prims.BYTES個位元組引數,按大位元組序返回原生型別值
byte[] toByteArray(prim value)
按大位元組序返回value的位元組陣列
8. 區間(Ranges)
1) 簡介
區間,有時也稱為範圍,是特定域中的凸性(非正式說法為連續的或不中斷的)部分。在形式上,凸性表示對a<=b<=c, range.contains(a)且range.contains(c)意味著range.contains(b)。
區間可以延伸至無限——例如,範圍”x>3″包括任意大於3的值——也可以被限制為有限,如” 2<=x<5″。Guava用更緊湊的方法表示範圍,有數學背景的程式設計師對此是耳熟能詳的:
(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稱為端點 。為了提高一致性,Guava中的Range要求上端點不能小於下端點。上下端點有可能是相等的,但要求區間是閉區間或半開半閉區間(至少有一個端點是包含在區間中的):
[a..a]:單元素區間
[a..a); (a..a]:空區間,但它們是有效的
(a..a):無效區間
Guava用型別Range<C>表示區間。所有區間實現都是不可變型別。
2) 構建區間
區間例項可以由Range類的靜態方法獲取:
(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()
此外,也可以明確地指定邊界型別來構造區間:
有界區間 |
range(C, BoundType, C, BoundType) |
無上界區間:((a..+∞) 或[a..+∞)) |
downTo(C, BoundType) |
無下界區間:((-∞..b) 或(-∞..b]) |
upTo(C, BoundType) |
這裡的BoundType是一個列舉型別,包含CLOSED和OPEN兩個值。
3) 區間運算
Range的基本運算是它的contains(C) 方法,和你期望的一樣,它用來區間判斷是否包含某個值。此外,Range例項也可以當作Predicate,並且在函數語言程式設計中使用(譯者注:見第4章)。任何Range例項也都支援containsAll(Iterable<? extends C>)方法:
4) 查詢運算
Range類提供了以下方法來 檢視區間的端點:
hasLowerBound()和hasUpperBound():判斷區間是否有特定邊界,或是無限的;
lowerBoundType()和upperBoundType():返回區間邊界型別,CLOSED或OPEN;如果區間沒有對應的邊界,丟擲IllegalStateException;
lowerEndpoint()和upperEndpoint():返回區間的端點值;如果區間沒有對應的邊界,丟擲IllegalStateException;
isEmpty():判斷是否為空區間。
5) 關係運算
a) 包含[enclose]
區間之間的最基本關係就是包含[encloses(Range)]:如果內區間的邊界沒有超出外區間的邊界,則外區間包含內區間。包含判斷的結果完全取決於區間端點的比較
b) 相連[isConnected]
Range.isConnected(Range)判斷區間是否是相連的。具體來說,isConnected測試是否有區間同時包含於這兩個區間,這等同於數學上的定義”兩個區間的並集是連續集合的形式”(空區間的特殊情況除外)。
c) 交集[intersection]
Range.intersection(Range)返回兩個區間的交集:既包含於第一個區間,又包含於另一個區間的最大區間。當且僅當兩個區間是相連的,它們才有交集。如果兩個區間沒有交集,該方法將丟擲IllegalArgumentException。
d) 跨區間[span]
Range.span(Range)返回”同時包括兩個區間的最小區間”,如果兩個區間相連,那就是它們的並集。
span是可互換的[commutative] 、關聯的[associative] 、閉合的[closed]運算[operation]。
6) 離散域
部分(但不是全部)可比較型別是離散的,即區間的上下邊界都是可列舉的。
在Guava中,用DiscreteDomain<C>實現型別C的離散形式操作。一個離散域總是代表某種型別值的全集;它不能代表類似”素數”、”長度為5的字串”或”午夜的時間戳”這樣的區域性域。
DiscreteDomain提供的離散域例項包括:
型別
離散域
Integer
integers()
Long
longs()
一旦獲取了DiscreteDomain例項,你就可以使用下面的Range運算方法:
ContiguousSet.create(range, domain):用ImmutableSortedSet<C>形式表示Range<C>中符合離散域定義的元素,並增加一些額外操作——譯者注:實際返回ImmutableSortedSet的子類ContiguousSet。(對無限區間不起作用,除非型別C本身是有限的,比如int就是可列舉的)
canonical(domain):把離散域轉為區間的”規範形式”。如果ContiguousSet.create(a, domain).equals(ContiguousSet.create(b,domain))並且!a.isEmpty(),則有a.canonical(domain).equals(b.canonical(domain))。(這並不意味著a.equals(b))
你可以建立自己的離散域,但必須記住DiscreteDomain契約的幾個重要方面。
一個離散域總是代表某種型別值的全集;它不能代表類似”素數”或”長度為5的字串”這樣的區域性域。所以舉例來說,你無法構造一個DiscreteDomain以表示精確到秒的JODA DateTime日期集合:因為那將無法包含JODA DateTime的所有值。
DiscreteDomain可能是無限的——比如BigInteger DiscreteDomain。這種情況下,你應當用minValue()和maxValue()的預設實現,它們會丟擲NoSuchElementException。但Guava禁止把無限區間傳入ContiguousSet.create——譯者注:那明顯得不到一個可列舉的集合。
9. I/O
1) Guava Files中的檔案操作
Java的基本API對檔案的操作很繁瑣,為了向檔案中寫入一行文字,都需要寫十幾行的程式碼。guava對此作了很多改進,提供了很多方便的操作。
10. 雜湊(Hash)
1) 概述
Java內建的雜湊碼[hash code]概念被限制為32位,並且沒有分離雜湊演算法和它們所作用的資料,因此很難用備選演算法進行替換。此外,使用Java內建方法實現的雜湊碼通常是劣質的,部分是因為它們最終都依賴於JDK類中已有的劣質雜湊碼。
Object.hashCode往往很快,但是在預防碰撞上卻很弱,也沒有對分散性的預期。這使得它們很適合在散列表中運用,因為額外碰撞只會帶來輕微的效能損失,同時差勁的分散性也可以容易地通過再雜湊來糾正(Java中所有合理的散列表都用了再雜湊方法)。然而,在簡單散列表以外的雜湊運用中,Object.hashCode幾乎總是達不到要求——因此,有了com.google.common.hash包。
2) 雜湊包的組成
在這個包的Java doc中,我們可以看到很多不同的類,但是文件中沒有明顯地表明它們是怎樣一起配合工作的。
a) HashFunction
HashFunction是一個單純的(引用透明的)、無狀態的方法,它把任意的資料塊對映到固定數目的位置,並且保證相同的輸入一定產生相同的輸出,不同的輸入儘可能產生不同的輸出。
b) Hasher
HashFunction的例項可以提供有狀態的Hasher,Hasher提供了流暢的語法把資料新增到雜湊運算,然後獲取雜湊值。Hasher可以接受所有原生型別、位元組陣列、位元組陣列的片段、字元序列、特定字符集的字元序列等等,或者任何給定了Funnel實現的物件。
Hasher實現了PrimitiveSink介面,這個介面為接受原生型別流的物件定義了fluent風格的API
c) Funnel
Funnel描述瞭如何把一個具體的物件型別分解為原生欄位值,從而寫入PrimitiveSink。
注:putString(“abc”,Charsets.UTF_8).putString(“def”, Charsets.UTF_8)完全等同於putString(“ab”, Charsets.UTF_8).putString(“cdef”,Charsets.UTF_8),因為它們提供了相同的位元組序列。這可能帶來預料之外的雜湊衝突。增加某種形式的分隔符有助於消除雜湊衝突。
d) HashCode
一旦Hasher被賦予了所有輸入,就可以通過hash()方法獲取HashCode例項(多次呼叫hash()方法的結果是不確定的)。HashCode可以通過asInt()、asLong()、asBytes()方法來做相等性檢測,此外,writeBytesTo(array, offset, maxLength)把雜湊值的前maxLength位元組寫入位元組陣列。
3) 布魯姆過濾器[BloomFilter]
布魯姆過濾器是雜湊運算的一項優雅運用,它可以簡單地基於Object.hashCode()實現。簡而言之,布魯姆過濾器是一種概率資料結構,它允許你檢測某個物件是一定不在過濾器中,還是可能已經新增到過濾器了。
Guava雜湊包有一個內建的布魯姆過濾器實現,你只要提供Funnel就可以使用它。你可以使用create(Funnel funnel, int expectedInsertions, doublefalsePositiveProbability)方法獲取BloomFilter<T>,預設誤檢率[falsePositiveProbability]為3%。BloomFilter<T>提供了booleanmightContain(T) 和void put(T),它們的含義都不言自明瞭。
4) Hashing類
Hashing類提供了若干雜湊函式,以及運算HashCode物件的工具方法。
已提供的雜湊函式
md5()
murmur3_128()
murmur3_32()
sha1()
sha256()
sha512()
goodFastHash(int bits)
HashCode運算
方法 |
描述 |
HashCode combineOrdered( Iterable<HashCode>) |
以有序方式聯接雜湊碼,如果兩個雜湊集合用該方法聯接出的雜湊碼相同,那麼雜湊集合的元素可能是順序相等的 |
HashCode combineUnordered( Iterable<HashCode>) |
以無序方式聯接雜湊碼,如果兩個雜湊集合用該方法聯接出的雜湊碼相同,那麼雜湊集合的元素可能在某種排序下是相等的 |
int consistentHash( HashCode, int buckets) |
為給定的”桶”大小返回一致性雜湊值。當”桶”增長時,該方法保證最小程度的一致性雜湊值變化。詳見一致性雜湊。 |
11. 事件匯流排(EventBus)
傳統上,Java的程序內事件分發都是通過釋出者和訂閱者之間的顯式註冊實現的。設計EventBus就是為了取代這種顯示註冊方式,使元件間有了更好的解耦。EventBus不是通用型的釋出-訂閱實現,不適用於程序間通訊。
12. 數學運算(Math)
13. 反射(Reflection)
1) guava反射TypeToken解決泛型執行時型別擦除的問題
介紹guava中的TypeToken類解決java 執行時泛型型別擦除問題。
TypeToken的方法列表如下:
方法
描述
getType()
獲得包裝的java.lang.reflect.Type.
getRawType()
返回大家熟知的執行時類
getSubtype(Class<?>)
返回那些有特定原始類的子型別。舉個例子,如果這有一個Iterable並且引數是List.class,那麼返回將是List。
getSupertype(Class<?>)
產生這個型別的超類,這個超類是指定的原始型別。舉個例子,如果這是一個Set並且引數是Iterable.class,結果將會是Iterable。
isAssignableFrom(type)
如果這個型別是 assignable from 指定的型別,並且考慮泛型引數,返回true。List<? extends Number>是assignable from List,但List沒有.
getTypes()
返回一個Set,包含了這個所有介面,子類和類是這個型別的類。返回的Set同樣提供了classes()和interfaces()方法允許你只瀏覽超類和介面類。
isArray()
檢查某個型別是不是陣列,甚至是<? extends A[]>。
getComponentType()
返回元件型別陣列。
2) guava反射之Invokable使用
Guava的Invokable是對java.lang.reflect.Method和java.lang.reflect.Constructor的流式包裝。它簡化了常見的反射程式碼的使用。
一些使用例子:
a) 方法是否是public的?
JDK:
Modifier.isPublic(method.getModifiers());
Invokable:
invokable.isPublic();
b) 方法是否是package private?
JDK:
!(Modifier.isPrivate(method.getModifiers())||Modifier.isPublic(method.getModifiers()))
Invokable:
invokable.isPackagePrivate()
c) 方法是否能夠被子類重寫?
JDK:
!(Modifier.isFinal(method.getModifiers())
||Modifiers.isPrivate(method.getModifiers())
||Modifiers.isStatic(method.getModifiers())
||Modifiers.isFinal(method.getDeclaringClass().getModifiers()))
Invokable:
invokable.isOverridable()
d) 方法的第一個引數是否被定義了註解@Nullable?
JDK:
for (Annotation annotation : method.getParameterAnnotations[0]) {
if (annotation instanceof Nullable) {
return true;
}
}
return false;
Invokable:
invokable.getParameters().get(0).isAnnotationPresent(Nullable.class)
e) 建構函式和工廠方法如何共享同樣的程式碼?
你是否很想重複自己,因為你的反射程式碼需要以相同的方式工作在建構函式和工廠方法中?
Invokable提供了一個抽象的概念。下面的程式碼適合任何一種方法或建構函式:
invokable.isPublic();
invokable.getParameters();
invokable.invoke(object,args);
List的List.get(int)返回型別是什麼?
Invokable提供了與眾不同的型別解決方案:
Invokable<List<String>,?> invokable = new TypeToken<List<String>>() {}.method(getMethod);
invokable.getReturnType();// String.class
3) guava反射:Reflection.newProxy方法簡化動態代理
原理上GoogleGuava的動態代理也是使用JDK的動態代理,這是做了封裝,更加簡便。另外一點是能夠很好的檢查需要代理的物件必須擁有介面。使用Class
類的
isInterface()
來做檢查。
14. 註解(Annotations)
com.google.common.annotations包下註解類的含義和用法:
/**
* 表明一個公用API的未來版本是受不相容變更或刪除限制的
* 擁有這個註釋標誌的API不受任何相容性保證
*
*/
@Retention(RetentionPolicy.CLASS)
@Target({
ElementType.ANNOTATION_TYPE,
ElementType.CONSTRUCTOR,
ElementType.FIELD,
ElementType.METHOD,
ElementType.TYPE})
@Documented
@GwtCompatible
[email protected] Beta {}
2) GwtCompatible
/**
* 表明一個型別可能會與 Google WebToolkit 一起使用.
* 如果一個方法使用這個註釋,說明這個方法的返回值是GWT 相容的
*
*/
@Retention(RetentionPolicy.CLASS)
@Target({ElementType.TYPE, ElementType.METHOD })
@Documented
@GwtCompatible
[email protected] GwtCompatible {
/**
* 說明一個型別或者方法的返回值是否支援GWT 序列化
*
*/
boolean serializable() default false;
/**
* 說明一個型別是否在 GWT 被模擬.
* 被模擬的源(父源)和JVM的實現不一樣
*
*/
boolean emulated() default false;
}
3) GwtIncompatible
/**
* 說明一個方法可能無法與 GWT 一起使用
* 他只能用於被 @GwtCompatible標誌的類的欄位,方法和內部類
*
*/
@Retention(RetentionPolicy.CLASS)
@Target({
ElementType.TYPE, ElementType.METHOD,
ElementType.CONSTRUCTOR,ElementType.FIELD })
@Documented
@GwtCompatible
[email protected] GwtIncompatible {
/**
* 用於表示不相容 GWT 的原因
*
*/
String value();
}
4) VisibleForTesting
/**
*註釋程式元素的存在,或比其他必要廣泛可見,僅用於測試程式碼。
*/
@GwtCompatible
[email protected] VisibleForTesting {
}
15. 網路程式設計(Net)
guava中的net包目前提供的功能較少,而且大多類都標註了@Beta的註解,在guava中標記Beta註解表示這個類還不穩定,有可能在以後的版本中變化,或者去掉,所以不建議大量使用,這裡也是隻做簡單的介紹。
先介紹下唯一一個沒有Beta註解的類HttpHeaders,這個類中並沒有實質的方法,只是定義了一些Http頭名稱的常量,通常如果需要我們會自己定義這些常量,如果你引用了guava包,那麼就不再建議我們自己定義這些頭名稱的常量了,直接用它定義的即可。
這裡面應該有幾乎所有的Http頭名稱,例如:X_FORWARDED_FOR,UPGRADE,REFERER等等。用法也沒有必要介紹了,直接引用常量就可以了。
再介紹下一個比較常用的小功能,有時候我們需要在配置檔案中配置IP+埠,這時候需要自己寫解析ip,埠的方法,guava為我們提供瞭解析類,我們看下用法例項:
HostAndPort hostAndPort =HostAndPort.fromString(“127.0.0.1:8080”);
System.out.println(“host== ” + hostAndPort.getHostText());
System.out.println(“port== ” + hostAndPort.getPortOrDefault(80));
HostAndPort類的靜態方法fromString(String)可以解析出字串中定義的Host和埠資訊。
另外guava包中還提供了InetAddresses類,這個類是InetAddress的幫助類,通過這個類可以方便的從字串中解析出InetAddress類。但是此類也有@Beta的註解,所以要謹慎使用。
參考資料:http://ifeve.com/google-guava/
https://code.google.com/p/guava-libraries/
相關推薦
google guava 入門教程
Guava(瓜娃)學習筆記 (程式碼下載地址) Guava工程包含了若干被google的java專案廣泛依賴的核心庫,例如:集合 [collections] 、快取 [caching] 、原生型別支援 [primitives support] 、併發庫 [concurrency libraries]
Google Guava入門教程
class PreconditionsTest { @Test public void Preconditions() throws Exception { getPersonByPrecondition(8,"peida");
Google Guava官方教程
原文連結 譯文連結 譯者: 沈義揚,羅立樹,何一昕,*武祖 * 校對:方騰飛 引言 Guava工程包含了若干被Google的 Java專案廣泛依賴 的核心庫,例如:集合 [collections] 、快取 [caching] 、原生型別支援 [primitives support] 、併發庫 [
Google Guava官方教程(中文版)
原文連結 譯文連結 譯者: 沈義揚,羅立樹,何一昕,武祖 校對:方騰飛 引言 Guava工程包含了若干被Google的 Java專案廣泛依賴 的核心庫,例如:集合 [collections] 、快取 [caching] 、原生型別支援 [primitives support] 、併發庫 [
Google Guava官方教程(中文版)(轉)
引言 Guava工程包含了若干被Google的 Java專案廣泛依賴 的核心庫,例如:集合 [collections] 、快取 [caching] 、原生型別支援 [primitives support] 、併發庫 [concurrency libraries] 、通用
函數式編程入門教程(轉)
制作 說明 讀取 ttf 中國 png if...else per 部分 初涉函數式編程語言python,轉載了一篇文章,先簡單來了解一下函數式編程的概念. 文章原址:http://www.ruanyifeng.com/blog/2017/02/fp-tutorial.ht
CodeIgniter 入門教程第一篇:信息發布
per 所有 控制 知識點 image doc ref har 提交 一、MVC CodeIgniter 采用MVC架構即:控制層、模型層和視圖層。 對應Application下面的文件夾 (圖1): 所有新建文件以.php結尾 視圖層
Java - Struts框架教程 Hibernate框架教程 Spring框架入門教程(新版) sping mvc spring boot spring cloud Mybatis
java ee cloud pac .cn java get pin nat 輕量級 https://www.zhihu.com/question/21142149 http://how2j.cn/k/hibernate/hibernate-tutorial/31.html
Django REST framework 的快速入門教程
ret turn ads 使用 blog 所有 定義 想去 cti CRM-API項目搭建 序列器(Serializers) 首先,我們來定義一些序列器。我們來創建一個新的模塊(module)叫做 crm/rest_searializer.py ,這是我們用來描述數據是如何
Jade模板引擎入門教程
undefine 文件 ech content arrays str www versions contain Jade是一款高性能簡潔易懂的模板引擎,Jade是Haml的Javascript實現,在服務端(NodeJS)及客戶端均有支持。 功能 客戶端支持 超強的可讀性
Webpack新手入門教程(學習筆記)
自身 方式 pin 演示 要求 const 初學者 功能 plugins p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 30.0px Helvetica; color: #000000 }
gulp入門教程
綠色 實現 save lan 當前 包管理 安裝插件 列出文件 編寫 gulp是什麽? gulp是前端開發過程中對代碼進行構建的工具,是自動化項目的構建利器;它不僅能對網站資源進行優化,而且在開發過程中很多重復的任務能夠使用正確的工具自動完成;使
asp.net core入門教程系列 (一)
home padding 方式 title sys 活性 elf tro ash Asp.Net Core簡介 ASP.NET Core 是一個全新的開源、跨平臺框架,可以用它來構建基於網絡連接的現代雲應用程序,比如:Web 應用,IoT(Internet Of Thin
數據庫詳細入門教程
刪除數據 表結構 arch 刪除數據庫 1.2 tro host 顯示 唯一性約束 創建用戶:CREATE USER [email protected]/* */ IDENTIFIED BY ‘密碼‘ 主機名可以為空,為空默認為%權限,表示所有主機可連接
Redux 入門教程
ref tutorial mod html .com opera 異步 6.0 part Redux 入門教程(三):React-Redux 的用法([email protected]/* */) Redux 入門教程(二):中間件與異步操作([email
zookeeper入門教程
下載 eval 節點 zkcli span books 生產環境 存儲 線程 zookeeper使用場景,不是很難了解,感覺zk監聽節點變化,這個功能比較厲害。zk存儲的節點組織結構有點像unix文件系統 1.安裝zk 運行環境 centos 7 java 8 zoo
【CC2530入門教程-05】CC2530的串行接口原理與應用
max blog 模式 指數 open != tab bre 就會 第5課 CC2530的串行接口原理與應用 廣東職業技術學院 歐浩源 一、並行通信與串行通信 微控制器與外設之間的數據通信,根據連線結構和傳送方式的不同,可以分為兩種:並行通信和串行通信。
CodeArt入門教程(二)
本質 文件夾 不同的 存在 切換數據庫 站點 ear 新的 組裝 4.第一個示例的編碼工作 使用CA編碼項目的核心結構是:由多個子系統組成多個不同的服務來提供項目的各種功能。請不要將這裏提到的子系統與大家在別的項目實施方法裏的概念混為一談,CA裏的子系統概念是完全不一樣
CodeArt入門教程(三)
pan center account 根據 領域對象 保存 顏色 單一職責原則 用例 5.領域模型設計 下面我們創建賬戶子系統(AccountSubsystem),賬戶子系統雖然被門戶服務使用,但是子系統本身是獨立於任何服務存在的。所以我們為賬戶子系統創建獨立的項目解決
Python基礎入門教程,Python學習路線圖
第一天 字符 語法 知識 國內 排序 inux 跟著 最好的 給大家整理的這套python學習路線圖,按照此教程一步步的學習來,肯定會對python有更深刻的認識。或許可以喜歡上python這個易學,精簡,開源的語言。此套教程,不但有視頻教程,還有源碼分享,讓大家能真正