- 1.以面向?qū)ο笏枷胩幚碜址?Joiner/Splitter/CharMatcher
// 連接器
private static final Joiner joiner = Joiner.on(",").skipNulls();
// 分割器
private static final Splitter spliter = Splitter.on(",").trimResults().omitEmptyStrings();
public static void main(String[] args) {
//把集合數(shù)組中的元素join在一起
String join = joiner.join(Lists.newArrayList("a", null, "b", "", " "));
System.out.println("join=" + join);
for (String tmp : spliter.split(" a, b, null ,,")){
System.out.println("|" + tmp + "|");
}
}
輸出:
join=a,b,,
|a|
|b|
|null|
使用
useForNull
可以制定一個字符串替換null,而不是直接跳過null , 如下:
private static final Joiner joiner = Joiner.on(",").useForNull("wudy");
輸出: join=a,wudy,b,,
使用空白字符分割
private static final Splitter spliter = Splitter.on(CharMatcher.WHITESPACE).trimResults().omitEmptyStrings();
for (String tmp : spliter.split(" a, b, null , ,")){
System.out.println("|" + tmp + "|");
}
輸出:
|a,|
|b,|
|null|
|,|
|,|
按固定長度拆分,最后一段可能比給定長度短烂瘫,但不會為空
private static final Splitter spliter = Splitter.fixedLength(3).trimResults().omitEmptyStrings();
for (String tmp : spliter.split(" a, b, null , , ")){
System.out.println("|" + tmp + "|");
}
輸出:
|a,|
|b,|
|n|
|ull|
|,|
|,|
字符串匹配器
private static final CharMatcher charMatcherDigit = CharMatcher.DIGIT;
private static final CharMatcher charMatcherAny = CharMatcher.ANY;
public static void main(String[] args) {
//只保留匹配的字符卵蛉,其他移除
System.out.println("只保留字符串的數(shù)字=" + charMatcherDigit.retainFrom("ashbx78i~!"));
System.out.println("移除字符串的數(shù)字=" + charMatcherDigit.removeFrom("ashbx78i~!"));
System.out.println("用?替換數(shù)字=" + charMatcherDigit.replaceFrom("ashbx78i~!", "?"));
System.out.println("在字母a~f范圍或者等于n狐肢,全部替換為* | " + charMatcherAny.inRange('a', 'f').or(charMatcherAny.is('n')).replaceFrom("xscfgvjhjkhdnass", "*"));
}
輸出:
只保留字符串的數(shù)字=78
移除字符串的數(shù)字=ashbxi~!
用?替換數(shù)字=ashbx??i~!
在字母a~f范圍或者等于n而昨,全部替換為* | xsgvjhjkh*ss
總結(jié):
- 1.對于
Joiner
话侧,常用的方法是 跳過NULL元素:skipNulls()
/ 對于NULL元素使用其他替代:useForNull(String)
- 對于
Splitter
速蕊,常用的方法是:trimResults()
/omitEmptyStrings()
滓侍。注意拆分的方式顶伞,有字符串喝峦,還有正則,還有固定長度分割- 3.
joiner
實例總是不可變的势誊。用來定義joiner
目標語義的配置方法總會返回一個新的joiner
實例。這使得joiner實例都是線程安全的谣蠢,你可以將其定義為static final
常量
- 2.guava對JDK提供的原生類型操作進行了擴展
public static void main(String[] args) {
// 快速完成到集合的轉(zhuǎn)換
List<Integer> list = Ints.asList(1,3,5,7,9);
System.out.println(Ints.join(",", 1,3,1,4));
// 原生類型的數(shù)組快速合并
int[] intArray = Ints.concat(new int[]{1,2}, new int[]{3,4});
System.out.println(intArray.length);
//最大最小
System.out.println("最大值=" + Ints.max(intArray) + "最小值=" + Ints.min(intArray));
// 是否包含
System.out.println("是否包含=" + Ints.contains(intArray, 1));
// 集合到數(shù)組轉(zhuǎn)換
int[] intArr = Ints.toArray(list);
}
輸出:
1,3,1,4
4
最大值=4最小值=1
是否包含=true
總結(jié): guava提供了
Bytes/Shorts/Ints/Iongs/Floats/Doubles/Chars/Booleans
這些基本數(shù)據(jù)類型的擴展支持
- 3.對JDK集合的有效補充
灰色地帶:
Multiset
JDK
的集合粟耻,提供了有序且可以重復(fù)的List
,無序且不可以重復(fù)的Set
眉踱。那這里其實對于集合涉及到了2個概念挤忙,一個order,一個dups谈喳。那么List vs Set册烈,and then some ?
image.png
Multiset
是什么,我想上面的圖婿禽,你應(yīng)該了解它的概念了赏僧。Multiset
就是無序的大猛,但是可以重復(fù)的集合
,它就是游離在List/Set
之間的“灰色地帶”淀零!
(至于有序的胎署,不允許重復(fù)的集合嘛,guava還沒有提供窑滞,當(dāng)然在未來應(yīng)該會提供UniqueList琼牧,我猜的,哈哈)
重點:Multiset自帶一個有用的功能哀卫,就是可以跟蹤每個對象的數(shù)量
public static void main(String[] args) {
HashMultiset<String> hashMultiset = HashMultiset.create();
hashMultiset.add("a");
hashMultiset.add("a");
hashMultiset.add("b");
hashMultiset.add("c");
hashMultiset.add("b");
System.out.println("size=" + hashMultiset.size());
System.out.println("元素a的出現(xiàn)次數(shù)" + hashMultiset.count("a"));
}
輸出:
size=5
元素a的出現(xiàn)次數(shù)2
- 4.Immutable vs unmodifiable
// 先看一個unmodifiable的例子:
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
List<String> readOnlyList = Collections.unmodifiableList(list);
// readOnlyList.add("c"); //java.lang.UnsupportedOperationException
list.add("c");
System.out.println(readOnlyList.size()); // 3
}
你看到
JDK
提供的unmodifiable
的缺陷了嗎巨坊?
實際上,Collections.unmodifiableXxx
所返回的集合和源集合是同一個對象此改,只不過可以對集合做出改變的API
都被override
趾撵,會拋出UnsupportedOperationException
。
也即是說我們改變源集合共啃,導(dǎo)致不可變視圖(unmodifiable View
)也會發(fā)生變化占调。
當(dāng)然,在不使用guava的情況下移剪,我們是怎么避免上面的問題的呢究珊?
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
// new Object: copy (Defensive Copies,保護性拷貝)
List<String> readOnlyList = Collections.unmodifiableList(new ArrayList<String>(list));
list.add("c");
System.out.println(readOnlyList.size()); // 2
}
使用
Guava
方式
guava
提供了很多Immutable
集合纵苛,比如ImmutableList/ImmutableSet/ImmutableSortedSet/ImmutableMap
,Immutable
在COPY
階段還考慮了線程的并發(fā)性等
public static void main(String[] args) {
ImmutableList<String> immutableList = ImmutableList.of("a", "b", "c");
// immutableList.add("d"); //java.lang.UnsupportedOperationException
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
ImmutableList<String> immutableList1 = ImmutableList.copyOf(list);
list.add("d");
// 視圖不會隨著源數(shù)據(jù)而改變剿涮,guava只讀設(shè)置安全可靠
System.out.println("list size=" + list.size() + " immutableList1 size=" + immutableList1.size() ); // list size=4 immutableList1 size=3
}
// ImmutableMap例子
ImmutableMap<String, String> immutableMap = ImmutableMap.of("name", "wudy", "phone", "13074491521");
immutableMap.put("address", "sz"); // java.lang.UnsupportedOperationException
- 5.一對多:
Multimap
JDK
提供給我們的Map是一個鍵
,一個值攻人,一對一的取试,那么在實際開發(fā)中,顯然存在一個KEY
多個VALUE
的情況(比如一個分類下的書本)怀吻,我們往往這樣表達:Map<k,List>
瞬浓,好像有點臃腫!臃腫也就算了蓬坡,更加不爽的事猿棉,我們還得判斷KEY是否存在來決定是否new
一個LIST
出來,有點麻煩渣窜!更加麻煩的事情還在后頭铺根,比如遍歷宪躯,比如刪除
public static void main(String[] args) {
Multimap<String, String> multimap = ArrayListMultimap.create();
multimap.put("phone", "13074491521");
multimap.put("phone", "18973038382");
multimap.put("name", "wudy");
System.out.println(multimap.get("phone")); // [13074491521, 18973038382]
}
友情提示下乔宿,
guava
所有的集合都有create
方法,這樣的好處在于簡單访雪,而且我們不必在重復(fù)泛型信息了详瑞。
get()/keys()/keySet()/values()/entries()/asMap()
都是非常有用的返回view collection
的方法掂林。
Multimap
的實現(xiàn)類有:ArrayListMultimap/HashMultimap/LinkedHashMultimap/TreeMultimap/ImmutableMultimap
- 6.雙向
BiMap
JDK
提供的MAP
讓我們可以find value by key
,那么能不能通過find key by value
呢坝橡,能不能KEY
和VALUE
都是唯一的呢泻帮。這是一個雙向的概念,即forward+backward
计寇。
在實際場景中有這樣的需求嗎锣杂?比如通過用戶ID找到mail,也需要通過mail找回用戶名番宁。沒有guava
的時候元莫,我們需要create forward map AND create backward map,and now just let guava do that for you.
public static void main(String[] args) {
HashBiMap<String, String> biMap = HashBiMap.create();
biMap.put("wudy.yu", "13074491521");
// value 重復(fù)會報錯
// biMap.put("peter.li", "13074491521"); // java.lang.IllegalArgumentException: value already present: 13074491521
// 強制覆蓋
biMap.forcePut("peter.li", "13074491521");
// 反轉(zhuǎn)為 value => key
System.out.println(biMap.inverse().get("13074491521")); // peter.li
}
biMap / biMap.inverse() / biMap.inverse().inverse()
它們是什么關(guān)系呢蝶押?
你可以稍微看一下BiMap
的源碼實現(xiàn)踱蠢,實際上,當(dāng)你創(chuàng)建BiMap
的時候棋电,在內(nèi)部維護了2個map
茎截,一個forward map
,一個backward map
赶盔,并且設(shè)置了它們之間的關(guān)系企锌。
因此,biMap.inverse() != biMap
于未;biMap.inverse().inverse() == biMap
- 7.多個
key
:Table
我們知道數(shù)據(jù)庫除了主鍵外霎俩,還提供了復(fù)合索引,而且實際中這樣的多級關(guān)系查找也是比較多的沉眶,當(dāng)然我們可以利用嵌套的Map來實現(xiàn):
Map<k1,Map<k2,v2>>
打却。為了讓我們的代碼看起來不那么丑陋,guava為我們提供了Table
Table
涉及到3個概念:rowKey
,columnKey
,value
谎倔,并提供了多種視圖以及操作方法讓你更加輕松的處理多個KEY
的場景
public static void main(String[] args) {
Table<String, String, Integer> table = HashBasedTable.create();
table.put("wudy","語文", 100);
table.put("wudy","數(shù)學(xué)", 80);
table.put("wudy","英語", 90);
table.put("wudy","計算機", 89);
table.put("peter","地理", 13);
table.put("peter","計算機", 73);
//最小單位cell
Set<Table.Cell<String, String, Integer>> set = table.cellSet();
for (Table.Cell cell:set){
System.out.println(cell.getRowKey() + "," + cell.getColumnKey() + "," + cell.getValue());
}
//row set
Set<String> rowSet = table.rowKeySet();
System.out.println(rowSet); // [wudy, peter]
//column set
Set<String> columnSet = table.columnKeySet();
System.out.println(columnSet); // [數(shù)學(xué), 語文, 英語, 計算機, 地理]
//根據(jù)rowKey獲取信息Map<column, value>
System.out.println(table.row("wudy")); // {數(shù)學(xué)=80, 語文=100, 英語=90, 計算機=89}
//根據(jù)column獲得信息Map<row, value>
System.out.println(table.column("計算機")); // {wudy=89, peter=73}
}
- 8.函數(shù)式編程:
Functions
public static void main(String[] args) {
ArrayList<String> list = Lists.newArrayList("wudy.yu", "peter.li", "jack");
Function<String, String> f1 = new Function<String, String>(){
@Override
public String apply(@Nullable String s) {
return s.length() <= 5 ? s : s.substring(0,5);
}
};
Function<String, String> f2 = new Function<String, String>() {
@Nullable
@Override
public String apply(@Nullable String s) {
return s.toUpperCase();
}
};
Function<String, String> f3 = Functions.compose(f1, f2);
Collection<String> collection = Collections2.transform(list, f3);
for (String s:collection){
System.out.println(s);
}
}
輸出:
WUDY.
PETER
JACK
上面的代碼是為了完成將List集合中的元素柳击,先截取5個長度,然后轉(zhuǎn)成大寫片习。
函數(shù)式編程的好處在于在集合遍歷操作中提供自定義Function的操作捌肴,比如transform轉(zhuǎn)換。我們再也不需要一遍遍的遍歷集合藕咏,顯著的簡化了代碼状知!
- 9.斷言Predicate
Predicate
最常用的功能就是運用在集合的過濾當(dāng)中!
image.png
public static void main(String[] args) {
// 需要注意的是Lists并沒有提供filter方法孽查,不過你可以使用Collections2.filter完成饥悴!
List<String> list = Lists.newArrayList("wudy.yu", "peter.li", "moom");
Collection<String> collection = Collections2.filter(list, new Predicate<String>() {
@Override
public boolean apply(@Nullable String s) {
return new StringBuilder(s).reverse().toString().equals(s);
}
});
for (String s:collection) {
System.out.println(s); // moom
}
}
- 10.
check null and other:Optional、Preconditions
在
guava
中,對于null
的處理手段是快速失敗西设,你可以看看guava
的源碼瓣铣,很多方法的第一行就是:Preconditions.checkNotNull(elements);
要知道null
是模糊的概念,是成功呢贷揽,還是失敗呢棠笑,還是別的什么含義呢?
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
test("null", 101, null);
}
public static void test(String name, Integer age, Map<String, String> extraInfo) {
Preconditions.checkNotNull(name, "name must be given");
Preconditions.checkArgument(age >= 18, "未成年人不能觀看");
Map<String, String> defaultExtraInfo = Maps.newHashMap();
defaultExtraInfo.put("name", "wudy");
extraInfo = Optional.fromNullable(extraInfo).or(defaultExtraInfo); // java API方式: Optional.ofNullable(extraInfo).orElse(defaultExtraInfo);
for (Map.Entry<String, String> entry : extraInfo.entrySet()){
System.out.println(entry.getKey() + ":" + entry.getValue()); // name:wudy
}
}
11.
Guava RateLimiter
參考文章:https://mp.weixin.qq.com/s?__biz=MzI3ODcxMzQzMw==&mid=2247546330&idx=2&sn=864bf29bb10748f34be380cfcdd63f83&chksm=eb50b0ecdc2739fa9fd4d2241d74b3f516273944d64ef22d46e20bce0b877660499b7a827430&mpshare=1&scene=23&srcid=1014KCFaEZRo7IYKNhPsA5P0&sharer_sharetime=1634185620678&sharer_shareid=f770d25bc57f1c2f9159f85750f854dc#rd
-
Guava騷操作
參考文章:https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&mid=2247572229&idx=1&sn=e82470244be0bfa059a7efd34a9f3772&chksm=fa4ba4b4cd3c2da2819c28ddaa37493e8aa3ebf5733e3cdb03269f4e017ead8210b222c5b546&mpshare=1&scene=23&srcid=0509HUFL13l1c6FKdSFePdnv&sharer_sharetime=1683621223963&sharer_shareid=7fec9c1809ccb850bfdebba7d4f7a81e#rd
-