一、介紹
1、常用點:集合 [collections] 、緩存 [caching] 、原生類型支持 [primitives support] 、並發庫 [concurrency libraries] 、通用注解 [common annotations] 、字符串處理 [string processing] 、I/O 等等
2、開源的Java庫,這個庫是為了方便編碼,並減少編碼錯誤。
二、Optional類
1、定義
官方解釋:用於包含非空對象的不可變對象,Optional對象不存在值表示null。
個人解釋:換言之就是把變量轉成Optional對象,其中null都轉成Optional.absent()(就是一個空的Optional對象),然后就可以對Optional對象進行操作。好處就是發現null可選擇拋出異常。
2、java8自帶Optional
所以建議直接用java8自帶的就好了,用法一樣,只是方法名字稍微不一樣
3、使用
關鍵方法(解釋看代碼):fromNullable、of、get、or、isPresent
@Test
public void OptionalTest() {
handleParam(null,1); //后面兩個參數自己隨意寫
}
//處理參數舉例子
void handleParam(String a,Integer b){
//對於處理string參數
Optional<String> aOpt = Optional.fromNullable(a); //允許參數空。如果非空返回一個包含引用Optional實例,否則返回Optional.absent()。
System.out.println(aOpt.isPresent());//輸出aOpt是否為空
a=aOpt.or("defaultValue");//如果為空,就給一個默認值defaultValue
System.out.println(a);
//同理對於處理int參數
Optional<Integer> bOpt = Optional.of(b);//不允許參數空,不然會拋出異常
b=bOpt.get();//get的時候不允許變量為空
System.out.println(b);
}
三、Preconditions類
1、定義
官方解釋:檢查方法的參數是否符合業務
個人感覺:我不喜歡這個,我覺得沒什么用,用到的幾率太小,要一直捕獲exception
2、使用
關鍵方法(解釋看代碼):checkArgument、checkState;checkPositionIndex、checkElementIndex;checkNotNull
@Test
public void PreconditionsTest() {
try {
System.out.println(sqrt(-3.0)); //計算開方
}catch(Exception e){
System.out.println(e.getMessage());
}
try {
System.out.println(sum(null,3)); //計算和
}catch(NullPointerException e){
System.out.println(e.getMessage());
}
try {
System.out.println(getValue(-1,6));//判斷下標是否有效
}catch(IndexOutOfBoundsException e){
System.out.println(e.getMessage());
}
}
public double sqrt(double input) {
Preconditions.checkArgument(input > 0.0, "非法參數: 參數為%s", input);//和checkState差不了多少
return Math.sqrt(input);
}
public int sum(Integer a, Integer b){
Preconditions.checkNotNull(a, "非法參數: 參數為空");
Preconditions.checkNotNull(b, "非法參數: 參數為空");
return a+b;
}
public int getValue(int index, int size){
Preconditions.checkPositionIndex(index, size, "無效的下標");//和checkElementIndex差不了多少
return index;
}
四、Ordering類
1、定義
官方解釋:Ordering(排序)可以被看作是一個豐富的比較具有增強功能的鏈接,多個實用方法,多類型排序功能等
個人解釋:反正就是列表的排序,倒序,取最大最小,取從最大到最小的k個最大的元素,取從小到最大的k個最小的元素,亮點是可以兼容null
2、使用
關鍵方法(解釋看代碼):greatestOf、leastOf;min、max;sortedCopy、isOrdered、reverse;nullsFirst、nullsLast
@Test
public void OrderingTest() {
List<Integer> myList = new ArrayList<Integer>();
myList.add(new Integer(5));
myList.add(new Integer(2));
myList.add(new Integer(15));
myList.add(new Integer(51));
myList.add(new Integer(53));
myList.add(new Integer(35));
myList.add(new Integer(45));
myList.add(new Integer(32));
myList.add(new Integer(43));
myList.add(new Integer(16));
Ordering ordering = Ordering.natural();
//從最大到最小的k個最大的元素
List list1 = ordering.greatestOf(myList, 3);
System.out.println("從最大到最小的k個最大的元素list1:"+list1);//輸出[53, 51, 45]
//從小到最大的k個最小的元素
List list2 = ordering.leastOf(myList, 3);
System.out.println("從小到最大的k個最小的元素list2:"+list2);//輸出[2, 5, 15]
//最小元素
int min = (int) ordering.min(myList);
System.out.println("最小元素:"+min);//輸出2
//最大元素
int max = (int) ordering.max(myList);
System.out.println("最大元素:"+max);//輸出53
//排序后復制,原list不變,從小到大排序
List list3 = ordering.sortedCopy(myList);
System.out.println("從小到大排序后復制給list3:"+list3);//輸出[2, 5, 15, 16, 32, 35, 43, 45, 51, 53]
System.out.println("原mylist:"+myList);//輸出[5, 2, 15, 51, 53, 35, 45, 32, 43, 16]
//排序也可以直接用Collections.sort,從小到大排序,正常情況下此方法禁止list含null
Collections.sort(myList);
System.out.println("從小到大排序好原mylist:"+myList);//輸出[2, 5, 15, 16, 32, 35, 43, 45, 51, 53]
//查看是否已經從小到大好了序,該方法禁止list含null,如果是從大到小則返回false
boolean isOrdered = ordering.isOrdered(myList);
System.out.println("查看是否已經排好了序:"+isOrdered);//輸出true
//換成從大到小排序或者是翻轉
Collections.sort(myList,ordering.reverse());
System.out.println("從大到小排序好原mylist:"+myList);//輸出53, 51, 45, 43, 35, 32, 16, 15, 5, 2]
//ordering允許list含有null
myList.add(null);
//對待null小於所有其他值
Collections.sort(myList,ordering.nullsFirst());
System.out.println("添加null以后,對待null小於所有其他值,myList為:"+myList);//輸出[null, 2, 5, 15, 16, 32, 35, 43, 45, 51, 53]
//對待null大於所有其他值
Collections.sort(myList,ordering.nullsLast());
System.out.println("添加null以后,對待null大於所有其他值,myList為:"+myList);//輸出[2, 5, 15, 16, 32, 35, 43, 45, 51, 53, null]
}
五、Range類
1、定義
官方解釋:Range 表示一個間隔或一個序列。它被用於獲取一組數字/串在一個特定范圍之內。Range定義了連續跨度的范圍邊界,這個連續跨度是一個可以比較的類型(Comparable type)。比如1到100之間的整型數據。
個人解釋:可以生產區間,就是一段連續的整型數據,可以判斷是否存在或者獲取兩個區間的交集和並集,可以判斷是否存在或者獲取一個區間的最低端點和上限端點,可以查詢一個區間是包含一個或者多個元素。
2、生產區間的方法
概念 | 表示范圍 | guava對應功能方法 |
---|---|---|
(a..b) | {x | a < x < b} |
open(a, b) |
[a..b] | {x | a <= x <= b} |
closed(a, b) |
[a..b) | {x | a <= x < b} |
closedOpen(a, b) |
(a..b] | {x | a < x <= b} |
openClosed(a, b) |
(a..+∞) | {x | x > a} |
greaterThan(a) |
[a..+∞) | {x | x >= a} |
atLeast(a) |
(-∞..b) | {x | x < b} | |
lessThan(b) |
(-∞..b] | {x | x <= b} |
atMost(b) |
(-∞..+∞) | all values |
all() |
3、使用
關鍵方法(解釋看代碼):lowerEndpoint,upperEndpoint,hasUpperBound,hasLowerBound;encloses,isConnected,intersection
@Test
public void RangeTest(){
System.out.println("-------------------基本獲取---------------------");
//創建一個范圍 [a,b]
Range<Integer> range1 = Range.closed(0, 9);
System.out.println("生成range1 [0,9]: "+ range1.toString()); //輸出[0‥9]
//查看Range是否存在某個或某些值
System.out.println("range1是否存在5: " + range1.contains(5));//輸出true
System.out.println("range1是否存在(1,2,3): " + range1.containsAll(Ints.asList(1, 2, 3)));//輸出true
//查看Range的最低端點和上限端點。
System.out.println("range1的最低端點: " + range1.lowerEndpoint());//輸出0
System.out.println("range1是否有上端點: " + range1.hasUpperBound());//輸出true
System.out.println("range1的上限端點: " + range1.upperEndpoint());//輸出9
System.out.println("------------------閉區間和開區間----------------------");
//創建一個范圍 (a,b)
Range<Integer> range2 = Range.open(0, 9);
System.out.println("生成range2 (0,9) :"+range2.toString());
//創建一個范圍 (a,b]
Range<Integer> range3 = Range.openClosed(0, 9);
System.out.println("生成range3 (0,9] : "+range3.toString());
//創建一個范圍 [a,b)
Range<Integer> range4 = Range.closedOpen(0, 9);
System.out.println("生成range4 [0,9) : "+range4.toString());
//返回一個包含所有值嚴格大於端點的范圍內 (a,∞)
Range<Integer> range5 = Range.greaterThan(9);
System.out.println("生成range5 (9,∞) : "+range5.toString());
System.out.println("range5是否有上端點: " + range5.hasUpperBound());
System.out.println("------------------交集和並集----------------------");
Range<Integer> range6 = Range.closed(3, 5);
//是否包含子集
System.out.println("range1 [0,9] 是否包含 range6 [3,5]:" + range1.encloses(range6));
Range<Integer> range7 = Range.closed(9, 20);
//是否有交集
System.out.println("range1 [0,9] 和 range7 [9,20]是否有交集:" + range1.isConnected(range7));
Range<Integer> range8 = Range.closed(5, 15);
//返回由兩者范圍和connectedRange封閉,如果這樣的范圍存在的最大范圍。如果不相連時,直接拋出異常
System.out.println("range1 [0,9]和 range8 [5,15]的交集:"+range1.intersection(range8).toString());
//返回最小的范圍包圍兩者這個范圍和other等。
System.out.println("range1 [0,9]和 range8 [5,15]的並集:"+range1.span(range8).toString());
System.out.println("-------------------拓展---------------------");
//輸出有限range
ContiguousSet<Integer> set = ContiguousSet.create(range8, DiscreteDomain.integers());
for(int grade : set) {
System.out.print(grade +" ");
}
}
六、Multiset接口
1、定義
Multiset接口擴展設置有重復的元素,並提供了各種實用的方法來處理這樣的元素在集合中出現。
2、使用
關鍵方法(解釋看代碼):elementSet、iterator;count、contains、containsAll、size;add、remove
@Test
public void MultisetTest(){
//創建一個multiset
Multiset<String> multiset = HashMultiset.create();
multiset.add("a");multiset.add("b");multiset.add("c");
multiset.add("d");multiset.add("a");multiset.add("b");
multiset.add("c");multiset.add("b");multiset.add("b");
System.out.print("把multiset轉成無重復set:");
Set<String> set = multiset.elementSet();
set.forEach(e-> System.out.print(e+" "));//輸出a b c d
System.out.print("\n把multiset轉成可重復且有序的Iterator:");
Iterator<String> iterator = multiset.iterator();
iterator.forEachRemaining(e-> System.out.print(e+" "));//輸出a a b b b b c c d
System.out.println("\n含有幾個'b' : "+multiset.count("b"));//輸出4
System.out.println("是否包含e' : "+multiset.contains("e"));//輸出false
System.out.println("總size : "+multiset.size());//輸出9
//移除i個某元素
System.out.println("移除1一個元素a");
multiset.remove("a",1);
//增加i個某元素
System.out.println("增加2個元素c");
multiset.add("c",2);
//顯示集合的不同元素及其出現次數
System.out.print("遍歷打印出multiset的元素和個數:");
multiset.entrySet().forEach(entry->System.out.print("元素"+entry.getElement() +"的個數為 " + entry.getCount()+";"));//元素a的個數為 1;元素b的個數為 4;元素c的個數為 4;元素d的個數為 1;
}
七、Bimap接口
1、定義
BiMap確保沒有重復的值,且可以從value獲取key
2、使用
關鍵方法(解釋看代碼):put、forcePut;inverse
@Test
public void BimapTest(){
BiMap<Integer, String> empIDNameMap = HashBiMap.create();
empIDNameMap.put(101, "Mahesh");
empIDNameMap.put(102, "Sohan");
empIDNameMap.put(103, "Ramesh");
//亮點:如果key已經存在,強制覆蓋
empIDNameMap.forcePut(101, "Mahesh1");
//亮點:根據值找到key 。inverse():生成value到key的逆視圖
System.out.println(empIDNameMap.inverse().get("Mahesh"));//輸出null
System.out.println(empIDNameMap.inverse().get("Mahesh1"));//輸出101
//把所有value轉成set集合
Set<String> values = empIDNameMap.values();
values.forEach(e-> System.out.print(e+" "));//輸出Ramesh Mahesh1 Sohan
}
八、Bimap接口
1、定義
Table代表一個特殊的映射,其中兩個鍵可以在組合的方式被指定為單個值。它類似於創建映射的映射。
簡單點說就是有rowKey,有columnKey,匹配對應value
2、使用
關鍵方法(解釋看代碼):put、row、rowKeySet、column
@Test
public void TableTest(){
//創建一個表
Table<String, String, String> employeeTable = HashBasedTable.create();
employeeTable.put("IBM", "101","Mahesh");
employeeTable.put("IBM", "102","Ramesh");
employeeTable.put("IBM", "103","Suresh");
employeeTable.put("Microsoft", "101","Sohan");
employeeTable.put("Microsoft", "102","Mohan");
employeeTable.put("Microsoft", "103","Rohan");
employeeTable.put("TCS", "121","Ram");
employeeTable.put("TCS", "122","Shyam");
employeeTable.put("TCS", "123","Sunil");
//獲取某一行的所有列
Map<String,String> ibmEmployees = employeeTable.row("IBM");
System.out.println("rowKey為IBM的這一行的所有列為");
ibmEmployees.entrySet().forEach(entry ->System.out.println("列字段columnKey: " + entry.getKey() + ", 值value: " + entry.getValue()));//輸出列字段columnKey: 103, 值value: Suresh \n 列字段columnKey: 101, 值value: Mahesh \n 列字段columnKey: 102, 值value: Ramesh
//獲取所有行的rowkey,自動按照字母順序
Set<String> employers = employeeTable.rowKeySet();
System.out.print("所有的rowKey為: ");
employers.forEach(employer-> System.out.print(employer + "、"));//輸出IBM、TCS、Microsoft
//獲取某一列的所有行和值
System.out.println("\ncolumnKey為102的所有行和值為");
Map<String,String> EmployerMap = employeeTable.column("102");
EmployerMap.entrySet().forEach( entry->System.out.println("行字段rowKey: " + entry.getKey() + ", 值value: " + entry.getValue()));//輸出行字段rowKey: IBM, 值value: Ramesh \n 行字段rowKey: Microsoft, 值value: Mohan
}
九、LoadingCache
1、定義
在緩存中自動加載值,它提供了許多實用的方法,在有緩存需求時非常有用。
優點:
- 線程安全的緩存,與ConcurrentMap相似,但前者增加了更多的元素失效策略,后者只能顯示的移除元素。
- 提供了三種基本的緩存回收方式:基於容量回收、定時回收和基於引用回收。定時回收有兩種:按照寫入時間,最早寫入的最先回收;按照訪問時間,最早訪問的最早回收。
- 監控緩存加載/命中情況
- 集成了多部操作,調用get方式,可以在未命中緩存的時候,從其他地方獲取數據源(DB,redis),並加載到緩存中。
缺點:
- Guava Cache的超時機制不是精確的。
- 不能持久化本地緩存
2、使用
關鍵方法(駕駛看代碼):getIfPresent、get、put、putAll、invalidate、
invalidateAll、refresh、size、stats、asMap、
public class GuavaTester {
public static void main(String args[]) {
//定義一個LoadingCache
LoadingCache employeeCache = CacheBuilder.newBuilder()
.concurrencyLevel(8)//設置並發級別為8,並發級別是指可以同時寫緩存的線程數
.maximumSize(100) // 設置緩存最大容量為100,超過100之后就會按照LRU最近雖少使用算法來移除緩存項
.expireAfterWrite(10, TimeUnit.MINUTES)//設置寫緩存后10分鍾后過期
.expireAfterAccess(30, TimeUnit.MINUTES) // 設置緩存在訪問30分鍾后過期
.initialCapacity(10) //設置緩存容器的初始容量為10
.recordStats() //設置要統計緩存的命中率,開啟統計信息開關,
.removalListener(notification -> System.out.println("key為"+notification.getKey() + "的緩存被移除了, 因為" + notification.getCause()))//設置緩存的移除通知
.build(new CacheLoader() { //build方法中可以指定CacheLoader,,用於從數據源加載數據,在緩存不存在時可自定義策略,比如從數據庫獲取數據
@Override
public Object load(Object key) throws Exception {
//從數據庫拿數據
return getFromDatabase(key.toString()); //自定義
}
});
try {
//第一次調用時,緩存沒有命中,會從數據庫拿數據,如果數據庫沒有就直接拋異常
System.out.println("第一次調用:");
System.out.println(employeeCache.get("100"));//輸出Employee(name=Mahesh, dept=Finance, emplD=100)
System.out.println(employeeCache.get("103"));//輸出Employee(name=Rohan, dept=IT, emplD=103)
System.out.println(employeeCache.get("110"));//輸出EmployeeEmployee(name=Sohan, dept=Admin, emplD=110)
//第二次調用時,直接從緩存中拿
System.out.println("第二次調用:");
System.out.println(employeeCache.get("100"));//輸出Employee(name=Mahesh, dept=Finance, emplD=100)
System.out.println(employeeCache.get("103"));//輸出Employee(name=Rohan, dept=IT, emplD=103)
System.out.println(employeeCache.get("110"));//輸出EmployeeEmployee(name=Sohan, dept=Admin, emplD=110)
System.out.println("---------------------分割線-----------------------");
//常用方法
System.out.println("用getIfPresent獲取key為104的值:"+employeeCache.getIfPresent("104"));//獲取緩存中key對應的value,如果緩存沒命中,返回null
//如果緩存有值,覆蓋,否則,新增
employeeCache.put("104",new Employee("Aria","Boss","104"));
//刪除緩存
employeeCache.invalidate("100");
//獲取緩存中元素的大概個數
System.out.println("獲取緩存中元素的大概個數為:"+employeeCache.size());
//緩存的狀態數據,包括(未)命中個數,加載成功/失敗個數,總共加載時間,刪除個數等。
System.out.println("緩存的狀態數據為:"+employeeCache.stats());//輸出CacheStats{hitCount=3, missCount=4, loadSuccessCount=3, loadExceptionCount=0, totalLoadTime=966956, evictionCount=0}
//asMap()方法獲得緩存數據的ConcurrentMap快照
System.out.println("把LoadingCache轉換成concurrentMap:"+ employeeCache.asMap());//輸出{103=Employee(name=Rohan, dept=IT, emplD=103), 110=Employee(name=Sohan, dept=Admin, emplD=110)}
//刷新緩存,即重新取緩存數據,更新緩存
employeeCache.refresh("110");
//清除緩存
employeeCache.invalidateAll();
//清空所有數據
employeeCache.cleanUp();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
//模擬從數據庫拿數據
private static Object getFromDatabase(String empId) {
//局部變量,取一次,清除一次
Employee e1 = new Employee("Mahesh", "Finance", "100");
Employee e2 = new Employee("Rohan", "IT", "103");
Employee e3 = new Employee("Sohan", "Admin", "110");
Map database = new HashMap();
database.put("100", e1);
database.put("103", e2);
database.put("110", e3);
System.out.println("從數據庫找empId為" + empId);
return database.get(empId);
}
}
@Data
@AllArgsConstructor
class Employee {
private String name;
private String dept;
private String emplD;
}
十、Multimap
1、定義
可以含有多個一樣的key
2、使用
關鍵方法:containsEntry、containsKey、containsValue;get、asMap、keySet、values;add、remove
public static void main(String args[]){
//初始化一個Multimap
Multimap<String,String> multimap = ArrayListMultimap.create();
multimap.put("lower", "a");
multimap.put("lower", "b");
multimap.put("lower", "c");
multimap.put("lower", "d");
multimap.put("lower", "e");
multimap.put("upper", "A");
multimap.put("upper", "B");
multimap.put("upper", "C");
multimap.put("upper", "D");
System.out.println("是否包含鍵值對lower-a:"+multimap.containsEntry("lower", "a"));//輸出 true
System.out.println("是否包含鍵lower:"+multimap.containsKey("lower"));//輸出 true
System.out.println("是否包含值a:"+multimap.containsValue("a"));//輸出 true
System.out.println("multimap包含鍵值對數量:"+multimap.size());//輸出9
System.out.println("---------------分割線---------------");
List<String> lowerList = (List<String>)multimap.get("lower");
System.out.println("所有key為lower的值有:"+lowerList.toString());//輸出[a, b, c, d, e]
List<String> upperList = (List<String>)multimap.get("upper");
System.out.println("所有key為lower的值有:"+upperList.toString());//輸出[A, B, C, D]
lowerList.add("f");
upperList.remove("D");
System.out.println("---------------分割線---------------");
Map<String, Collection<String>> map = multimap.asMap();
System.out.println("遍歷整個multimap:");
map.entrySet().forEach(entry->{
String key = entry.getKey();
Collection<String> value = multimap.get(key);
System.out.println(key + ":" + value); //輸出lower:[a, b, c, d, e, f] \n upper:[A, B, C]
});
System.out.println("---------------分割線---------------");
System.out.println("所有唯一key:");
Set<String> keys = multimap.keySet();
keys.forEach(key-> System.out.print(key+" "));//輸出lower upper
System.out.println("\n所有的值:");
Collection<String> values = multimap.values();
System.out.println(values);//輸出[a, b, c, d, e, f, A, B, C]
}